diff --git a/.gitignore b/.gitignore index ad6b6502a..7d5f217e9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,3 @@ __pycache__ /TAGS /bx_enh_dbg.ini /tool/emacs/*.elc -/usr/share/dict/words diff --git a/Makefile b/Makefile index 44d406136..7e6952bab 100644 --- a/Makefile +++ b/Makefile @@ -59,9 +59,9 @@ # # build/config.mk -SHELL = /bin/sh +SHELL = build/bootstrap/cocmd.com HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win7 win10 xnu -SANITY := $(shell build/sanitycheck $$PPID) +#SANITY := $(shell build/sanitycheck $$PPID) .SUFFIXES: .DELETE_ON_ERROR: @@ -229,7 +229,7 @@ depend: o/$(MODE)/depend tags: TAGS HTAGS o/$(MODE)/.x: - @mkdir -p $(@D) && touch $@ + @$(COMPILE) -AMKDIR -tT$@ $(MKDIR) $(@D) o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x)))) $(file >$@,$(SRCS)) @@ -246,11 +246,11 @@ o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS $(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x))) TAGS: o/$(MODE)/srcs-old.txt $(SRCS) - @rm -f $@ + @$(RM) $@ @$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@ HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS) - @rm -f $@ + @$(RM) $@ @$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@ loc: o/$(MODE)/tool/build/summy.com @@ -258,6 +258,7 @@ loc: o/$(MODE)/tool/build/summy.com $(XARGS) wc -l | grep total | awk '{print $$1}' | $< COSMOPOLITAN_OBJECTS = \ + NET_HTTP \ LIBC_DNS \ LIBC_SOCK \ LIBC_NT_WS2_32 \ @@ -331,6 +332,7 @@ COSMOPOLITAN_HEADERS = \ LIBC_UNICODE \ LIBC_X \ LIBC_ZIPOS \ + NET_HTTP \ THIRD_PARTY_DLMALLOC \ THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ @@ -352,9 +354,10 @@ o/cosmopolitan.h: \ o/cosmopolitan.html: \ o/$(MODE)/third_party/chibicc/chibicc.com.dbg \ $(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) + $(file >$@.args,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS)))) o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \ -fno-common -include libc/integral/normalize.inc -o $@ \ - $(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) + @$@.args $(SRCS): \ libc/integral/normalize.inc \ @@ -388,9 +391,9 @@ $(SRCS): $(HDRS): $(INCS): .DEFAULT: - @echo >&2 - @echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2 - @echo >&2 - rm -f o/$(MODE)/depend + @$(ECHO) >&2 + @$(ECHO) NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2 + @$(ECHO) >&2 + $(RM) o/$(MODE)/depend -include o/$(MODE)/depend diff --git a/README.md b/README.md index 2e8477863..a00dfb8a2 100644 --- a/README.md +++ b/README.md @@ -28,21 +28,61 @@ printf 'main() { printf("hello world\\n"); }\n' >hello.c gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \ -fno-omit-frame-pointer -pg -mnop-mcount \ -o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds \ - -include cosmopolitan.h crt.o ape.o cosmopolitan.a + -include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a objcopy -S -O binary hello.com.dbg hello.com ``` -You now have a portable program. Please note that your APE binary will -assimilate itself as a conventional resident of your platform after the -first run, so it can be fast and efficient for subsequent executions. +You now have a portable program. ```sh ./hello.com -bash -c './hello.com' # zsh/fish workaround (we upstreamed patches) +bash -c './hello.com' # zsh/fish workaround (we patched them in 2021) ``` -So if you intend to copy the binary to Windows or Mac then please do -that before you run it, not after. +Since we used the `ape-no-modify-self.o` bootloader (rather than +`ape.o`) your executable will not modify itself when it's run. What +it'll instead do, is extract a 4kb program to `${TMPDIR:-/tmp}` that +maps your program into memory without needing to copy it. It's possible +to install the APE loader systemwide as follows. + +```sh +# (1) linux systems that want binfmt_misc +ape/apeinstall.sh + +# (2) for linux/freebsd/netbsd/openbsd systems +cp build/bootstrap/ape.elf /usr/bin/ape + +# (3) for mac os x systems +cp build/bootstrap/ape.macho /usr/bin/ape +``` + +If you followed steps (2) and (3) then there's going to be a slight +constant-time startup latency each time you run an APE binary. Your +system might also prevent your APE program from being installed to a +system directory as a setuid binary or a script interpreter. To solve +that, you can use the following flag to turn your binary into the +platform local format (ELF or Mach-O): + +```sh +$ file hello.com +hello.com: DOS/MBR boot sector +./hello.com --assimilate +$ file hello.com +hello.com: ELF 64-bit LSB executable +``` + +There's also some other useful flags that get baked into your binary by +default: + +```sh +./hello.com --strace # log system calls to stderr +./hello.com --ftrace # log function calls to stderr +``` + +If you want your `hello.com` program to be much tinier, more on the +order of 16kb rather than 60kb, then all you have to do is use + instead. See +. ### MacOS @@ -64,22 +104,85 @@ Windows](https://justine.lol/cosmopolitan/windows-compiling.html) tutorial. It's needed because the ELF object format is what makes universal binaries possible. +Cosmopolitan officially only builds on Linux. However, one highly +experimental (and currently broken) thing you could try, is building the +entire cosmo repository from source using the cross9 toolchain. + +``` +mkdir -p o/third_party +rm -rf o/third_party/gcc +wget https://justine.lol/linux-compiler-on-windows/cross9.zip +unzip cross9.zip +mv cross9 o/third_party/gcc +build/bootstrap/make.com +``` + ## Source Builds -Cosmopolitan can be compiled from source on any Linux distro. GNU make -needs to be installed beforehand. This is a freestanding hermetic -repository that bootstraps using a vendored static gcc9 executable. -No further dependencies are required. +Cosmopolitan can be compiled from source on any Linux distro. First, you +need to download or clone the repository. ```sh wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz tar xf cosmopolitan.tar.gz # see releases page cd cosmopolitan -make -j16 +``` + +This will build the entire repository and run all the tests: + +```sh +build/bootstrap/make.com -j16 o//examples/hello.com find o -name \*.com | xargs ls -rShal | less ``` +If you get an error running make.com then it's probably because you have +WINE installed to `binfmt_misc`. You can fix that by installing the the +APE loader as an interpreter. It'll improve build performance too! + +```sh +ape/apeinstall.sh +``` + +Since the Cosmopolitan repository is very large, you might only want to +build a particular thing. Cosmopolitan's build config does a good job at +having minimal deterministic builds. For example, if you wanted to build +only hello.com then you could do that as follows: + +```sh +build/bootstrap/make.com -j16 o//examples/hello.com +``` + +Sometimes it's desirable to build a subset of targets, without having to +list out each individual one. You can do that by asking make to build a +directory name. For example, if you wanted to build only the targets and +subtargets of the chibicc package including its tests, you would say: + +```sh +build/bootstrap/make.com -j16 o//third_party/chibicc +o//third_party/chibicc/chibicc.com --help +``` + +Cosmopolitan provides a variety of build modes. For example, if you want +really tiny binaries (as small as 12kb in size) then you'd say: + +```sh +build/bootstrap/make.com -j16 MODE=tiny +``` + +Here's some other build modes you can try: + +```sh +build/bootstrap/make.com -j16 MODE=dbg # asan + ubsan + debug +build/bootstrap/make.com -j16 MODE=asan # production memory safety +build/bootstrap/make.com -j16 MODE=opt # -march=native optimizations +build/bootstrap/make.com -j16 MODE=rel # traditional release binaries +build/bootstrap/make.com -j16 MODE=optlinux # optimal linux-only performance +build/bootstrap/make.com -j16 MODE=tinylinux # tiniest linux-only 4kb binaries +``` + +For further details, see [//build/config.mk](build/config.mk). + ## GDB Here's the recommended `~/.gdbinit` config: @@ -123,4 +226,3 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000' | FreeBSD | 12 | 2018 | | OpenBSD | 6.4 | 2018 | | NetBSD | 9.1 | 2020 | -| GNU Make | 4.0 | 2015 | diff --git a/ape/ape.S b/ape/ape.S index 48e25aaae..ab1d19cd8 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -542,27 +542,39 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang // present two choices. .ascii "o=\"$(command -v \"$0\")\"\n" // Try to use a system-wide APE loader. - .ascii "type ape-loader >/dev/null 2>&1 && " - .ascii "exec ape-loader \"$o\" \"$@\"\n" + .ascii "[ x\"$1\" != x--assimilate ] && " + .ascii "type ape >/dev/null 2>&1 && " + .ascii "exec ape \"$o\" \"$@\"\n" #ifdef APE_LOADER // There is no system-wide APE loader, but there is one // embedded inside the APE. So if the system is not MacOs, // extract the loader into a temp folder, and use it to // load the APE without modifying it. - .ascii "if [ ! -d /Applications ]; then\n" - .ascii "t=\"${TMPDIR:-/tmp}/ape-loader\"\n" + .ascii "[ x\"$1\" != x--assimilate ] && {\n" + .ascii "t=\"${TMPDIR:-/tmp}/ape\"\n" .ascii "[ -x \"$t\" ] || {\n" + .ascii "mkdir -p \"${t%/*}\" &&\n" .ascii "dd if=\"$o\" of=\"$t.$$\" skip=\"" .shstub ape_loader_dd_skip,2 .ascii "\" count=\"" .shstub ape_loader_dd_count,2 - .ascii "\" bs=64 2>/dev/null &&\n" - .ascii "chmod 755 \"$t.$$\" &&\n" - .ascii "mv \"$t.$$\" \"$t\"\n" + .ascii "\" bs=64 2>/dev/null\n" +#if SupportsXnu() + .ascii "[ -d /Applications ] && " + .ascii "dd if=\"$t.$$\"" + .ascii " of=\"$t.$$\"" + .ascii " skip=6" + .ascii " count=10" + .ascii " bs=64" + .ascii " conv=notrunc" + .ascii " 2>/dev/null\n" +#endif /* SupportsXnu() */ + .ascii "chmod 755 \"$t.$$\"\n" + .ascii "mv -f \"$t.$$\" \"$t\"\n" .ascii "}\n" .ascii "exec \"$t\" \"$o\" \"$@\"\n" - .ascii "fi\n" -#endif + .ascii "}\n" +#endif /* APE_LOADER */ #ifndef APE_NO_MODIFY_SELF // The default behavior is: to overwrite the header in place. // We prefer this because it's a tiny constant one time cost. @@ -581,15 +593,42 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang // then permission clashes can happen between system users, // since only root is able to set the sticky bit, which can // be addressed simply by overriding the TMPDIR environment - .ascii "o=\"${TMPDIR:-/tmp}/$0\"\n" - .ascii "if [ ! -e \"$o\" ]; then\n" - .ascii "d=\"$o\"\n" - .ascii "o=\"$o.$$\"\n" - .ascii "mkdir -p \"${o%/*}\" 2>/dev/null\n" - .ascii "cp -f \"$0\" \"$o\" || exit 120\n" + .ascii "t=\"${TMPDIR:-/tmp}/$0\"\n" + .ascii "[ x\"$1\" != x--assimilate ] || [ ! -e \"$t\" ] && {\n" + .ascii "[ x\"$1\" != x--assimilate ] && {\n" + .ascii "mkdir -p \"${t%/*}\" 2>/dev/null\n" + .ascii "cp -f \"$o\" \"$t.$$\" &&\n" + .ascii "mv -f \"$t.$$\" \"$t\" || exit 120\n" + .ascii "o=\"$t\"\n" + .ascii "}\n" #endif /* APE_NO_MODIFY_SELF */ + .ascii "exec 7<> \"$o\" || exit 121\n" + .ascii "printf '" + .ascii "\\177ELF" # 0x0: ⌂ELF + .ascii "\\2" # 4: long mode + .ascii "\\1" # 5: little endian + .ascii "\\1" # 6: elf v1.o + .ascii "\\011" # 7: FreeBSD + .ascii "\\0" # 8: os/abi ver. + .ascii "\\0\\0\\0" # 9: padding 3/7 + .ascii "\\0\\0\\0\\0" # padding 4/7 + .ascii "\\2\\0" # 10: εxεcµταblε + .ascii "\\076\\0" # 12: NexGen32e + .ascii "\\1\\0\\0\\0" # 14: elf v1.o + .shstub ape_elf_entry,8 # 18: e_entry + .shstub ape_elf_phoff,8 # 20: e_phoff + .shstub ape_elf_shoff,8 # 28: e_shoff + .ascii "\\0\\0\\0\\0" # 30: e_flags + .ascii "\\100\\0" # 34: e_ehsize + .ascii "\\070\\0" # 36: e_phentsize + .shstub ape_elf_phnum,2 # 38: e_phnum + .ascii "\\0\\0" # 3a: e_shentsize + .shstub ape_elf_shnum,2 # 3c: e_shnum + .shstub ape_elf_shstrndx,2 # 3e: e_shstrndx + .ascii "' >&7\n" + .ascii "exec 7<&-\n" #if SupportsXnu() - .ascii "if [ -d /Applications ]; then\n" + .ascii "[ -d /Applications ] && " .ascii "dd if=\"$o\"" .ascii " of=\"$o\"" .ascii " bs=8" @@ -598,54 +637,21 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang .ascii "\" count=\"" .shstub ape_macho_dd_count,2 .ascii "\" conv=notrunc 2>/dev/null\n" - .ascii "el" #endif /* XNU */ - .ascii "if exec 7<> \"$o\"; then\n" - .ascii "printf '" - .ascii "\\177ELF" # 0x0: ⌂ELF - .ascii "\\2" # 4: long mode - .ascii "\\1" # 5: little endian - .ascii "\\1" # 6: elf v1.o - .ascii "\\011" # 7: FreeBSD - .ascii "\\0" # 8: os/abi ver. - .ascii "\\0\\0\\0" # 9: padding 3/7 - .ascii "\\0\\0\\0\\0" # padding 4/7 - .ascii "\\2\\0" # 10: εxεcµταblε - .ascii "\\076\\0" # 12: NexGen32e - .ascii "\\1\\0\\0\\0" # 14: elf v1.o - .shstub ape_elf_entry,8 # 18: e_entry - .shstub ape_elf_phoff,8 # 20: e_phoff - .shstub ape_elf_shoff,8 # 28: e_shoff - .ascii "\\0\\0\\0\\0" # 30: e_flags - .ascii "\\100\\0" # 34: e_ehsize - .ascii "\\070\\0" # 36: e_phentsize - .shstub ape_elf_phnum,2 # 38: e_phnum - .ascii "\\0\\0" # 3a: e_shentsize - .shstub ape_elf_shnum,2 # 3c: e_shnum - .shstub ape_elf_shstrndx,2 # 3e: e_shstrndx - .ascii "' >&7\n" - .ascii "exec 7<&-\n" - .ascii "else\n" - .ascii "exit 121\n" - .ascii "fi\n" + .ascii "[ x\"$1\" = x--assimilate ] && exit 0\n" #ifndef APE_NO_MODIFY_SELF - .ascii "exec \"$0\" \"$@\"\n" # optimistic execution + .ascii "exec \"$0\" \"$@\"\n" # try to preserve argv[0] #else - .ascii "mv -f \"$o\" \"$d\" 2>/dev/null\n" - .ascii "o=\"$d\"\n" - .ascii "fi\n" + .ascii "}\n" + .ascii "o=\"$t\"\n" .ascii "exec \"$o\" \"$@\"\n" #endif /* APE_NO_MODIFY_SELF */ .ascii "R=$?\n" - .ascii "\n" - .ascii "if [ $R -eq 126 ] && [ \"$(uname -m)\" != x86_64 ]; then\n" - .ascii "if Q=\"$(command -v qemu-x86_64)\"; then\n" + .ascii "if [ \"$(uname -m)\" != x86_64 ]; then\n" + .ascii "Q=\"$(command -v qemu-x86_64)\" &&\n" .ascii "exec \"$Q\" \"$o\" \"$@\"\n" - .ascii "else\n" - .ascii "echo error: need qemu-x86_64 >&2\n" - .ascii "fi\n" #ifndef APE_NO_MODIFY_SELF - .ascii "elif [ $R -eq 127 ]; then\n" # means argv[0] was wrong + .ascii "else\n" # means argv[0] was wrong .ascii " exec \"$o\" \"$@\"\n" # so do a path resolution #endif /* APE_NO_MODIFY_SELF */ .ascii "fi\n" @@ -653,7 +659,14 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang .endobj apesh #ifdef APE_LOADER .section .ape.loader,"a",@progbits + .align 64 +ape_loader: .incbin APE_LOADER + .endobj ape_loader,globl + .align 64 +ape_loader_end: + nop + .endobj ape_loader_end,globl .previous #endif /* APE_LOADER */ #endif /* SupportsWindows() || SupportsMetal() || SupportsXnu() */ @@ -856,7 +869,7 @@ ape_macho: .long (520f-510f)/4 # count 510: .quad 0 # rax .quad IMAGE_BASE_VIRTUAL # rbx - .quad 0 # rcx + .quad XNU # rcx .quad 0 # rdx .quad 0 # rdi .quad 0 # rsi @@ -870,7 +883,7 @@ ape_macho: .quad 0 # r13 .quad 0 # r14 .quad 0 # r15 - .quad _xnu # rip + .quad _start # rip .quad 0 # rflags .quad 0 # cs .quad 0 # fs @@ -1156,47 +1169,6 @@ gdt: .short 2f-1f # table byte length .quad 0b0000000010101111100100110000000000000000000000001111111111111111 #48 2: .endobj gdt,global,hidden -/*─────────────────────────────────────────────────────────────────────────────╗ -│ αcτµαlly pδrταblε εxεcµταblε § multiboot stub │ -╚──────────────────────────────────────────────────────────────────────────────╝ - boot modernized for the nineties */ - -#define GRUB_MAGIC 0x1BADB002 -#define GRUB_EAX 0x2BADB002 -#define GRUB_AOUT (1 << 16) -#define GRUB_CHECKSUM(FLAGS) (-(GRUB_MAGIC + (FLAGS)) & 0xffffffff) - -// Grub Header. - .align 4 -ape_grub: - .long GRUB_MAGIC # Magic - .long GRUB_AOUT # Flags - .long GRUB_CHECKSUM(GRUB_AOUT) # Checksum - .long RVA(ape_grub) # HeaderPhysicalAddress - .long IMAGE_BASE_PHYSICAL # TextPhysicalAddress - .long PHYSICAL(_edata) # LoadEndPhysicalAddress - .long PHYSICAL(_end) # BssEndPhysicalAddress - .long RVA(ape_grub_entry) # EntryPhysicalAddress - .endobj ape_grub,globl - -// Grub Entrypoint. -// Takes CPU out of legacy mode and jumps to normal entrypoint. -// @noreturn - .align 4 -ape_grub_entry: - .code32 -// cmp $GRUB_EAX,%eax -// jne triplf - push $0 - popf - mov $0x40,%dl - mov %cr0,%eax - and $~CR0_PE,%eax - mov %eax,%cr0 - ljmpw $0,$REAL(pc) - .code16 - .endfn ape_grub_entry - /*─────────────────────────────────────────────────────────────────────────────╗ │ αcτµαlly pδrταblε εxεcµταblε § real mode │ ╚──────────────────────────────────────────────────────────────────────────────╝ @@ -1473,6 +1445,47 @@ long: push $GDT_LONG_DATA jmp *%rax .endfn long +/*─────────────────────────────────────────────────────────────────────────────╗ +│ αcτµαlly pδrταblε εxεcµταblε § multiboot stub │ +╚──────────────────────────────────────────────────────────────────────────────╝ + boot modernized for the nineties */ + +#define GRUB_MAGIC 0x1BADB002 +#define GRUB_EAX 0x2BADB002 +#define GRUB_AOUT (1 << 16) +#define GRUB_CHECKSUM(FLAGS) (-(GRUB_MAGIC + (FLAGS)) & 0xffffffff) + +// Grub Header. + .align 4 +ape_grub: + .long GRUB_MAGIC # Magic + .long GRUB_AOUT # Flags + .long GRUB_CHECKSUM(GRUB_AOUT) # Checksum + .long RVA(ape_grub) # HeaderPhysicalAddress + .long IMAGE_BASE_PHYSICAL # TextPhysicalAddress + .long PHYSICAL(_edata) # LoadEndPhysicalAddress + .long PHYSICAL(_end) # BssEndPhysicalAddress + .long RVA(ape_grub_entry) # EntryPhysicalAddress + .endobj ape_grub,globl + +// Grub Entrypoint. +// Takes CPU out of legacy mode and jumps to normal entrypoint. +// @noreturn + .align 4 +ape_grub_entry: + .code32 +// cmp $GRUB_EAX,%eax +// jne triplf + push $0 + popf + mov $0x40,%dl + mov %cr0,%eax + and $~CR0_PE,%eax + mov %eax,%cr0 + ljmpw $0,$REAL(pc) + .code64 + .endfn ape_grub_entry + /* ▄▄▒▀▀▀▀▒▒▄ █████▓▓▄░░░░ ▒▒▄ ▐█▓▓█▓▄█████▓░ ▀▒▄ @@ -1508,12 +1521,9 @@ kernel: movabs $ape_stack_vaddr,%rsp .byte 0x0f,0x1f,0207 # nop rdi binbase .long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512 #endif - .weak __hostos - ezlea __hostos,ax - test %rax,%rax - jz 1f - movb $METAL,(%rax) -1: push $0 + push $METAL # sets __hostos in crt.S + pop %rcx + push $0 mov %rsp,%rbp mov .Lenv0(%rip),%rax mov %rax,(%rbp) # envp[0][0] @@ -1529,7 +1539,6 @@ kernel: movabs $ape_stack_vaddr,%rsp push $1 # argc xor %ebp,%ebp xor %eax,%eax - xor %ecx,%ecx xor %edx,%edx xor %edi,%edi xor %esi,%esi diff --git a/ape/ape.lds b/ape/ape.lds index caac90617..e97b96058 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -243,10 +243,12 @@ SECTIONS { /* Code that needs to be addressable in Real Mode */ *(.text.real) KEEP(*(SORT_BY_NAME(.sort.text.real.*))) + /* Code we want earlier in the binary w/o modifications */ + KEEP(*(.ape.loader)) HIDDEN(_ereal = .); - . += 1; - /*END: realmode addressability guarantee */ +/*BEGIN: morphable code */ + . += 1; /* Normal Code */ *(.start) @@ -283,6 +285,7 @@ SECTIONS { /* Privileged code invulnerable to magic */ KEEP(*(.ape.pad.privileged)); . += . > 0 ? 1 : 0; +/*END: morphable code */ HIDDEN(__privileged_start = .); . += . > 0 ? 1 : 0; *(.privileged) @@ -390,15 +393,6 @@ SECTIONS { } :Ram /*END: file content that's loaded by o/s */ -/*BEGIN: payload (for now, only the APE loader) */ - .payload ALIGN(64) : { - /* Loader */ - HIDDEN(ape_loader = .); - KEEP(*(.ape.loader)) - . = ALIGN(64); - HIDDEN(ape_loader_end = .); - } -/*END: payload */ /*BEGIN: bss memory void */ .zip . : { @@ -510,7 +504,7 @@ HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr)); HIDDEN(ape_stack_pf = DEFINED(ape_stack_pf) ? ape_stack_pf : PF_R | PF_W); HIDDEN(ape_stack_prot = _PF2PROT(ape_stack_pf)); HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz); -HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE); +HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000); HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz); HIDDEN(ape_stack_filesz = 0); HIDDEN(ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : STACKSIZE); @@ -546,8 +540,14 @@ HIDDEN(ape_bss_filesz = 0); HIDDEN(ape_bss_memsz = SIZEOF(.bss)); HIDDEN(ape_bss_align = PAGESIZE); -SHSTUB2(ape_loader_dd_skip, RVA(ape_loader) / 64); -SHSTUB2(ape_loader_dd_count, (ape_loader_end - ape_loader) / 64); +/* we roundup here because xnu wants the file load segments page-aligned */ +/* but we don't want to add the nop padding to the ape program, so we'll */ +/* let ape.S dd read past the end of the file into the wrapping binaries */ +SHSTUB2(ape_loader_dd_skip, DEFINED(ape_loader) ? RVA(ape_loader) / 64 : 0); +SHSTUB2(ape_loader_dd_count, + DEFINED(ape_loader_end) + ? ROUNDUP(ape_loader_end - ape_loader, PAGESIZE) / 64 + : 0); #if SupportsXnu() SHSTUB2(ape_macho_dd_skip, RVA(ape_macho) / 8); @@ -697,6 +697,12 @@ ASSERT(DEFINED(_start) || DEFINED(_start16), ASSERT(!DEFINED(_start16) || REAL(_end) < 65536, "ape won't support non-tiny real mode programs"); +ASSERT(IS2POW(ape_stack_memsz), + "ape_stack_memsz must be a two power"); + +ASSERT(!(ape_stack_vaddr & (ape_stack_memsz - 1)), + "ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000000000 - ape_stack_memsz);"); + /* Let's not be like Knight Capital. */ /* NOCROSSREFS_TO(.test .text) */ diff --git a/ape/ape.mk b/ape/ape.mk index 6302a2804..14b0880b3 100644 --- a/ape/ape.mk +++ b/ape/ape.mk @@ -15,20 +15,40 @@ PKGS += APE -APE = o/$(MODE)/ape/ape.o \ +APE = o/$(MODE)/ape/ape.o \ o/$(MODE)/ape/ape.lds -APE_NO_MODIFY_SELF = \ - o/$(MODE)/ape/ape.lds \ +APE_NO_MODIFY_SELF = \ + o/$(MODE)/ape/ape.lds \ o/$(MODE)/ape/ape-no-modify-self.o -APELINK = \ - $(COMPILE) \ - -ALINK.ape \ - $(LINK) \ - $(LINKARGS) \ +APE_COPY_SELF = \ + o/$(MODE)/ape/ape.lds \ + o/$(MODE)/ape/ape-copy-self.o + +APELINK = \ + $(COMPILE) \ + -ALINK.ape \ + $(LINK) \ + $(LINKARGS) \ $(OUTPUT_OPTION) +APE_LOADER_FLAGS = \ + -DNDEBUG \ + -iquote. \ + -Wall \ + -Wextra \ + -fpie \ + -Os \ + -ffreestanding \ + -mgeneral-regs-only \ + -mno-red-zone \ + -fno-ident \ + -fno-gnu-unique \ + -c \ + $(OUTPUT_OPTION) \ + $< + APE_FILES := $(wildcard ape/*.*) APE_HDRS = $(filter %.h,$(APE_FILES)) APE_INCS = $(filter %.inc,$(APE_FILES)) @@ -38,32 +58,68 @@ APE_SRCS = $(APE_SRCS_C) $(APE_SRCS_S) APE_OBJS = $(APE_SRCS_S:%.S=o/$(MODE)/%.o) APE_CHECKS = $(APE_HDRS:%=o/%.ok) -o/$(MODE)/ape/ape.lds: \ - ape/ape.lds \ - ape/macros.internal.h \ - libc/dce.h \ +o/$(MODE)/ape/ape.lds: \ + ape/ape.lds \ + ape/macros.internal.h \ + libc/dce.h \ libc/zip.h -o/ape/idata.inc: \ - ape/idata.internal.h \ +o/ape/idata.inc: \ + ape/idata.internal.h \ ape/relocations.h -o/$(MODE)/ape/ape-no-modify-self.o: ape/ape.S o/$(MODE)/ape/loader.elf - @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -DAPE_LOADER="\"o/$(MODE)/ape/loader.elf\"" -DAPE_NO_MODIFY_SELF $< +o/$(MODE)/ape/ape-no-modify-self.o: \ + ape/ape.S \ + o/$(MODE)/ape/ape.elf + @$(COMPILE) \ + -AOBJECTIFY.S \ + $(OBJECTIFY.S) \ + $(OUTPUT_OPTION) \ + -DAPE_NO_MODIFY_SELF \ + -DAPE_LOADER='"o/$(MODE)/ape/ape.elf"' $< + +o/$(MODE)/ape/ape-copy-self.o: \ + ape/ape.S + @$(COMPILE) \ + -AOBJECTIFY.S \ + $(OBJECTIFY.S) \ + $(OUTPUT_OPTION) \ + -DAPE_NO_MODIFY_SELF $< o/$(MODE)/ape/loader.o: ape/loader.c - @$(COMPILE) -AOBJECTIFY.c $(CC) $(cpp.flags) -fpie -Os -ffreestanding -mno-red-zone -fno-ident -fno-gnu-unique -c $(OUTPUT_OPTION) $< - + @$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b01111001 -g $(APE_LOADER_FLAGS) o/$(MODE)/ape/loader-gcc.asm: ape/loader.c - @$(COMPILE) -AOBJECTIFY.c $(CC) $(cpp.flags) -Os -ffreestanding -mno-red-zone -fno-ident -fno-gnu-unique -c -S $(OUTPUT_OPTION) $< + @$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b01111001 -S -g0 $(APE_LOADER_FLAGS) +o/$(MODE)/ape/loader-clang.asm: ape/loader.c + @$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=0b01111001 -S -g0 $(APE_LOADER_FLAGS) -o/$(MODE)/ape/loader.elf: \ - o/$(MODE)/ape/loader.o \ - o/$(MODE)/ape/loader1.o \ +o/$(MODE)/ape/loader-xnu.o: ape/loader.c + @$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b00001000 -g $(APE_LOADER_FLAGS) +o/$(MODE)/ape/loader-xnu-gcc.asm: ape/loader.c + @$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b00001000 -S -g0 $(APE_LOADER_FLAGS) +o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c + @$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=0b00001000 -S -g0 $(APE_LOADER_FLAGS) + +o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg +o/$(MODE)/ape/ape.macho: o/$(MODE)/ape/ape.macho.dbg + +o/$(MODE)/ape/ape.elf.dbg: \ + o/$(MODE)/ape/loader.o \ + o/$(MODE)/ape/loader-elf.o \ ape/loader.lds - @$(ELFLINK) -s -z max-page-size=0x10 + @$(ELFLINK) -z max-page-size=0x10 + +o/$(MODE)/ape/ape.macho.dbg: \ + o/$(MODE)/ape/loader-xnu.o \ + o/$(MODE)/ape/loader-macho.o \ + ape/loader-macho.lds + @$(ELFLINK) -z max-page-size=0x10 .PHONY: o/$(MODE)/ape -o/$(MODE)/ape: $(APE) \ - $(APE_CHECKS) \ +o/$(MODE)/ape: $(APE_CHECKS) \ + o/$(MODE)/ape/ape.o \ + o/$(MODE)/ape/ape.lds \ + o/$(MODE)/ape/ape.elf \ + o/$(MODE)/ape/ape.macho \ + o/$(MODE)/ape/ape-copy-self.o \ o/$(MODE)/ape/ape-no-modify-self.o diff --git a/ape/apeinstall.sh b/ape/apeinstall.sh new file mode 100755 index 000000000..6d2b7cd74 --- /dev/null +++ b/ape/apeinstall.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +if ! [ x"$(uname -s)" = xLinux ]; then + echo this script is intended for linux binfmt_misc >&2 + echo freebsd/netbsd/openbsd users can use release binary >&2 + exit 1 +fi + +if [ -f o/depend ]; then + # mkdeps.com build was successfully run so assume we can build + echo >&2 + echo running: make -j8 o//ape/ape.elf >&2 + make -j8 o//ape/ape.elf || exit + echo done >&2 +else + # no evidence we can build, use prebuilt one + mkdir -p o//ape || exit + cp -af build/bootstrap/ape.elf o//ape/ape.elf +fi + +echo >&2 +echo installing o//ape/ape.elf to /usr/bin/ape >&2 +echo sudo mv -f o//ape/ape.elf /usr/bin/ape >&2 +sudo mv -f o//ape/ape.elf /usr/bin/ape || exit +echo done >&2 + +if [ -e /proc/sys/fs/binfmt_misc/APE ]; then + echo >&2 + echo it looks like APE is already registered with binfmt_misc >&2 + echo please check that it is mapped to ape not /bin/sh >&2 + echo cat /proc/sys/fs/binfmt_misc/APE >&2 + cat /proc/sys/fs/binfmt_misc/APE >&2 + # TODO: we need better uninstall recommendations + # the following works fine for justine + # but might remove unrelated software? + # sudo sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/status' + exit +fi + +if ! [ -e /proc/sys/fs/binfmt_misc ]; then + echo >&2 + echo loading binfmt_misc into your kernel >&2 + echo you may need to edit configs to persist across reboot >&2 + echo sudo modprobe binfmt_misc >&2 + sudo modprobe binfmt_misc || exit + echo done >&2 +fi + +if ! [ -e /proc/sys/fs/binfmt_misc/register ]; then + echo >&2 + echo mounting binfmt_misc into your kernel >&2 + echo you may need to edit configs to persist across reboot >&2 + echo sudo mount -t binfmt_misc none /proc/sys/fs/binfmt_misc >&2 + sudo mount -t binfmt_misc none /proc/sys/fs/binfmt_misc || exit + echo done >&2 +fi + +echo >&2 +echo registering APE with binfmt_misc >&2 +echo you may need to edit configs to persist across reboot >&2 +echo 'sudo sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2 +sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit +echo done >&2 diff --git a/ape/loader-elf.S b/ape/loader-elf.S new file mode 100644 index 000000000..cbde38956 --- /dev/null +++ b/ape/loader-elf.S @@ -0,0 +1,238 @@ +/*-*- 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 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/elf/def.h" +#include "libc/sysv/consts/prot.h" +#include "libc/macho.internal.h" +#include "libc/dce.h" +#include "libc/macros.internal.h" + +// APE Loader Executable Structure +// Linux, FreeBSD, NetBSD, OpenBSD + + .align 8 +ehdr: .ascii "\177ELF" + .byte ELFCLASS64 + .byte ELFDATA2LSB + .byte 1 + .byte ELFOSABI_FREEBSD + .quad 0 + .word ET_EXEC # e_type + .word EM_NEXGEN32E # e_machine + .long 1 # e_version + .quad _start # e_entry + .quad phdrs - ehdr # e_phoff + .quad 0 # e_shoff + .long 0 # e_flags + .word 64 # e_ehsize + .word 56 # e_phentsize + .word 4 # e_phnum + .word 0 # e_shentsize + .word 0 # e_shnum + .word 0 # e_shstrndx + .endobj ehdr,globl + + .align 8 +phdrs: .long PT_LOAD # p_type + .long PF_R|PF_X # p_flags + .quad 0 # p_offset + .quad ehdr # p_vaddr + .quad ehdr # p_paddr + .quad filesz # p_filesz + .quad filesz # p_memsz + .quad 64 # p_align + + .long PT_LOAD # p_type + .long PF_R|PF_W # p_flags + .quad 0 # p_offset + .quad bss # p_vaddr + .quad bss # p_paddr + .quad 0 # p_filesz + .quad bsssize # p_memsz + .quad 64 # p_align + + .long PT_GNU_STACK # p_type + .long PF_R|PF_W # p_flags + .quad 0 # p_offset + .quad 0 # p_vaddr + .quad 0 # p_paddr + .quad 0 # p_filesz + .quad 0 # p_memsz + .quad 16 # p_align + + .long PT_NOTE # p_type + .long PF_R # p_flags + .quad note - ehdr # p_offset + .quad note # p_vaddr + .quad note # p_paddr + .quad notesize # p_filesz + .quad notesize # p_memsz + .quad 8 # p_align + .endobj phdrs + +note: .long 2f-1f + .long 4f-3f + .long 1 +1: .asciz "OpenBSD" +2: .align 4 +3: .long 0 +4: .long 2f-1f + .long 4f-3f + .long 1 +1: .asciz "NetBSD" +2: .align 4 +3: .long 901000000 +4: .endobj note + notesize = . - note + + .align 64,0 # for ape.S dd + .org 0x180 # for ape.S dd + +// APE Loader XNU Header +// +// This header is dd'd backwards by the APE shell script when +// running on Mac OS X. +// +// @see ape/ape.S +macho: .long 0xFEEDFACE+1 + .long MAC_CPU_NEXGEN32E + .long MAC_CPU_NEXGEN32E_ALL + .long MAC_EXECUTE + .long 5 # number of load commands + .long 60f-10f # size of all load commands + .long MAC_NOUNDEFS # flags + .long 0 # reserved +10: .long MAC_LC_SEGMENT_64 + .long 20f-10b # unmaps first page dir + .ascin "__PAGEZERO",16 # consistent with linux + .quad 0,0x200000,0,0 # which forbids mem <2m + .long 0,0,0,0 +20: .long MAC_LC_SEGMENT_64 + .long 30f-20b + .ascin "__TEXT",16 + .quad ehdr # vaddr + .quad 4096 # memsz + .quad 0 # file offset + .quad filesz # file size + .long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot + .long PROT_EXEC|PROT_READ # initprot + .long 1 # segment section count + .long 0 # flags +210: .ascin "__text",16 # section name (.text) + .ascin "__TEXT",16 + .quad _start # vaddr + .quad textsz # memsz + .long textoff # offset + .long 6 # align 2**6 = 64 + .long 0 # reloc table offset + .long 0 # relocation count + .long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes + .long 0,0,0 # reserved +30: .long MAC_LC_SEGMENT_64 + .long 40f-30b + .ascin "__DATA",16 + .quad bss # vaddr + .quad bsssize # memsz + .quad 0 # offset + .quad 0 # file size + .long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot + .long PROT_READ|PROT_WRITE # initprot + .long 1 # segment section count + .long 0 # flags +310: .ascin "__bss",16 # section name (.bss) + .ascin "__DATA",16 + .quad bss # vaddr + .quad bsssize # memsz + .long 0 # offset + .long 12 # align 2**12 = 4096 + .long 0 # reloc table offset + .long 0 # relocation count + .long MAC_S_ZEROFILL # section type & attributes + .long 0,0,0 # reserved +40: .long MAC_LC_UUID + .long 50f-40b + .quad 0x3fb29ee4ac6c87aa # uuid1 + .quad 0xdd2c9bb866d9eef8 # uuid2 +50: .long MAC_LC_UNIXTHREAD + .long 60f-50b # cmdsize + .long MAC_THREAD_NEXGEN32E # flavaflav + .long (520f-510f)/4 # count +510: .quad 0 # rax + .quad 0 # rbx + .quad 0 # rcx + .quad XNU # rdx + .quad 0 # rdi + .quad 0 # rsi + .quad 0 # rbp + .quad 0 # rsp + .quad 0 # r8 + .quad 0 # r9 + .quad 0 # r10 + .quad 0 # r11 + .quad 0 # r12 + .quad 0 # r13 + .quad 0 # r14 + .quad 0 # r15 + .quad _start # rip + .quad 0 # rflags + .quad 0 # cs + .quad 0 # fs + .quad 0 # gs +520: +60: + .endobj macho + + .align 64,0 # for ape.S dd + .org 0x400 # for ape.S dd + +// Ape Loader Entrpoint +// +// This is normally called by the operating system. However it may +// be called by the Actually Portable Executables themselves, when +// re-executing a program. Just do this: +// +// memcpy(0x200000, loader) +// lea handoff(%rip),%rcx +// lea argblock(%rip),%rsp +// jmp 0x200400 +// +// @see APE_LOADER_ENTRY +// @see ape/loader.h +_start: mov %rsp,%rsi + jmp ApeLoader + .endfn _start,globl + +// System Call Entrpoint +// +// This function is used by the APE loader to make system calls. +// We also pass a reference to this function to the APE binary's +// _start() function. It's needed because on OpenBSD, msyscall() +// restricts which pages can issue system calls, and it can only +// be called once. Therefore if we want to be load and re-load a +// binary multiple times without calling the system execve(), we +// need to be able to handover the SYSCALL function. We hardcode +// this to a fixed address, but that shouldn't be used, since we +// would ideally want to move it to a random page in the future. +__syscall_loader: + clc + syscall + jc 1f + ret +1: neg %rax + ret + .endfn __syscall_loader,globl diff --git a/ape/loader-macho.S b/ape/loader-macho.S new file mode 100644 index 000000000..b027760a7 --- /dev/null +++ b/ape/loader-macho.S @@ -0,0 +1,127 @@ +/*-*- 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 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macho.internal.h" +#include "libc/sysv/consts/prot.h" +#include "libc/dce.h" +#include "libc/macros.internal.h" + +// APE Loader Executable Structure for XNU + + .align 4096 +macho: .long 0xFEEDFACE+1 + .long MAC_CPU_NEXGEN32E + .long MAC_CPU_NEXGEN32E_ALL + .long MAC_EXECUTE + .long 5 # number of load commands + .long 60f-10f # size of all load commands + .long MAC_NOUNDEFS # flags + .long 0 # reserved +10: .long MAC_LC_SEGMENT_64 + .long 20f-10b # unmaps first page dir + .ascin "__PAGEZERO",16 # consistent with linux + .quad 0,0x200000,0,0 # which forbids mem <2m + .long 0,0,0,0 +20: .long MAC_LC_SEGMENT_64 + .long 30f-20b + .ascin "__TEXT",16 + .quad macho # vaddr + .quad 4096 # memsz + .quad 0 # file offset + .quad filesz # file size + .long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot + .long PROT_EXEC|PROT_READ # initprot + .long 1 # segment section count + .long 0 # flags +210: .ascin "__text",16 # section name (.text) + .ascin "__TEXT",16 + .quad _start # vaddr + .quad textsz # memsz + .long textoff # offset + .long 6 # align 2**3 = 64 + .long 0 # reloc table offset + .long 0 # relocation count + .long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes + .long 0,0,0 # reserved +30: .long MAC_LC_SEGMENT_64 + .long 40f-30b + .ascin "__DATA",16 + .quad bss # vaddr + .quad bsssize # memsz + .quad 0 # offset + .quad 0 # file size + .long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot + .long PROT_READ|PROT_WRITE # initprot + .long 1 # segment section count + .long 0 # flags +310: .ascin "__bss",16 # section name (.bss) + .ascin "__DATA",16 + .quad bss # vaddr + .quad bsssize # memsz + .long 0 # offset + .long 12 # align 2**12 = 4096 + .long 0 # reloc table offset + .long 0 # relocation count + .long MAC_S_ZEROFILL # section type & attributes + .long 0,0,0 # reserved +40: .long MAC_LC_UUID + .long 50f-40b + .quad 0x3fb29ee4ac6c87aa # uuid1 + .quad 0xdd2c9bb866d9eef8 # uuid2 +50: .long MAC_LC_UNIXTHREAD + .long 60f-50b # cmdsize + .long MAC_THREAD_NEXGEN32E # flavaflav + .long (520f-510f)/4 # count +510: .quad 0 # rax + .quad 0 # rbx + .quad 0 # rcx + .quad XNU # rdx + .quad 0 # rdi + .quad 0 # rsi + .quad 0 # rbp + .quad 0 # rsp + .quad 0 # r8 + .quad 0 # r9 + .quad 0 # r10 + .quad 0 # r11 + .quad 0 # r12 + .quad 0 # r13 + .quad 0 # r14 + .quad 0 # r15 + .quad _start # rip + .quad 0 # rflags + .quad 0 # cs + .quad 0 # fs + .quad 0 # gs +520: +60: + .endobj macho,globl + + .align 64 +_start: mov %rsp,%rsi + jmp ApeLoader + .endfn _start,globl + +__syscall_loader: + clc + syscall + jc 1f + ret +1: neg %rax + ret + .endfn __syscall_loader,globl diff --git a/ape/loader-macho.lds b/ape/loader-macho.lds new file mode 100644 index 000000000..973c182a5 --- /dev/null +++ b/ape/loader-macho.lds @@ -0,0 +1,42 @@ +/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│ +│vi: set et sts=2 tw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +ENTRY(_start) + +SECTIONS { + . = 0x200000; + .text : { + *(.text) + *(.rodata .rodata.*) + . = ALIGN(4096); + } + filesz = . - macho; + textsz = . - _start; + .bss ALIGN(4096) : { + bss = .; + *(.bss) + . = ALIGN(4096); + } + memsz = . - macho; + /DISCARD/ : { + *(.*) + } +} + +bsssize = SIZEOF(.bss); +textoff = _start - macho; diff --git a/ape/loader.c b/ape/loader.c index c79b01757..d38e4b838 100644 --- a/ape/loader.c +++ b/ape/loader.c @@ -16,28 +16,88 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/bits.h" -#include "libc/calls/struct/metastat.internal.h" -#include "libc/calls/struct/stat.h" -#include "libc/elf/def.h" -#include "libc/elf/struct/ehdr.h" -#include "libc/elf/struct/phdr.h" -#include "libc/sysv/consts/prot.h" +#include "ape/loader.h" + +#define TROUBLESHOOT 0 +#define TROUBLESHOOT_OS LINUX /** - * @fileoverview APE embeddable loader for Linux and BSD, e.g. + * @fileoverview APE Loader for GNU/Systemd/XNU/FreeBSD/NetBSD/OpenBSD + * + * We recommend using the normal APE design, where binaries assimilate + * themselves once by self-modifying the first 64 bytes. If that can't + * meet your requirements then we provide an excellent alternative. * * m=tiny * make -j8 MODE=$m o/$m/ape o/$m/examples/printargs.com - * o/$m/ape/loader.elf o/$m/examples/printargs.com + * o/$m/ape/ape.elf o/$m/examples/printargs.com + * + * This is an embeddable Actually Portable Executable interpreter. The + * `ape/ape.S` bootloader embeds this binary inside each binary that's + * linked using `$(APE_NO_MODIFY_SELF)` so it is an automated seamless + * process. the shell script at the top of the .COM files will copy it + * to `${TMPDIR:-/tmp}/ape` and call execve(). It's a zero copy + * operation in praxis since this payload uses mmap() to load the rest + * of your executable the same way the kernel does, based on ELF phdrs + * which are located in accordance with the first sh printf statement. + * + * APE executables will look for this program on the system path first + * so your APE loader may be installed to your system as follows: + * + * m=tiny + * make -j8 MODE=$m o/$m/ape/ape.elf + * sudo cp o/$m/ape/ape.elf /usr/bin/ape + * + * For Mac OS X systems you should install the `ape.macho` executable: + * + * sudo cp o/$m/ape/ape.macho /usr/bin/ape + * + * Your APE loader may be used as a shebang interpreter by doing this: + * + * #!/usr/bin/ape python.com + * # -*- python -*- + * print("hello world") + * + * However you won't need to do that, if your APE Loader is registered + * as a binfmt_misc interpreter. You can do that as follows with root: + * + * sudo cp -f o/$m/ape/ape.elf /usr/bin + * f=/proc/sys/fs/binfmt_misc/register + * sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >$f" + * + * If the register file doesn't exist on your Linux machine then you'd + * load it using the following commands: + * + * sudo modprobe binfmt_misc + * sudo mount -t binfmt_misc none /proc/sys/fs/binfmt_misc + * + * You should now experience a performance boost, and you can also now + * use the regular shebang form: + * + * #!/usr/bin/python.com + * # -*- python -*- + * print("hello world") * * @note this can probably be used as a binfmt_misc interpreter */ -#define LINUX 0 -#define FREEBSD 1 -#define NETBSD 2 -#define OPENBSD 3 +#define LINUX 1 +#define XNU 8 +#define OPENBSD 16 +#define FREEBSD 32 +#define NETBSD 64 + +#define SupportsLinux() (SUPPORT_VECTOR & LINUX) +#define SupportsXnu() (SUPPORT_VECTOR & XNU) +#define SupportsFreebsd() (SUPPORT_VECTOR & FREEBSD) +#define SupportsOpenbsd() (SUPPORT_VECTOR & OPENBSD) +#define SupportsNetbsd() (SUPPORT_VECTOR & NETBSD) + +#define IsLinux() (SupportsLinux() && os == LINUX) +#define IsXnu() (SupportsXnu() && os == XNU) +#define IsFreebsd() (SupportsFreebsd() && os == FREEBSD) +#define IsOpenbsd() (SupportsOpenbsd() && os == OPENBSD) +#define IsNetbsd() (SupportsNetbsd() && os == NETBSD) #define O_RDONLY 0 #define PROT_READ 1 @@ -46,173 +106,409 @@ #define MAP_SHARED 1 #define MAP_PRIVATE 2 #define MAP_FIXED 16 -#define MAP_ANONYMOUS (os == LINUX ? 32 : 4096) +#define MAP_ANONYMOUS (IsLinux() ? 32 : 4096) #define AT_EXECFN_LINUX 31 #define AT_EXECFN_NETBSD 2014 +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define EM_NEXGEN32E 62 +#define ET_EXEC 2 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define EI_CLASS 4 +#define EI_DATA 5 +#define PF_X 1 +#define PF_W 2 +#define PF_R 4 +#define X_OK 1 +#define XCR0_SSE 2 +#define XCR0_AVX 4 -#define __NR_read (os == LINUX ? 0 : 3) -#define __NR_write (os == LINUX ? 1 : 4) -#define __NR_open (os == LINUX ? 2 : 5) -#define __NR_close (os == LINUX ? 3 : 6) -#define __NR_exit (os == LINUX ? 60 : 1) -#define __NR_mmap (os == LINUX ? 9 : os == FREEBSD ? 477 : 197) -#define __NR_fstat \ - (os == LINUX ? 5 : os == FREEBSD ? 551 : os == OPENBSD ? 53 : 440) +#define Read32(S) \ + ((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \ + (unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000) -static wontreturn void Exit(int os, long rc) { - asm volatile("syscall" - : /* no outputs */ - : "a"(__NR_exit), "D"(rc) - : "memory"); - unreachable; +#define Read64(S) \ + ((unsigned long)(255 & (S)[7]) << 070 | \ + (unsigned long)(255 & (S)[6]) << 060 | \ + (unsigned long)(255 & (S)[5]) << 050 | \ + (unsigned long)(255 & (S)[4]) << 040 | \ + (unsigned long)(255 & (S)[3]) << 030 | \ + (unsigned long)(255 & (S)[2]) << 020 | \ + (unsigned long)(255 & (S)[1]) << 010 | \ + (unsigned long)(255 & (S)[0]) << 000) + +struct PathSearcher { + char os; + unsigned long namelen; + const char *name; + const char *syspath; + char path[1024]; +}; + +struct ElfEhdr { + unsigned char e_ident[16]; + unsigned short e_type; + unsigned short e_machine; + unsigned e_version; + unsigned long e_entry; + unsigned long e_phoff; + unsigned long e_shoff; + unsigned e_flags; + unsigned short e_ehsize; + unsigned short e_phentsize; + unsigned short e_phnum; + unsigned short e_shentsize; + unsigned short e_shnum; + unsigned short e_shstrndx; +}; + +struct ElfPhdr { + unsigned p_type; + unsigned p_flags; + unsigned long p_offset; + unsigned long p_vaddr; + unsigned long p_paddr; + unsigned long p_filesz; + unsigned long p_memsz; + unsigned long p_align; +}; + +static void *syscall; +static struct PathSearcher ps; +extern char __syscall_loader[]; + +static int ToLower(int c) { + return 'A' <= c && c <= 'Z' ? c + ('a' - 'A') : c; } -static void Close(int os, long fd) { - long ax, di; - asm volatile("syscall" +static char *MemCpy(char *d, const char *s, unsigned long n) { + unsigned long i = 0; + for (; i < n; ++i) d[i] = s[i]; + return d + n; +} + +static unsigned long StrLen(const char *s) { + unsigned long n = 0; + while (*s++) ++n; + return n; +} + +static const char *MemChr(const char *s, unsigned char c, unsigned long n) { + for (; n; --n, ++s) { + if ((*s & 255) == c) { + return s; + } + } + return 0; +} + +static char *GetEnv(char **p, const char *s) { + unsigned long i, j; + if (p) { + for (i = 0; p[i]; ++i) { + for (j = 0;; ++j) { + if (!s[j]) { + if (p[i][j] == '=') { + return p[i] + j + 1; + } + break; + } + if (s[j] != p[i][j]) { + break; + } + } + } + } + return 0; +} + +static char *Utoa(char p[21], unsigned long x) { + char t; + unsigned long i, a, b; + i = 0; + do { + p[i++] = x % 10 + '0'; + x = x / 10; + } while (x > 0); + p[i] = '\0'; + if (i) { + for (a = 0, b = i - 1; a < b; ++a, --b) { + t = p[a]; + p[a] = p[b]; + p[b] = t; + } + } + return p + i; +} + +static char *Itoa(char p[21], long x) { + if (x < 0) *p++ = '-', x = -(unsigned long)x; + return Utoa(p, x); +} + +#if TROUBLESHOOT +const char *DescribeOs(int os) { + if (IsLinux()) { + return "GNU/SYSTEMD"; + } else if (IsXnu()) { + return "XNU"; + } else if (IsFreebsd()) { + return "FREEBSD"; + } else if (IsOpenbsd()) { + return "OPENBSD"; + } else if (IsNetbsd()) { + return "NETBSD"; + } else { + return "WUT"; + } +} +#endif + +__attribute__((__noreturn__)) static void Exit(int rc, int os) { + asm volatile("call\t*%2" + : /* no outputs */ + : "a"((IsLinux() ? 60 : 1) | (IsXnu() ? 0x2000000 : 0)), "D"(rc), + "rm"(syscall) + : "memory"); + __builtin_unreachable(); +} + +static void Close(int fd, int os) { + int ax, di; + asm volatile("call\t*%4" : "=a"(ax), "=D"(di) - : "0"(__NR_close), "1"(fd) + : "0"((IsLinux() ? 3 : 6) | (IsXnu() ? 0x2000000 : 0)), "1"(fd), + "rm"(syscall) : "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc"); } -static long Read(int os, long fd, void *data, unsigned long size) { - bool cf; - long ax, di, si, dx; - asm volatile("clc\n\t" - "syscall" - : "=@ccc"(cf), "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "1"(__NR_read), "2"(fd), "3"(data), "4"(size) +static int Read(int fd, void *data, int size, int os) { + long si; + int ax, di, dx; + asm volatile("call\t*%8" + : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) + : "0"((IsLinux() ? 0 : 3) | (IsXnu() ? 0x2000000 : 0)), "1"(fd), + "2"(data), "3"(size), "rm"(syscall) : "rcx", "r8", "r9", "r10", "r11", "memory"); - if (cf) ax = -ax; return ax; } -static void Write(int os, long fd, const void *data, unsigned long size) { - long ax, di, si, dx; - asm volatile("syscall" +static void Write(int fd, const void *data, int size, int os) { + long si; + int ax, di, dx; + asm volatile("call\t*%8" : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "0"(__NR_write), "1"(fd), "2"(data), "3"(size) + : "0"((IsLinux() ? 1 : 4) | (IsXnu() ? 0x2000000 : 0)), "1"(fd), + "2"(data), "3"(size), "rm"(syscall) : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); } -static long Fstat(int os, long fd, union metastat *st) { - long ax, di, si; - asm volatile("syscall" - : "=a"(ax), "=D"(di), "=S"(si) - : "0"(__NR_fstat), "1"(fd), "2"(st) - : "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc"); +static void Execve(const char *prog, char **argv, char **envp, int os) { + long ax, di, si, dx; + asm volatile("call\t*%8" + : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) + : "0"(59 | (IsXnu() ? 0x2000000 : 0)), "1"(prog), "2"(argv), + "3"(envp), "rm"(syscall) + : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); +} + +static int Access(const char *path, int mode, int os) { + int ax, si; + long dx, di; + asm volatile("call\t*%7" + : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) + : "0"((IsLinux() ? 21 : 33) | (IsXnu() ? 0x2000000 : 0)), + "1"(path), "2"(mode), "rm"(syscall) + : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); return ax; } -static void Msyscall(int os, long p, long n) { - long ax, di, si; - if (os == OPENBSD) { - asm volatile("syscall" +static int Msyscall(long p, long n, int os) { + int ax; + long di, si; + if (!IsOpenbsd()) { + return 0; + } else { + asm volatile("call\t*%6" : "=a"(ax), "=D"(di), "=S"(si) - : "0"(37), "1"(p), "2"(n) + : "0"(37), "1"(p), "2"(n), "rm"(syscall) : "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc"); + return ax; } } -static long Open(int os, const char *path, long flags, long mode) { - bool cf; - long ax, di, si, dx; - asm volatile("clc\n\t" - "syscall" - : "=@ccc"(cf), "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "1"(__NR_open), "2"(path), "3"(flags), "4"(mode) - : "rcx", "r8", "r9", "r10", "r11", "memory"); - if (cf) ax = -ax; +static int Open(const char *path, int flags, int mode, int os) { + long di; + int ax, dx, si; + asm volatile("call\t*%8" + : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) + : "0"((IsLinux() ? 2 : 5) | (IsXnu() ? 0x2000000 : 0)), + "1"(path), "2"(flags), "3"(mode), "rm"(syscall) + : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); return ax; } -static long Mmap(int os, long addr, long size, long prot, long flags, long fd, - long off) { - bool cf; - long ax; - register long flags_ asm("r10") = flags; - register long fd_ asm("r8") = fd; +__attribute__((__noinline__)) static long Mmap(long addr, long size, int prot, + int flags, int fd, long off, + int os) { + long ax, di, si, dx; + register int flags_ asm("r10") = flags; + register int fd_ asm("r8") = fd; register long off_ asm("r9") = off; asm volatile("push\t%%r9\n\t" "push\t%%r9\n\t" - "clc\n\t" - "syscall\n\t" + "call\t*%7\n\t" "pop\t%%r9\n\t" "pop\t%%r9" - : "=@ccc"(cf), "=a"(ax) - : "1"(__NR_mmap), "D"(addr), "S"(size), "d"(prot), "r"(flags_), - "r"(fd_), "r"(off_) - : "rcx", "r11", "memory"); - if (cf) ax = -ax; + : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx), "+r"(flags_), + "+r"(fd_), "+r"(off_) + : "rm"(syscall), + "0"((IsLinux() ? 9 + : IsFreebsd() ? 477 + : 197) | + (IsXnu() ? 0x2000000 : 0)), + "1"(addr), "2"(size), "3"(prot) + : "rcx", "r11", "memory", "cc"); return ax; } -static size_t GetFdSize(int os, int fd) { - union metastat st; - if (!Fstat(os, fd, &st)) { - if (os == LINUX) { - return st.linux.st_size; - } else if (os == FREEBSD) { - return st.freebsd.st_size; - } else if (os == OPENBSD) { - return st.openbsd.st_size; - } else { - return st.netbsd.st_size; +static void Emit(int os, const char *s) { + Write(2, s, StrLen(s), os); +} + +static void Perror(int os, const char *c, int rc, const char *s) { + char ibuf[21]; + Emit(os, "ape error: "); + Emit(os, c); + Emit(os, ": "); + Emit(os, s); + if (rc) { + Emit(os, " failed errno="); + Itoa(ibuf, -rc); + Emit(os, ibuf); + } + Emit(os, "\n"); +} + +__attribute__((__noreturn__)) static void Pexit(int os, const char *c, int rc, + const char *s) { + Perror(os, c, rc, s); + Exit(127, os); +} + +static int StrCmp(const char *l, const char *r) { + unsigned long i = 0; + while (l[i] == r[i] && r[i]) ++i; + return (l[i] & 255) - (r[i] & 255); +} + +static char EndsWithIgnoreCase(const char *p, unsigned long n, const char *s) { + unsigned long i, m; + if (n >= (m = StrLen(s))) { + for (i = n - m; i < n; ++i) { + if (ToLower(p[i]) != *s++) { + return 0; + } } + return 1; } else { return 0; } } -static size_t Length(const char *s) { - size_t n = 0; - while (*s++) ++n; - return n; +static char IsComPath(struct PathSearcher *ps) { + return EndsWithIgnoreCase(ps->name, ps->namelen, ".com") || + EndsWithIgnoreCase(ps->name, ps->namelen, ".exe") || + EndsWithIgnoreCase(ps->name, ps->namelen, ".com.dbg"); } -static void Emit(int os, const char *s) { - Write(os, 2, s, Length(s)); +static char AccessCommand(struct PathSearcher *ps, const char *suffix, + unsigned long pathlen) { + unsigned long suffixlen; + suffixlen = StrLen(suffix); + if (pathlen + 1 + ps->namelen + suffixlen + 1 > sizeof(ps->path)) return 0; + if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/'; + MemCpy(ps->path + pathlen, ps->name, ps->namelen); + MemCpy(ps->path + pathlen + ps->namelen, suffix, suffixlen + 1); + return !Access(ps->path, X_OK, ps->os); } -static void Log(int os, const char *s) { -#ifndef NDEBUG - Emit(os, "ape loader error: "); - Emit(os, s); -#endif -} - -static void Spawn(int os, int fd, long *sp, char *b, struct Elf64_Ehdr *e) { - size_t i; - int prot, flags; - long code, codesize; - struct Elf64_Phdr *p; - if (e->e_ident[EI_CLASS] != ELFCLASS64) { - Log(os, "EI_CLASS != ELFCLASS64\n"); - return; +static char SearchPath(struct PathSearcher *ps, const char *suffix) { + const char *p; + unsigned long i; + for (p = ps->syspath;;) { + for (i = 0; p[i] && p[i] != ':'; ++i) { + if (i < sizeof(ps->path)) { + ps->path[i] = p[i]; + } + } + if (AccessCommand(ps, suffix, i)) { + return 1; + } else if (p[i] == ':') { + p += i + 1; + } else { + return 0; + } } - if (e->e_ident[EI_DATA] != ELFDATA2LSB) { - Log(os, "EI_CLASS != ELFCLASS64\n"); - return; +} + +static char FindCommand(struct PathSearcher *ps, const char *suffix) { + if (MemChr(ps->name, '/', ps->namelen) || + MemChr(ps->name, '\\', ps->namelen)) { + ps->path[0] = 0; + return AccessCommand(ps, suffix, 0); + } else { + if (AccessCommand(ps, suffix, 0)) return 1; + } + return SearchPath(ps, suffix); +} + +static char *Commandv(struct PathSearcher *ps, int os, const char *name, + const char *syspath) { + ps->os = os; + ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin"; + if (!(ps->namelen = StrLen((ps->name = name)))) return 0; + if (ps->namelen + 1 > sizeof(ps->path)) return 0; + if (FindCommand(ps, "") || (!IsComPath(ps) && FindCommand(ps, ".com"))) { + return ps->path; + } else { + return 0; + } +} + +__attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd, + long *sp, char *page, + struct ElfEhdr *e) { + long rc; + unsigned long i; + int prot, flags; + struct ElfPhdr *p; + long code, codesize; + if (e->e_type != ET_EXEC) { + Pexit(os, exe, 0, "ELF e_type != ET_EXEC"); } if (e->e_machine != EM_NEXGEN32E) { - Log(os, "e_machine != EM_NEXGEN32E\n"); - return; + Pexit(os, exe, 0, "ELF e_machine != EM_NEXGEN32E"); } - if (e->e_type != ET_EXEC) { - Log(os, "e_type != ET_EXEC\n"); - return; + if (e->e_ident[EI_CLASS] != ELFCLASS64) { + Pexit(os, exe, 0, "ELF e_ident[EI_CLASS] != ELFCLASS64"); + } + if (e->e_ident[EI_DATA] != ELFDATA2LSB) { + Pexit(os, exe, 0, "ELF e_ident[EI_DATA] != ELFDATA2LSB"); } if (e->e_phoff + e->e_phnum * sizeof(*p) > 0x1000) { - Log(os, "phnum out of bounds\n"); - return; + Pexit(os, exe, 0, "ELF phdrs need to be in first page"); } code = 0; codesize = 0; - for (p = (struct Elf64_Phdr *)(b + e->e_phoff), i = e->e_phnum; i--;) { + for (p = (struct ElfPhdr *)(page + e->e_phoff), i = e->e_phnum; i--;) { + if (p[i].p_type == PT_DYNAMIC) { + Pexit(os, exe, 0, "not a real executable"); + } if (p[i].p_type != PT_LOAD) continue; if ((p[i].p_vaddr | p[i].p_filesz | p[i].p_memsz | p[i].p_offset) & 0xfff) { - Log(os, "ape requires strict page size padding and alignment\n"); - return; + Pexit(os, exe, 0, "APE phdrs must be 4096-aligned and 4096-padded"); } prot = 0; flags = MAP_FIXED | MAP_PRIVATE; @@ -228,107 +524,211 @@ static void Spawn(int os, int fd, long *sp, char *b, struct Elf64_Ehdr *e) { codesize = p[i].p_filesz; } if (p[i].p_memsz > p[i].p_filesz) { - if (Mmap(os, p[i].p_vaddr + p[i].p_filesz, p[i].p_memsz - p[i].p_filesz, - prot, flags | MAP_ANONYMOUS, -1, 0) < 0) { - Log(os, "bss mmap failed\n"); - return; + if ((rc = Mmap(p[i].p_vaddr + p[i].p_filesz, p[i].p_memsz - p[i].p_filesz, + prot, flags | MAP_ANONYMOUS, -1, 0, os)) < 0) { + Pexit(os, exe, rc, "bss mmap()"); } } if (p[i].p_filesz) { - if (Mmap(os, p[i].p_vaddr, p[i].p_filesz, prot, flags, fd, - p[i].p_offset) < 0) { - Log(os, "image mmap failed\n"); - return; + if ((rc = Mmap(p[i].p_vaddr, p[i].p_filesz, prot, flags, fd, + p[i].p_offset, os)) < 0) { + Pexit(os, exe, rc, "image mmap()"); } } } - Close(os, fd); - Msyscall(os, code, codesize); - sp[1] = sp[0] - 1; - ++sp; - asm volatile("mov\t%2,%%rsp\n\t" - "jmpq\t*%1" + if (!code) { + Pexit(os, exe, 0, "ELF needs PT_LOAD phdr w/ PF_X"); + } + Close(fd, os); + + // authorize only the loaded program to issue system calls. if this + // fails, then we pass a link to our syscall function to the program + // since it probably means a userspace program executed this loader + // and passed us a custom syscall function earlier. + if (Msyscall(code, codesize, os) != -1) { + syscall = 0; + } + +#if TROUBLESHOOT + Emit(TROUBLESHOOT_OS, "preparing to jump\n"); +#endif + + // we clear all the general registers we can to have some wiggle room + // to extend the behavior of this loader in the future. we don't need + // to clear the xmm registers since the ape loader should be compiled + // with the -mgeneral-regs-only flag. + register void *r8 asm("r8") = syscall; + asm volatile("xor\t%%eax,%%eax\n\t" + "xor\t%%r9d,%%r9d\n\t" + "xor\t%%r10d,%%r10d\n\t" + "xor\t%%r11d,%%r11d\n\t" + "xor\t%%ebx,%%ebx\n\t" // netbsd dosen't clear this + "xor\t%%r12d,%%r12d\n\t" // netbsd dosen't clear this + "xor\t%%r13d,%%r13d\n\t" // netbsd dosen't clear this + "xor\t%%r14d,%%r14d\n\t" // netbsd dosen't clear this + "xor\t%%r15d,%%r15d\n\t" // netbsd dosen't clear this + "mov\t%%rdx,%%rsp\n\t" + "xor\t%%edx,%%edx\n\t" + "push\t%%rsi\n\t" + "xor\t%%esi,%%esi\n\t" + "xor\t%%ebp,%%ebp\n\t" + "ret" : /* no outputs */ - : "D"(os == FREEBSD ? sp : 0), "S"(e->e_entry), "d"(sp) + : "D"(IsFreebsd() ? sp : 0), "S"(e->e_entry), "d"(sp), "c"(os), + "r"(r8) : "memory"); - unreachable; + __builtin_unreachable(); } -void loader(long di, long *sp) { - size_t size; - long rc, *auxv; - char *p, **argv; +__attribute__((__noreturn__)) void ApeLoader(long di, long *sp, char dl, + struct ApeLoader *handoff) { + int rc; + long *auxv; + struct ElfEhdr *ehdr; int c, i, fd, os, argc; - union { - struct Elf64_Ehdr ehdr; + char *p, *exe, *prog, **argv, **envp, *page; + static union { + struct ElfEhdr ehdr; char p[0x1000]; } u; - os = 0; - if (di) { + + // detect freebsd + if (handoff) { + os = handoff->os; + } else if (SupportsFreebsd() && di) { os = FREEBSD; sp = (long *)di; + } else if (SupportsXnu() && dl == XNU) { + os = XNU; + } else { + os = 0; } + + // extract arguments argc = *sp; argv = (char **)(sp + 1); - auxv = (long *)(argv + argc + 1); + envp = (char **)(sp + 1 + argc + 1); + auxv = (long *)(sp + 1 + argc + 1); for (;;) { if (!*auxv++) { break; } } - if (!auxv[0]) { - os = OPENBSD; + + // get syscall function pointer + if (handoff && handoff->syscall) { + syscall = handoff->syscall; + } else { + syscall = __syscall_loader; } - for (; auxv[0]; auxv += 2) { - if (!os) { - if (auxv[0] == AT_EXECFN_NETBSD) { - os = NETBSD; - if (argc > 1) { - auxv[1] = (long)argv[1]; - } - } else if (auxv[0] == AT_EXECFN_LINUX) { - if (argc > 1) { - auxv[1] = (long)argv[1]; + + if (handoff) { + // we were called by ape_execve() + // no argument parsing is needed + // no path searching is needed + exe = handoff->prog; + fd = handoff->fd; + exe = handoff->prog; + page = handoff->page; + ehdr = (struct ElfEhdr *)handoff->page; + } else { + + // detect openbsd + if (SupportsOpenbsd() && !os && !auxv[0]) { + os = OPENBSD; + } + + // detect netbsd + if (SupportsNetbsd() && !os) { + for (; auxv[0]; auxv += 2) { + if (auxv[0] == AT_EXECFN_NETBSD) { + os = NETBSD; + break; } } } + + // default operating system + if (!os) { + os = LINUX; + } + + // we can load via shell, shebang, or binfmt_misc + if (argc >= 3 && !StrCmp(argv[1], "-")) { + // if the first argument is a hyphen then we give the user the + // power to change argv[0] or omit it entirely. most operating + // systems don't permit the omission of argv[0] but we do, b/c + // it's specified by ANSI X3.159-1988. + prog = (char *)sp[3]; + argc = sp[3] = sp[0] - 3; + argv = (char **)((sp += 3) + 1); + } else if (argc < 2) { + Emit(os, "usage: ape PROG [ARGV1,ARGV2,...]\n" + " ape - PROG [ARGV0,ARGV1,...]\n" + "αcτµαlly pδrταblε εxεcµταblε loader v1.o\n" + "copyright 2022 justine alexandra roberts tunney\n" + "https://justine.lol/ape.html\n"); + Exit(1, os); + } else { + prog = (char *)sp[2]; + argc = sp[1] = sp[0] - 1; + argv = (char **)((sp += 1) + 1); + } + + if (!(exe = Commandv(&ps, os, prog, GetEnv(envp, "PATH")))) { + Pexit(os, prog, 0, "not found (maybe chmod +x)"); + } else if ((fd = Open(exe, O_RDONLY, 0, os)) < 0) { + Pexit(os, exe, fd, "open"); + } else if ((rc = Read(fd, u.p, sizeof(u.p), os)) < 0) { + Pexit(os, exe, rc, "read"); + } else if (rc != sizeof(u.p) && Read32(u.p) != Read32("\177ELF")) { + Pexit(os, exe, 0, "too small"); + } + + page = u.p; + ehdr = &u.ehdr; } - if (argc < 2) { - Emit(os, "usage: loader PROG [ARGS...]\n"); - } else if ((fd = Open(os, argv[1], O_RDONLY, 0)) < 0) { - Log(os, "open failed\n"); - } else if ((rc = Read(os, fd, u.p, sizeof(u.p))) < 0) { - Log(os, "read failed\n"); - } else if (rc != sizeof(u.p)) { - Log(os, "file too small\n"); - } else if (READ32LE(u.p) == READ32LE("\177ELF")) { - Spawn(os, fd, sp, u.p, &u.ehdr); - } else { - for (p = u.p; p < u.p + sizeof(u.p); ++p) { - if (READ64LE(p) == READ64LE("printf '")) { - for (i = 0, p += 8; p + 3 < u.p + sizeof(u.p) && (c = *p++) != '\'';) { - if (c == '\\') { + +#if TROUBLESHOOT + Emit(TROUBLESHOOT_OS, "os = "); + Emit(TROUBLESHOOT_OS, DescribeOs(os)); + Emit(TROUBLESHOOT_OS, "\n"); + for (i = 0; i < argc; ++i) { + Emit(TROUBLESHOOT_OS, "argv = "); + Emit(TROUBLESHOOT_OS, argv[i]); + Emit(TROUBLESHOOT_OS, "\n"); + } +#endif + + if ((IsXnu() && Read32(page) == 0xFEEDFACE + 1) || + (!IsXnu() && Read32(page) == Read32("\177ELF"))) { + Close(fd, os); + Execve(exe, argv, envp, os); + } + + // TODO(jart): Parse Mach-O for old APE binary support on XNU. + for (p = page; p < page + sizeof(u.p); ++p) { + if (Read64(p) != Read64("printf '")) continue; + for (i = 0, p += 8; p + 3 < page + sizeof(u.p) && (c = *p++) != '\'';) { + if (c == '\\') { + if ('0' <= *p && *p <= '7') { + c = *p++ - '0'; + if ('0' <= *p && *p <= '7') { + c *= 8; + c += *p++ - '0'; if ('0' <= *p && *p <= '7') { - c = *p++ - '0'; - if ('0' <= *p && *p <= '7') { - c *= 8; - c += *p++ - '0'; - if ('0' <= *p && *p <= '7') { - c *= 8; - c += *p++ - '0'; - } - } + c *= 8; + c += *p++ - '0'; } } - u.p[i++] = c; - } - if (i >= 64 && READ32LE(u.p) == READ32LE("\177ELF")) { - Spawn(os, fd, sp, u.p, &u.ehdr); - Exit(os, 127); } } + page[i++] = c; + } + if (i >= 64 && Read32(page) == Read32("\177ELF")) { + Spawn(os, exe, fd, sp, page, ehdr); } - Log(os, "could not find printf elf in first page\n"); } - Exit(os, 127); + + Pexit(os, exe, 0, "could not find printf elf in first page"); } diff --git a/ape/loader.h b/ape/loader.h new file mode 100644 index 000000000..7080f1370 --- /dev/null +++ b/ape/loader.h @@ -0,0 +1,20 @@ +#ifndef COSMOPOLITAN_APE_LOADER_H_ +#define COSMOPOLITAN_APE_LOADER_H_ + +#define APE_LOADER_BASE 0x200000 +#define APE_LOADER_SIZE 0x200000 +#define APE_LOADER_ENTRY 0x200400 +#define APE_LOADER_BSS (PAGESIZE * 2) +#define APE_LOADER_STACK 0x7f0000000000 +#define APE_BLOCK_BASE 0x7e0000000000 +#define APE_BLOCK_SIZE 0x000200000000 + +struct ApeLoader { + int fd; + int os; + char *prog; + char *page; + void *syscall; +}; + +#endif /* COSMOPOLITAN_APE_LOADER_H_ */ diff --git a/ape/loader.lds b/ape/loader.lds index 403ae5f9f..b689cbae0 100644 --- a/ape/loader.lds +++ b/ape/loader.lds @@ -17,16 +17,26 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ ENTRY(_start) -OUTPUT_FORMAT(binary) SECTIONS { . = 0x200000; .text : { *(.text) *(.rodata .rodata.*) + . = ALIGN(64); } filesz = . - ehdr; + textsz = . - _start; + .bss ALIGN(4096) : { + bss = .; + *(.bss) + . = ALIGN(4096); + } + memsz = . - ehdr; /DISCARD/ : { *(.*) } } + +bsssize = SIZEOF(.bss); +textoff = _start - ehdr; diff --git a/ape/loader1.S b/ape/loader1.S deleted file mode 100644 index 3114ffdc4..000000000 --- a/ape/loader1.S +++ /dev/null @@ -1,95 +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 2021 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/elf/def.h" -#include "libc/macros.internal.h" - -// APE Loader Executable Structure -// Linux, FreeBSD, NetBSD, OpenBSD - - .align 8 -ehdr: .ascii "\177ELF" - .byte ELFCLASS64 - .byte ELFDATA2LSB - .byte 1 - .byte ELFOSABI_FREEBSD - .quad 0 - .word ET_EXEC # e_type - .word EM_NEXGEN32E # e_machine - .long 1 # e_version - .quad _start # e_entry - .quad phdrs - ehdr # e_phoff - .quad 0 # e_shoff - .long 0 # e_flags - .word 64 # e_ehsize - .word 56 # e_phentsize - .word 3 # e_phnum - .word 0 # e_shentsize - .word 0 # e_shnum - .word 0 # e_shstrndx - .endobj ehdr,globl - -// memcpy(0x200000, loader); xor %eax,%eax; jmp 0x200000 -jg47h: .org 0x47 - .endobj jg47h - -_start: mov %rsp,%rsi - jmp loader - .endfn _start,globl - - .align 8 -phdrs: .long PT_LOAD # p_type - .long PF_R|PF_X # p_flags - .quad 0 # p_offset - .quad ehdr # p_vaddr - .quad ehdr # p_paddr - .quad filesz # p_filesz - .quad filesz # p_memsz - .quad PAGESIZE # p_align - .long PT_GNU_STACK # p_type - .long PF_R|PF_W # p_flags - .quad 0 # p_offset - .quad 0 # p_vaddr - .quad 0 # p_paddr - .quad 0 # p_filesz - .quad 0 # p_memsz - .quad 16 # p_align - .long PT_NOTE # p_type - .long PF_R # p_flags - .quad note - ehdr # p_offset - .quad note # p_vaddr - .quad note # p_paddr - .quad notesize # p_filesz - .quad notesize # p_memsz - .quad 8 # p_align - .endobj phdrs - -note: .long 2f-1f - .long 4f-3f - .long 1 -1: .asciz "OpenBSD" -2: .align 4 -3: .long 0 -4: .long 2f-1f - .long 4f-3f - .long 1 -1: .asciz "NetBSD" -2: .align 4 -3: .long 901000000 -4: .endobj note - notesize = . - note diff --git a/build/bootstrap/ape.elf b/build/bootstrap/ape.elf new file mode 100755 index 000000000..b6da8fcb3 Binary files /dev/null and b/build/bootstrap/ape.elf differ diff --git a/build/bootstrap/apetest.com b/build/bootstrap/apetest.com new file mode 100755 index 000000000..f19ee992d Binary files /dev/null and b/build/bootstrap/apetest.com differ diff --git a/build/bootstrap/ar.com b/build/bootstrap/ar.com index 90bd84a8f..0f1dc30ec 100755 Binary files a/build/bootstrap/ar.com and b/build/bootstrap/ar.com differ diff --git a/build/bootstrap/cocmd.com b/build/bootstrap/cocmd.com new file mode 100755 index 000000000..d31f42752 Binary files /dev/null and b/build/bootstrap/cocmd.com differ diff --git a/build/bootstrap/compile.com b/build/bootstrap/compile.com index df9521d24..0ebc35571 100755 Binary files a/build/bootstrap/compile.com and b/build/bootstrap/compile.com differ diff --git a/build/bootstrap/cp.com b/build/bootstrap/cp.com new file mode 100755 index 000000000..421917e28 Binary files /dev/null and b/build/bootstrap/cp.com differ diff --git a/build/bootstrap/echo.com b/build/bootstrap/echo.com new file mode 100755 index 000000000..7e2cb9852 Binary files /dev/null and b/build/bootstrap/echo.com differ diff --git a/build/bootstrap/gzip.com b/build/bootstrap/gzip.com new file mode 100755 index 000000000..2e1c78976 Binary files /dev/null and b/build/bootstrap/gzip.com differ diff --git a/build/bootstrap/make.com b/build/bootstrap/make.com new file mode 100755 index 000000000..69751182a Binary files /dev/null and b/build/bootstrap/make.com differ diff --git a/build/bootstrap/mkdeps.com b/build/bootstrap/mkdeps.com index 9b9e0cc16..bbb1e066d 100755 Binary files a/build/bootstrap/mkdeps.com and b/build/bootstrap/mkdeps.com differ diff --git a/build/bootstrap/mkdir.com b/build/bootstrap/mkdir.com new file mode 100755 index 000000000..2307febea Binary files /dev/null and b/build/bootstrap/mkdir.com differ diff --git a/build/bootstrap/package.com b/build/bootstrap/package.com index 285af9e64..b5b0e8790 100755 Binary files a/build/bootstrap/package.com and b/build/bootstrap/package.com differ diff --git a/build/bootstrap/pwd.com b/build/bootstrap/pwd.com new file mode 100755 index 000000000..dc562bf51 Binary files /dev/null and b/build/bootstrap/pwd.com differ diff --git a/build/bootstrap/rm.com b/build/bootstrap/rm.com new file mode 100755 index 000000000..a99f8296b Binary files /dev/null and b/build/bootstrap/rm.com differ diff --git a/build/bootstrap/touch.com b/build/bootstrap/touch.com new file mode 100755 index 000000000..3a9630ce5 Binary files /dev/null and b/build/bootstrap/touch.com differ diff --git a/build/bootstrap/unbundle.com b/build/bootstrap/unbundle.com new file mode 100755 index 000000000..e3ddc7d8f Binary files /dev/null and b/build/bootstrap/unbundle.com differ diff --git a/build/bootstrap/zipobj.com b/build/bootstrap/zipobj.com index 1980a9018..c4702c1f8 100755 Binary files a/build/bootstrap/zipobj.com and b/build/bootstrap/zipobj.com differ diff --git a/build/definitions.mk b/build/definitions.mk index cfb7eafe8..6274df0b3 100644 --- a/build/definitions.mk +++ b/build/definitions.mk @@ -50,15 +50,42 @@ ARFLAGS = rcsD ZFLAGS ?= XARGS ?= xargs -P4 -rs8000 DOT ?= dot -GZ ?= gzip CLANG = clang FC = gfortran #/opt/cross9f/bin/x86_64-linux-musl-gfortran +TMPDIR = o/tmp -# see build/compile, etc. which run third_party/gcc/unbundle.sh AR = build/bootstrap/ar.com +CP = build/bootstrap/cp.com +RM = build/bootstrap/rm.com -f +ECHO = build/bootstrap/echo.com +TOUCH = build/bootstrap/touch.com PKG = build/bootstrap/package.com MKDEPS = build/bootstrap/mkdeps.com ZIPOBJ = build/bootstrap/zipobj.com +MKDIR = build/bootstrap/mkdir.com -p +COMPILE = build/bootstrap/compile.com -V9 $(QUOTA) + +COMMA := , +PWD := $(shell build/bootstrap/pwd.com) +IMAGE_BASE_VIRTUAL ?= 0x400000 + +IGNORE := $(shell $(ECHO) -2 ♥cosmo) +IGNORE := $(shell $(MKDIR) o/tmp) + +ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe)","") +AS = o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe +CC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe +CXX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-g++.exe +CXXFILT = o/third_party/gcc/bin/x86_64-pc-linux-gnu-c++filt.exe +LD = o/third_party/gcc/bin/x86_64-pc-linux-gnu-ld.bfd.exe +NM = o/third_party/gcc/bin/x86_64-pc-linux-gnu-nm.exe +GCC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe +STRIP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-strip.exe +OBJCOPY = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objcopy.exe +OBJDUMP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objdump.exe +ADDR2LINE = $(shell build/bootstrap/pwd.com)/o/third_party/gcc/bin/x86_64-pc-linux-gnu-addr2line.exe +else +IGNORE := $(shell build/bootstrap/unbundle.com) AS = o/third_party/gcc/bin/x86_64-linux-musl-as CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++ @@ -69,18 +96,12 @@ GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump -ADDR2LINE = $(shell pwd)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line - -COMMA := , -PWD := $(shell pwd) -IMAGE_BASE_VIRTUAL ?= 0x400000 -HELLO := $(shell build/hello) -TMPDIR := $(shell build/findtmp) -SPAWNER := $(shell build/getcompile) -V$(shell build/getccversion $(CC)) -COMPILE = $(SPAWNER) $(HARNESSFLAGS) $(QUOTA) +ADDR2LINE = $(shell build/bootstrap/pwd.com)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line +endif export ADDR2LINE export LC_ALL +export MKDIR export MODE export SOURCE_DATE_EPOCH export TMPDIR @@ -115,7 +136,7 @@ TRADITIONAL = \ DEFAULT_CCFLAGS = \ -Wall \ -Werror \ - -fdebug-prefix-map="$(PWD)"= \ + -fdebug-prefix-map='$(PWD)'= \ -frecord-gcc-switches DEFAULT_OFLAGS = \ @@ -180,7 +201,7 @@ PYFLAGS = \ ASONLYFLAGS = \ -c \ -g \ - --debug-prefix-map="$(PWD)"= + --debug-prefix-map='$(PWD)'= DEFAULT_LDLIBS = diff --git a/build/findtmp b/build/findtmp deleted file mode 100755 index 441b765ab..000000000 --- a/build/findtmp +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐ -#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘ -# -# OVERVIEW -# -# Temporary Directory Discovery -# -# DESCRIPTION -# -# We call this script once per build to ideally find a folder that's -# backed by an in-memory file system. We then export it to the TMPDIR -# environment variable. Many programs use it under the hood, e.g. gcc, -# so it grants many small performance improvements. - -mkdir -p o/tmp -echo $PWD/o/tmp diff --git a/build/getccversion b/build/getccversion deleted file mode 100755 index ed74ba39a..000000000 --- a/build/getccversion +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh -#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐ -#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘ -# -# OVERVIEW -# -# Compiler Version Discovery -# -# DESCRIPTION -# -# Cosmopolitan itself may be built using either GCC and Clang, and our -# build irons out many of the differences between the two. This script -# is used by build/definitions.mk alongside build/getccname to support -# the different versions folks use. -# -# Our aim is to support GCC 4.2.1+ since that's the last GPLv2 version -# with any sort of industry consensus. Please note, Cosmopolitan never -# links GCC runtimes when using later versions, so some concerns might -# not apply. - -if [ ! -d o/third_party/gcc ]; then - third_party/gcc/unbundle.sh -fi - -set -e - -MAJOR_VERSION=$( - $1 --version | - head -n1 | - sed -n ' - s!^[^(]*([^)]*) \([[:digit:]][[:digit:]]*\).*!\1!p - s!^.*clang.*version \([[:digit:]][[:digit:]]*\).*!\1!p - ') - -if [ -z "$MAJOR_VERSION" ]; then - echo 6 -else - printf '%s\n' "$MAJOR_VERSION" -fi diff --git a/build/getcompile b/build/getcompile deleted file mode 100755 index 7fbee1812..000000000 --- a/build/getcompile +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐ -#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘ - -if ! [ o/build/bootstrap/compile.com -nt build/bootstrap/compile.com ]; then - mkdir -p o/build/bootstrap/ - cp -f build/bootstrap/compile.com o/build/bootstrap/compile.$$.com - o/build/bootstrap/compile.$$.com -n - mv -f o/build/bootstrap/compile.$$.com o/build/bootstrap/compile.com -fi - -echo o/build/bootstrap/compile.com diff --git a/build/hello b/build/hello deleted file mode 100755 index b62ca7693..000000000 --- a/build/hello +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐ -#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘ -# -# SYNOPSIS -# -# HELLO BUILD -# -# OVERVIEW -# -# We generate a line at the start of each Makefile run, because if we -# use `make V=0` mode then the terminal logging trick we use in -# tool/build/compile.c will delete the previous line, and we'd rather -# have that line not be the bash prompt that ran make. -# -# This script is also useful for giving us an indicator each time the -# build restarts itself from scratch, which can happen in cases like -# when dependencies need to be regenerated by tool/build/mkdeps.c - -echo ♥cosmo >&2 diff --git a/build/htags b/build/htags index b5957145f..f1ffc2dd0 100755 --- a/build/htags +++ b/build/htags @@ -43,6 +43,10 @@ # '(progn # (add-hook 'c-mode-common-hook 'jart-c-mode-common-hook))) +# ctags doesn't understand atomics, e.g. +# extern char **environ; +set -- --regex-c='/_Atomic(\([^)]*\))/\1/b' "$@" + # ctags doesn't understand variable prototypes, e.g. # extern char **environ; set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@" diff --git a/build/rules.mk b/build/rules.mk index 34c2359c8..e999984c7 100644 --- a/build/rules.mk +++ b/build/rules.mk @@ -29,7 +29,6 @@ o/%.o: %.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx o/%.o: o/%.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $< o/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $< o/%.inc: %.h ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) -D__ASSEMBLER__ -P $< -o/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^) o/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $< o/%.okk: % ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $< o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $< @@ -75,7 +74,6 @@ o/$(MODE)/%.ncabi.o: %.ncabi.c ; @$(COMPILE) -AOBJECTIFY.nc $(OBJECTIFY.ncab o/$(MODE)/%.real.o: %.c ; @$(COMPILE) -AOBJECTIFY.real $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.runs: o/$(MODE)/% ; @$(COMPILE) -ACHECK -tT$@ $< $(TESTARGS) -o/$(MODE)/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^) o/$(MODE)/%.zip.o: % ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $< o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $< o/$(MODE)/%-gcc.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $< @@ -87,6 +85,14 @@ o/%.a: $(file >$@.args,$^) @$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ @$@.args +o/%.pkg: + $(file >$@.args,$(filter %.o,$^)) + @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$@.args + +o/$(MODE)/%.pkg: + $(file >$@.args,$(filter %.o,$^)) + @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$@.args + o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com @$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $< diff --git a/build/sanitycheck b/build/sanitycheck index c2da2d263..3bd95062f 100755 --- a/build/sanitycheck +++ b/build/sanitycheck @@ -27,29 +27,38 @@ EOF exit 1 fi -build/sanitycheck2 -if [ $? -ne 123 ]; then +if [ ! -f /proc/sys/fs/binfmt_misc/status ]; then + exit 0 +fi + +STATUS="$(build/bootstrap/apetest.com)" +if [ x"$STATUS" != xsuccess ]; then cat <<'EOF' >&2 ERROR - Thompson Shell Backwards Compatibility Issue Detected + APE Execution error. DETAILS - Actually Portable Executable assumes stock Linux configuration. - Normal behavior is non-ELF files with x bit are run by /bin/sh. - Linux lets people globally define arbitrary magic interpreters. - Your computer couldve been tuned to run MZ scripts inside WINE. - So if you use binfmt_misc you need to explicitly register this. + Your system has probably been configured to use binfmt_misc. You need + to run the command below to install /usr/bin/ape and register it with + binfmt_misc. See ape/loader.c for source code, and technical details. WORKAROUND - sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register" + ape/apeinstall.sh + +NOTES + + If it still doesn't work, possibly due to an overly aggressive WINE + or WSL registration, or possibly due to the ordering of definitions, + then one troubleshooting step is to just unregister everything using + sudo sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/status' and try again. SEE ALSO - https://justine.storage.googleapis.com/ape.html + https://justine.lol/ape.html EOF kill $1 diff --git a/build/sanitycheck2 b/build/sanitycheck2 deleted file mode 100755 index 152c3644a..000000000 --- a/build/sanitycheck2 +++ /dev/null @@ -1,9 +0,0 @@ -MZqFpD=123 -exit $MZqFpD - - - - - - - diff --git a/examples/compress.c b/examples/compress.c new file mode 100644 index 000000000..640672b66 --- /dev/null +++ b/examples/compress.c @@ -0,0 +1,121 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/assert.h" +#include "libc/errno.h" +#include "libc/fmt/conv.h" +#include "libc/log/check.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "third_party/zlib/zlib.h" + +#define CHUNK 32768 + +// clang-format off +// make -j8 o//examples && dd if=/dev/urandom count=100 | tee a | o//examples/compress.com | o//examples/decompress.com >b && sha1sum a b +/* +# data file is o/dbg/third_party/python/python.com +# level 0 147517 compress 495 MB/s decompress 1.4 GB/s +# level 1 80274 compress 29.2 MB/s decompress 303 MB/s +# level 2 79384 compress 33.8 MB/s decompress 212 MB/s +# level 3 78875 compress 28.9 MB/s decompress 224 MB/s +# level 4 78010 compress 27.1 MB/s decompress 319 MB/s <-- sweet spot? +# level 5 77107 compress 19.5 MB/s decompress 273 MB/s +# level 6 75081 compress 10.0 MB/s decompress 99.3 MB/s +# level 7 75022 compress 7.5 MB/s decompress 287 MB/s +# level 8 75016 compress 5.4 MB/s decompress 109 MB/s +# level 9 75016 compress 5.4 MB/s decompress 344 MB/s +m= +make -j8 MODE=$m o/$m/examples || exit +for level in $(seq 0 9); do + o/$m/examples/compress.com $level /tmp/info >/tmp/comp + compspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info) + o/$m/examples/decompress.com $level /tmp/info >/dev/null + decompspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info) + size=$(o/$m/examples/compress.com $level 1) { + level = atoi(argv[1]); + } else { + level = Z_DEFAULT_COMPRESSION; + } + rc = compressor(0, 1, level); + if (rc == Z_OK) { + return 0; + } else { + fprintf(stderr, "error: compressor: %s\n", zerr(rc)); + return 1; + } +} diff --git a/examples/shell.c b/examples/cosh.c similarity index 60% rename from examples/shell.c rename to examples/cosh.c index 19c9f2082..822fdb4d3 100644 --- a/examples/shell.c +++ b/examples/cosh.c @@ -14,6 +14,7 @@ #include "libc/calls/struct/timespec.h" #include "libc/fmt/fmt.h" #include "libc/fmt/itoa.h" +#include "libc/intrin/kprintf.h" #include "libc/log/internal.h" #include "libc/log/log.h" #include "libc/macros.internal.h" @@ -24,22 +25,29 @@ #include "libc/str/str.h" #include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/dt.h" +#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/sig.h" #include "libc/time/time.h" #include "libc/x/x.h" #include "third_party/linenoise/linenoise.h" /** - * @fileoverview Shell that works on Windows. + * @fileoverview Cosmopolitan Shell * * This doesn't have script language features like UNBOURNE.COM but it - * works on Windows and, unlike CMD.EXE, actually has CTRL-P and CTRL-R - * which alone make it so much better. + * works on Windows and, unlike CMD.EXE, has CTRL-P, CTRL-R, and other + * GNU Emacs / Readline keyboard shortcuts. * * One day we'll have UNBOURNE.COM working on Windows but the code isn't * very maintainable sadly. */ +volatile int gotint; + +static void OnInterrupt(int sig) { + gotint = sig; +} + static void AddUniqueCompletion(linenoiseCompletions *c, char *s) { size_t i; if (!s) return; @@ -106,20 +114,40 @@ static char *ShellHint(const char *p, const char **ansi1, const char **ansi2) { return h; } +static char *MakePrompt(char *p) { + char *s, buf[256]; + if (!gethostname(buf, sizeof(buf))) { + p = stpcpy(p, "\e[95m"); + if ((s = getenv("USER"))) { + p = stpcpy(p, s); + *p++ = '@'; + } + p = stpcpy(p, buf); + *p++ = ':'; + } + p = stpcpy(p, "\e[96m"); + if ((s = getcwd(buf, sizeof(buf)))) { + p = stpcpy(p, s); + } + return stpcpy(p, "\e[0m>: "); +} + int main(int argc, char *argv[]) { bool timeit; int64_t nanos; - int n, ws, pid; struct rusage ru; struct timespec ts1, ts2; char *prog, path[PATH_MAX]; sigset_t chldmask, savemask; - struct sigaction ignore, saveint, savequit; - char *p, *line, **args, *arg, *start, *state, prompt[64]; + int stdoutflags, stderrflags; + const char *stdoutpath, *stderrpath; + int n, rc, ws, pid, child, killcount; + struct sigaction sa, saveint, savequit; + char *p, *line, **args, *arg, *start, *state, prompt[1024]; linenoiseSetFreeHintsCallback(free); linenoiseSetHintsCallback(ShellHint); linenoiseSetCompletionCallback(ShellCompletion); - stpcpy(prompt, "$ "); + MakePrompt(prompt); while ((line = linenoiseWithHistory(prompt, "cmd"))) { n = 0; start = line; @@ -129,35 +157,114 @@ int main(int argc, char *argv[]) { } else { timeit = false; } + stdoutpath = 0; + stderrpath = 0; + stdoutflags = 0; + stderrflags = 0; args = xcalloc(1, sizeof(*args)); while ((arg = strtok_r(start, " \t\r\n", &state))) { - args = xrealloc(args, (++n + 1) * sizeof(*args)); - args[n - 1] = arg; - args[n - 0] = 0; + // cmd >>stdout.txt + if (arg[0] == '>' && arg[1] == '>') { + stdoutflags = O_WRONLY | O_APPEND | O_CREAT; + stdoutpath = arg + 2; + } else if (arg[0] == '>') { + // cmd >stdout.txt + stdoutflags = O_WRONLY | O_CREAT | O_TRUNC; + stdoutpath = arg + 1; + } else if (arg[0] == '2' && arg[1] == '>' && arg[2] == '>') { + // cmd 2>>stderr.txt + stderrflags = O_WRONLY | O_APPEND | O_CREAT; + stderrpath = arg + 3; + } else if (arg[0] == '2' && arg[1] == '>') { + // cmd 2>stderr.txt + stderrflags = O_WRONLY | O_CREAT | O_TRUNC; + stderrpath = arg + 2; + } else { + // arg + args = xrealloc(args, (++n + 1) * sizeof(*args)); + args[n - 1] = arg; + args[n - 0] = 0; + } start = 0; } if (n > 0) { if ((prog = commandv(args[0], path, sizeof(path)))) { - ignore.sa_flags = 0; - ignore.sa_handler = SIG_IGN; - sigemptyset(&ignore.sa_mask); - sigaction(SIGINT, &ignore, &saveint); - sigaction(SIGQUIT, &ignore, &savequit); + + // let keyboard interrupts kill child and not shell + gotint = 0; + killcount = 0; + sa.sa_flags = 0; + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + sigaction(SIGQUIT, &sa, &savequit); + sa.sa_handler = OnInterrupt; + sigaction(SIGINT, &sa, &saveint); sigemptyset(&chldmask); sigaddset(&chldmask, SIGCHLD); sigprocmask(SIG_BLOCK, &chldmask, &savemask); + // record timestamp if (timeit) { clock_gettime(CLOCK_REALTIME, &ts1); } - if (!fork()) { + + // launch process + if (!(child = vfork())) { + if (stdoutpath) { + close(1); + open(stdoutpath, stdoutflags, 0644); + } + if (stderrpath) { + close(2); + open(stderrpath, stderrflags, 0644); + } sigaction(SIGINT, &saveint, 0); sigaction(SIGQUIT, &savequit, 0); sigprocmask(SIG_SETMASK, &savemask, 0); execv(prog, args); _Exit(127); } - wait4(0, &ws, 0, &ru); + + // wait for process + for (;;) { + if (gotint) { + switch (killcount) { + case 0: + // ctrl-c + // we do nothing + // terminals broadcast sigint to process group + rc = 0; + break; + case 1: + // ctrl-c ctrl-c + // we try sending sigterm + rc = kill(child, SIGTERM); + break; + default: + // ctrl-c ctrl-c ctrl-c ... + // we use kill -9 as our last resort + rc = kill(child, SIGKILL); + break; + } + if (rc == -1) { + fprintf(stderr, "kill failed: %m\n"); + exit(1); + } + ++killcount; + gotint = 0; + } + rc = wait4(0, &ws, 0, &ru); + if (rc != -1) { + break; + } else if (errno == EINTR) { + errno = 0; + } else { + fprintf(stderr, "wait failed: %m\n"); + exit(1); + } + } + + // print resource consumption for `time` pseudocommand if (timeit) { clock_gettime(CLOCK_REALTIME, &ts2); if (ts2.tv_sec == ts1.tv_sec) { @@ -174,23 +281,27 @@ int main(int argc, char *argv[]) { free(p); } + // update prompt to reflect exit status p = prompt; if (WIFEXITED(ws)) { if (WEXITSTATUS(ws)) { if (!__nocolor) p = stpcpy(p, "\e[1;31m"); p = stpcpy(p, "rc="); p = FormatInt32(p, WEXITSTATUS(ws)); + if (128 < WEXITSTATUS(ws) && WEXITSTATUS(ws) <= 128 + 32) { + *p++ = ' '; + p = stpcpy(p, strsignal(WEXITSTATUS(ws) - 128)); + } if (!__nocolor) p = stpcpy(p, "\e[0m"); *p++ = ' '; } } else { if (!__nocolor) p = stpcpy(p, "\e[1;31m"); - p = stpcpy(p, "rc="); p = stpcpy(p, strsignal(WTERMSIG(ws))); if (!__nocolor) p = stpcpy(p, "\e[0m"); *p++ = ' '; } - p = stpcpy(p, "$ "); + MakePrompt(p); sigaction(SIGINT, &saveint, 0); sigaction(SIGQUIT, &savequit, 0); diff --git a/examples/cp.c b/examples/cp.c deleted file mode 100644 index ddb4910c3..000000000 --- a/examples/cp.c +++ /dev/null @@ -1,96 +0,0 @@ -#if 0 -/*─────────────────────────────────────────────────────────────────╗ -│ To the extent possible under law, Justine Tunney has waived │ -│ all copyright and related or neighboring rights to this file, │ -│ as it is written in the following disclaimers: │ -│ • http://unlicense.org/ │ -│ • http://creativecommons.org/publicdomain/zero/1.0/ │ -╚─────────────────────────────────────────────────────────────────*/ -#endif -#include "libc/calls/calls.h" -#include "libc/calls/copyfile.h" -#include "libc/errno.h" -#include "libc/fmt/conv.h" -#include "libc/fmt/fmt.h" -#include "libc/runtime/gc.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/ex.h" -#include "libc/sysv/consts/exit.h" -#include "libc/sysv/consts/ok.h" -#include "libc/x/x.h" -#include "third_party/getopt/getopt.h" - -#define USAGE \ - " SRC... DST\n\ -\n\ -SYNOPSIS\n\ -\n\ - Copies Files\n\ -\n\ -FLAGS\n\ -\n\ - -?\n\ - -h help\n\ - -f force\n\ - -n no clobber\n\ - -a preserve all\n\ - -p preserve owner and timestamps\n\ -\n" - -int flags; -bool force; - -wontreturn void PrintUsage(int rc, FILE *f) { - fprintf(f, "%s%s%s", "Usage: ", program_invocation_name, USAGE); - exit(rc); -} - -void GetOpts(int argc, char *argv[]) { - int opt; - while ((opt = getopt(argc, argv, "?hfnap")) != -1) { - switch (opt) { - case 'f': - force = true; - break; - case 'n': - flags |= COPYFILE_NOCLOBBER; - break; - case 'a': - case 'p': - flags |= COPYFILE_PRESERVE_OWNER; - flags |= COPYFILE_PRESERVE_TIMESTAMPS; - break; - case 'h': - case '?': - PrintUsage(EXIT_SUCCESS, stdout); - default: - PrintUsage(EX_USAGE, stderr); - } - } -} - -int cp(const char *src, const char *dst) { - if (endswith(dst, "/") || isdirectory(dst)) { - dst = _gc(xasprintf("%s/%s", dst, basename(src))); - } - if (!force && access(dst, W_OK) == -1 && errno != ENOENT) goto OnFail; - if (copyfile(src, dst, flags) == -1) goto OnFail; - return 0; -OnFail: - fprintf(stderr, "%s %s %s: %s\n", "error: cp", src, dst, strerror(errno)); - return -1; -} - -int main(int argc, char *argv[]) { - int i; - GetOpts(argc, argv); - if (argc - optind < 2) PrintUsage(EX_USAGE, stderr); - for (i = optind; i < argc - 1; ++i) { - if (cp(argv[i], argv[argc - 1]) == -1) { - return -1; - } - } - return 0; -} diff --git a/examples/crashreport.c b/examples/crashreport.c index 03f0650ff..558b6a28a 100644 --- a/examples/crashreport.c +++ b/examples/crashreport.c @@ -8,6 +8,7 @@ ╚─────────────────────────────────────────────────────────────────*/ #endif #include "libc/log/log.h" +#include "libc/runtime/symbols.internal.h" /** * @fileoverview How to print backtraces and cpu state on crash. diff --git a/examples/decompress.c b/examples/decompress.c new file mode 100644 index 000000000..657a0a4ed --- /dev/null +++ b/examples/decompress.c @@ -0,0 +1,123 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/assert.h" +#include "libc/errno.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/stdio/stdio.h" +#include "third_party/zlib/zlib.h" + +#define CHUNK 32768 + +// clang-format off +// make -j8 o//examples && dd if=/dev/urandom count=100 | tee a | o//examples/compress.com | o//examples/decompress.com >b && sha1sum a b +/* +# data file is o/dbg/third_party/python/python.com +# level 0 147517 compress 495 MB/s decompress 1.4 GB/s +# level 1 80274 compress 29.2 MB/s decompress 303 MB/s +# level 2 79384 compress 33.8 MB/s decompress 212 MB/s +# level 3 78875 compress 28.9 MB/s decompress 224 MB/s +# level 4 78010 compress 27.1 MB/s decompress 319 MB/s <-- sweet spot? +# level 5 77107 compress 19.5 MB/s decompress 273 MB/s +# level 6 75081 compress 10.0 MB/s decompress 99.3 MB/s +# level 7 75022 compress 7.5 MB/s decompress 287 MB/s +# level 8 75016 compress 5.4 MB/s decompress 109 MB/s +# level 9 75016 compress 5.4 MB/s decompress 344 MB/s +m= +make -j8 MODE=$m o/$m/examples || exit +for level in $(seq 0 9); do + o/$m/examples/compress.com $level /tmp/info >/tmp/comp + compspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info) + o/$m/examples/decompress.com $level /tmp/info >/dev/null + decompspeed=$(grep -Po '[.\d]+ \w+/s' /tmp/info) + size=$(o/$m/examples/compress.com $level $@ +o/$(MODE)/usr/share/dict/words: \ + usr/share/dict/words.gz \ + o/$(MODE)/tool/build/gzip.com + @$(MKDIR) $(@D) + @o/$(MODE)/tool/build/gzip.com $(ZFLAGS) -cd <$< >$@ .PHONY: o/$(MODE)/examples o/$(MODE)/examples: \ o/$(MODE)/examples/package \ + o/$(MODE)/examples/pyapp \ $(EXAMPLES_BINS) diff --git a/examples/greenbean.c b/examples/greenbean.c index 840926388..0d475bd85 100644 --- a/examples/greenbean.c +++ b/examples/greenbean.c @@ -1,32 +1,32 @@ -/*-*- 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 2022 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/assert.h" +#include "libc/bits/atomic.h" #include "libc/calls/calls.h" #include "libc/calls/sigbits.h" #include "libc/calls/struct/sigset.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timeval.h" +#include "libc/dce.h" +#include "libc/fmt/conv.h" #include "libc/fmt/itoa.h" #include "libc/intrin/kprintf.h" +#include "libc/limits.h" #include "libc/log/check.h" #include "libc/log/log.h" +#include "libc/macros.internal.h" #include "libc/mem/mem.h" -#include "libc/sock/goodsocket.internal.h" +#include "libc/nexgen32e/threaded.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/stack.h" +#include "libc/runtime/sysconf.h" #include "libc/sock/sock.h" #include "libc/str/str.h" #include "libc/sysv/consts/af.h" @@ -34,6 +34,7 @@ #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/rlimit.h" #include "libc/sysv/consts/sig.h" @@ -69,25 +70,25 @@ * Like redbean, greenbean has superior performance too, with an * advantage on benchmarks biased towards high connection counts * - * $ sudo wrk -c 300 -t 32 --latency http://127.0.0.1:8080/ - * Running 10s test @ http://127.0.0.1:8080/ + * $ wrk -c 300 -t 32 --latency http://10.10.10.124:8080/ + * Running 10s test @ http://10.10.10.124:8080/ * 32 threads and 300 connections * Thread Stats Avg Stdev Max +/- Stdev - * Latency 36.21us 133.39us 8.10ms 98.52% - * Req/Sec 73.24k 28.92k 131.06k 47.49% + * Latency 661.06us 5.11ms 96.22ms 98.85% + * Req/Sec 42.38k 8.90k 90.47k 84.65% * Latency Distribution - * 50% 22.00us - * 75% 29.00us - * 90% 40.00us - * 99% 333.00us - * 4356560 requests in 4.62s, 1.29GB read - * Requests/sec: 942663.73 - * Transfer/sec: 284.98MB + * 50% 184.00us + * 75% 201.00us + * 90% 224.00us + * 99% 11.99ms + * 10221978 requests in 7.60s, 3.02GB read + * Requests/sec: 1345015.69 + * Transfer/sec: 406.62MB * */ -#define THREADS 32 -#define HEARTBEAT 500 +#define PORT 8080 +#define HEARTBEAT 100 #define KEEPALIVE 5000 #define LOGGING 0 @@ -96,40 +97,48 @@ "Referrer-Policy: origin\r\n" \ "Cache-Control: private; max-age=0\r\n" -int workers; -int barrier; -int closingtime; +int threads; +_Atomic(int) workers; +_Atomic(int) messages; +_Atomic(int) listening; +_Atomic(int) connections; +_Atomic(int) closingtime; +const char *volatile status; int Worker(void *id) { - int server, itsover, ready, yes = 1; - - // announce to the main process this has spawned - kprintf(" #%.2ld", (intptr_t)id); - __atomic_add_fetch(&workers, 1, __ATOMIC_SEQ_CST); - - // wait for all threads to spawn before we proceed - for (;;) { - __atomic_load(&barrier, &ready, __ATOMIC_SEQ_CST); - if (ready) break; - __builtin_ia32_pause(); - } + int server, yes = 1; // load balance incoming connections for port 8080 across all threads // hangup on any browser clients that lag for more than a few seconds struct timeval timeo = {KEEPALIVE / 1000, KEEPALIVE % 1000}; - struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(8080)}; - CHECK_NE(-1, (server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))); + struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(PORT)}; + + server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (server == -1) { + kprintf("socket() failed %m\n" + " try running: sudo prlimit --pid=$$ --nofile=%d\n", + threads * 2); + goto WorkerFinished; + } + setsockopt(server, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); setsockopt(server, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)); setsockopt(server, SOL_TCP, TCP_FASTOPEN, &yes, sizeof(yes)); setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes)); - CHECK_EQ(0, bind(server, &addr, sizeof(addr))); - CHECK_EQ(0, listen(server, 10)); + errno = 0; + + if (bind(server, &addr, sizeof(addr)) == -1) { + kprintf("%s() failed %m\n", "socket"); + goto CloseWorker; + } + + listen(server, 1); // connection loop - for (;;) { + ++listening; + while (!closingtime) { struct tm tm; int64_t unixts; struct Url url; @@ -141,6 +150,13 @@ int Worker(void *id) { char inbuf[1500], outbuf[512], *p, *q; int clientip, client, inmsglen, outmsglen; + // this slows the server down a lot but is needed on non-Linux to + // react to keyboard ctrl-c + if (!IsLinux() && + poll(&(struct pollfd){server, POLLIN}, 1, HEARTBEAT) < 1) { + continue; + } + // wait for client connection clientaddrsize = sizeof(clientaddr); client = accept(server, &clientaddr, &clientaddrsize); @@ -153,12 +169,12 @@ int Worker(void *id) { // inherited by the accepted sockets, but using them also has the // side-effect that the listening socket fails with EAGAIN, every // several seconds. we can use that to our advantage to check for - // the ctrl-c shutdown event; otherwise, we retry the accept call - __atomic_load(&closingtime, &itsover, __ATOMIC_SEQ_CST); - if (itsover) break; + // the ctrl-c shutdowne event; otherwise, we retry the accept call continue; } + ++connections; + // message loop do { // parse the incoming http message @@ -167,11 +183,12 @@ int Worker(void *id) { if ((got = read(client, inbuf, sizeof(inbuf))) <= 0) break; // check that client message wasn't fragmented into more reads if (!(inmsglen = ParseHttpMessage(&msg, inbuf, got))) break; + ++messages; #if LOGGING // log the incoming http message clientip = ntohl(clientaddr.sin_addr.s_addr); - kprintf("#%.2ld get some %d.%d.%d.%d:%d %#.*s\n", (intptr_t)id, + kprintf("%6P get some %d.%d.%d.%d:%d %#.*s\n", (clientip & 0xff000000) >> 030, (clientip & 0x00ff0000) >> 020, (clientip & 0x0000ff00) >> 010, (clientip & 0x000000ff) >> 000, ntohs(clientaddr.sin_port), msg.uri.b - msg.uri.a, @@ -189,7 +206,7 @@ int Worker(void *id) { p = stpcpy(outbuf, "HTTP/1.1 200 OK\r\n" STANDARD_RESPONSE_HEADERS "Content-Type: text/html; charset=utf-8\r\n" "Date: "); - clock_gettime(CLOCK_REALTIME, &ts), unixts = ts.tv_sec; + clock_gettime(0, &ts), unixts = ts.tv_sec; p = FormatHttpDateTime(p, gmtime_r(&unixts, &tm)); p = stpcpy(p, "\r\nContent-Length: "); p = FormatInt32(p, strlen(q)); @@ -207,7 +224,7 @@ int Worker(void *id) { "HTTP/1.1 404 Not Found\r\n" STANDARD_RESPONSE_HEADERS "Content-Type: text/html; charset=utf-8\r\n" "Date: "); - clock_gettime(CLOCK_REALTIME, &ts), unixts = ts.tv_sec; + clock_gettime(0, &ts), unixts = ts.tv_sec; p = FormatHttpDateTime(p, gmtime_r(&unixts, &tm)); p = stpcpy(p, "\r\nContent-Length: "); p = FormatInt32(p, strlen(q)); @@ -227,58 +244,101 @@ int Worker(void *id) { (msg.method == kHttpGet || msg.method == kHttpHead)); DestroyHttpMessage(&msg); close(client); + --connections; } + --listening; // inform the parent that this clone has finished +CloseWorker: close(server); - kprintf(" #%.2ld", (intptr_t)id); - __atomic_sub_fetch(&workers, 1, __ATOMIC_SEQ_CST); +WorkerFinished: + --workers; return 0; } void OnCtrlC(int sig) { closingtime = true; + status = " shutting down..."; +} + +void PrintStatus(void) { + kprintf("\r\e[K\e[32mgreenbean\e[0m " + "workers=%d " + "listening=%d " + "connections=%d " + "messages=%d%s ", + workers, listening, connections, messages, status); } int main(int argc, char *argv[]) { - int64_t loadtzdbearly; - int i, gotsome, haveleft, ready = 1; + int i; + char **tls; + char **stack; + uint32_t *hostips; + // ShowCrashReports(); - ShowCrashReports(); - kprintf("welcome to greenbean\n"); - gmtime(&loadtzdbearly); + // listen for ctrl-c, hangup, and kill which shut down greenbean + status = ""; + struct sigaction sa = {.sa_handler = OnCtrlC}; + sigaction(SIGHUP, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGTERM, &sa, 0); - // spawn a bunch of threads - for (i = 0; i < THREADS; ++i) { - void *stack = mmap(0, 65536, PROT_READ | PROT_WRITE, - MAP_STACK | MAP_ANONYMOUS, -1, 0); - clone(Worker, stack, 65536, - CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(intptr_t)i, 0, 0, 0, 0); + // print all the ips that 0.0.0.0 will bind + for (hostips = GetHostIps(), i = 0; hostips[i]; ++i) { + kprintf("listening on http://%d.%d.%d.%d:%d\n", + (hostips[i] & 0xff000000) >> 030, (hostips[i] & 0x00ff0000) >> 020, + (hostips[i] & 0x0000ff00) >> 010, (hostips[i] & 0x000000ff) >> 000, + PORT); } - // wait for all threads to spawn - for (;;) { - __atomic_load(&workers, &gotsome, __ATOMIC_SEQ_CST); - if (workers == THREADS) break; - __builtin_ia32_pause(); - } - - // all threads are spawned so unleash the barrier - kprintf("\ngreenbean is ready to go\n"); - sigaction(SIGINT, &(struct sigaction){.sa_handler = OnCtrlC}, 0); - __atomic_store(&barrier, &ready, __ATOMIC_SEQ_CST); - - // main process does nothing until it's closing time - for (;;) { - __atomic_load(&workers, &haveleft, __ATOMIC_SEQ_CST); - if (!haveleft) break; - __builtin_ia32_pause(); - if (usleep(HEARTBEAT * 1000) == -1 && closingtime) { - kprintf("\rgreenbean is shutting down...\n"); + // spawn over 9,000 worker threads + tls = 0; + stack = 0; + threads = argc > 1 ? atoi(argv[1]) : GetCpuCount(); + if ((1 <= threads && threads <= INT_MAX) && + (tls = malloc(threads * sizeof(*tls))) && + (stack = malloc(threads * sizeof(*stack)))) { + for (i = 0; i < threads; ++i) { + if ((tls[i] = __initialize_tls(malloc(64))) && + (stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, + MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { + ++workers; + if (clone(Worker, stack[i], GetStackSize(), + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_SETTID | + CLONE_CHILD_CLEARTID, + (void *)(intptr_t)i, 0, tls[i], 64, + (int *)(tls[i] + 0x38)) == -1) { + --workers; + kprintf("error: clone(%d) failed %m\n", i); + } + } else { + kprintf("error: mmap(%d) failed %m\n", i); + } + if (!(i % 500)) { + PrintStatus(); + } } + } else { + kprintf("error: invalid number of threads\n"); } - kprintf("\n"); - kprintf("thank you for flying greenbean\n"); + // wait for workers to terminate + while (workers) { + PrintStatus(); + usleep(HEARTBEAT * 1000); + } + + // clean up terminal line + kprintf("\r\e[K"); + + // clean up memory + for (i = 0; i < threads; ++i) { + if (stack) munmap(stack[i], GetStackSize()); + if (tls) free(tls[i]); + } + free(hostips); + free(stack); + free(tls); } diff --git a/examples/touch.c b/examples/mkhello.c similarity index 70% rename from examples/touch.c rename to examples/mkhello.c index 58e179f44..c5448ae1a 100644 --- a/examples/touch.c +++ b/examples/mkhello.c @@ -8,22 +8,10 @@ ╚─────────────────────────────────────────────────────────────────*/ #endif #include "libc/calls/calls.h" -#include "libc/errno.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" - -/** - * @fileoverview Command for updating timestamps on files. - */ int main(int argc, char *argv[]) { - int i; - for (i = 1; i < argc; ++i) { - if (touch(argv[i], 0666) == -1) { - fprintf(stderr, "ERROR: %s: %s\n", argv[i], strerror(errno)); - exit(1); - } - } + creat("hello.txt", 0644); + write(3, "hello\n", 6); + close(3); return 0; } diff --git a/examples/echo.c b/examples/nomodifyself.c similarity index 58% rename from examples/echo.c rename to examples/nomodifyself.c index b1f757779..c3c5be75f 100644 --- a/examples/echo.c +++ b/examples/nomodifyself.c @@ -7,23 +7,30 @@ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif +#include "libc/dce.h" +#include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" -#include "libc/str/str.h" + +/** + * @fileoverview Non-Self-Modifying APE Binary Demo + * + * See examples/examples.mk for the build config, which uses the + * alternative APE runtime. + */ int main(int argc, char *argv[]) { - int i, j; - bool wantnewline; - if (argc > 1 && !strcmp(argv[1], "-n")) { - i = 2; - wantnewline = false; + if (_base[0] == 'M' && _base[1] == 'Z') { + printf("success: %s spawned without needing to modify its " + "executable header", + argv[0]); + if (!IsWindows()) { + printf(", thanks to APE loader!\n"); + } else { + printf(", because you ran it on Windows :P\n"); + } + return 0; } else { - i = 1; - wantnewline = true; + printf("error: %s doesn't have an MZ file header!\n", argv[0]); + return 1; } - for (j = 0; i + j < argc; ++j) { - if (j) fputc(' ', stdout); - fputs(argv[i + j], stdout); - } - if (wantnewline) fputc('\n', stdout); - return 0; } diff --git a/examples/package/build.mk b/examples/package/build.mk index fc604b2a2..acf3bf46b 100644 --- a/examples/package/build.mk +++ b/examples/package/build.mk @@ -60,7 +60,7 @@ o/$(MODE)/examples/package/%.com.dbg: \ $(EXAMPLES_PACKAGE_DEPS) \ o/$(MODE)/examples/package/%.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) # Invalidates objects in package when makefile is edited. diff --git a/examples/pyapp/pyapp.mk b/examples/pyapp/pyapp.mk index 298236fc6..49e88b386 100644 --- a/examples/pyapp/pyapp.mk +++ b/examples/pyapp/pyapp.mk @@ -95,7 +95,7 @@ o/$(MODE)/examples/pyapp/pyapp.com.dbg: \ o/$(MODE)/examples/pyapp/pyapp.pkg \ o/$(MODE)/examples/pyapp/pyapp.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) $(LINK) $(LINKARGS) -o $@ # # Unwrap the APE .COM binary, that's embedded within the linked file diff --git a/libc/atomic.h b/libc/atomic.h new file mode 100644 index 000000000..10e5925a9 --- /dev/null +++ b/libc/atomic.h @@ -0,0 +1,80 @@ +#ifndef COSMOPOLITAN_LIBC_ATOMIC_H_ +#define COSMOPOLITAN_LIBC_ATOMIC_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +/** + * @fileoverview C11 Atomic Types + * + * We supoprt C++ and old C compilers. It's recommended you use macros + * like `_Atomic(int)` rather than `_Atomic int` or `atomic_int` since + * we only define a portability macro for the syntax `_Atomic(T)`. + * + * @see libc/integral/c.inc + * @see libc/bits/atomic.h + */ + +#define atomic_bool _Atomic(_Bool) +#define atomic_bool32 atomic_int32 +#define atomic_char _Atomic(char) +#define atomic_schar _Atomic(signed char) +#define atomic_uchar _Atomic(unsigned char) +#define atomic_short _Atomic(short) +#define atomic_ushort _Atomic(unsigned short) +#define atomic_int _Atomic(int) +#define atomic_uint _Atomic(unsigned int) +#define atomic_long _Atomic(long) +#define atomic_ulong _Atomic(unsigned long) +#define atomic_llong _Atomic(long long) +#define atomic_ullong _Atomic(unsigned long long) +#define atomic_char16_t _Atomic(char16_t) +#define atomic_char32_t _Atomic(char32_t) +#define atomic_wchar_t _Atomic(wchar_t) +#define atomic_intptr_t _Atomic(intptr_t) +#define atomic_uintptr_t _Atomic(uintptr_t) +#define atomic_size_t _Atomic(size_t) +#define atomic_ptrdiff_t _Atomic(ptrdiff_t) +#define atomic_int_fast8_t _Atomic(int_fast8_t) +#define atomic_uint_fast8_t _Atomic(uint_fast8_t) +#define atomic_int_fast16_t _Atomic(int_fast16_t) +#define atomic_uint_fast16_t _Atomic(uint_fast16_t) +#define atomic_int_fast32_t _Atomic(int_fast32_t) +#define atomic_uint_fast32_t _Atomic(uint_fast32_t) +#define atomic_int_fast64_t _Atomic(int_fast64_t) +#define atomic_uint_fast64_t _Atomic(uint_fast64_t) +#define atomic_int_least8_t _Atomic(int_least8_t) +#define atomic_uint_least8_t _Atomic(uint_least8_t) +#define atomic_int_least16_t _Atomic(int_least16_t) +#define atomic_uint_least16_t _Atomic(uint_least16_t) +#define atomic_int_least32_t _Atomic(int_least32_t) +#define atomic_uint_least32_t _Atomic(uint_least32_t) +#define atomic_int_least64_t _Atomic(int_least64_t) +#define atomic_uint_least64_t _Atomic(uint_least64_t) + +#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE +#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE +#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE +#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE +#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE +#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE +#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE +#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE +#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE +#else +#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE +#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE +#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE +#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE +#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE +#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE +#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE +#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE +#endif + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_ATOMIC_H_ */ diff --git a/libc/bits/atomic.h b/libc/bits/atomic.h index e2d628adf..9d9b27ce0 100644 --- a/libc/bits/atomic.h +++ b/libc/bits/atomic.h @@ -1,18 +1,18 @@ #ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ #define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ -#include "libc/bits/bits.h" -#include "libc/intrin/lockcmpxchg.h" +#include "libc/atomic.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ /** - * @fileoverview C11 version of The Cosmopolitan Atomics Library. + * @fileoverview Cosmopolitan C11 Atomics Library * * - Forty-two different ways to say MOV. * - Fourteen different ways to say XCHG. * - Twenty different ways to say LOCK CMPXCHG. * - * Living proof high-level languages can be lower-level than assembly. + * It's a lower level programming language than assembly! + * + * @see libc/atomic.h */ #define memory_order int @@ -23,31 +23,148 @@ COSMOPOLITAN_C_START_ #define memory_order_acq_rel 4 #define memory_order_seq_cst 5 -#define atomic_flag struct AtomicFlag -#define atomic_flag_clear(PTR) atomic_store((PTR)->__cacheline, 0) -#define atomic_flag_test_and_set(PTR) \ - ({ \ - uint32_t ax = 0; \ - lockcmpxchg((PTR)->__cacheline, &ax, 1); \ +#define ATOMIC_VAR_INIT(value) (value) +#define atomic_is_lock_free(obj) ((void)(obj), sizeof(obj) <= sizeof(void *)) + +#define atomic_flag atomic_bool +#define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0) +#define atomic_flag_test_and_set_explicit(x, order) \ + atomic_exchange_explicit(x, 1, order) +#define atomic_flag_clear_explicit(x, order) atomic_store_explicit(x, 0, order) + +#define atomic_compare_exchange_strong(pObject, pExpected, desired) \ + atomic_compare_exchange_strong_explicit( \ + pObject, pExpected, desired, memory_order_seq_cst, memory_order_seq_cst) +#define atomic_compare_exchange_weak(pObject, pExpected, desired) \ + atomic_compare_exchange_weak_explicit( \ + pObject, pExpected, desired, memory_order_seq_cst, memory_order_seq_cst) +#define atomic_exchange(pObject, desired) \ + atomic_exchange_explicit(pObject, desired, memory_order_seq_cst) +#define atomic_fetch_add(pObject, operand) \ + atomic_fetch_add_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_fetch_and(pObject, operand) \ + atomic_fetch_and_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_fetch_or(pObject, operand) \ + atomic_fetch_or_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_fetch_sub(pObject, operand) \ + atomic_fetch_sub_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_fetch_xor(pObject, operand) \ + atomic_fetch_xor_explicit(pObject, operand, memory_order_seq_cst) +#define atomic_load(pObject) atomic_load_explicit(pObject, memory_order_seq_cst) +#define atomic_store(pObject, desired) \ + atomic_store_explicit(pObject, desired, memory_order_seq_cst) +#define atomic_flag_test_and_set(x) \ + atomic_flag_test_and_set_explicit(x, memory_order_seq_cst) +#define atomic_flag_clear(x) atomic_flag_clear_explicit(x, memory_order_seq_cst) + +#if defined(__CLANG_ATOMIC_BOOL_LOCK_FREE) + +#define atomic_init(obj, value) __c11_atomic_init(obj, value) +#define atomic_thread_fence(order) __c11_atomic_thread_fence(order) +#define atomic_signal_fence(order) __c11_atomic_signal_fence(order) +#define atomic_compare_exchange_strong_explicit(object, expected, desired, \ + success, failure) \ + __c11_atomic_compare_exchange_strong(object, expected, desired, success, \ + failure) +#define atomic_compare_exchange_weak_explicit(object, expected, desired, \ + success, failure) \ + __c11_atomic_compare_exchange_weak(object, expected, desired, success, \ + failure) +#define atomic_exchange_explicit(object, desired, order) \ + __c11_atomic_exchange(object, desired, order) +#define atomic_fetch_add_explicit(object, operand, order) \ + __c11_atomic_fetch_add(object, operand, order) +#define atomic_fetch_and_explicit(object, operand, order) \ + __c11_atomic_fetch_and(object, operand, order) +#define atomic_fetch_or_explicit(object, operand, order) \ + __c11_atomic_fetch_or(object, operand, order) +#define atomic_fetch_sub_explicit(object, operand, order) \ + __c11_atomic_fetch_sub(object, operand, order) +#define atomic_fetch_xor_explicit(object, operand, order) \ + __c11_atomic_fetch_xor(object, operand, order) +#define atomic_load_explicit(object, order) __c11_atomic_load(object, order) +#define atomic_store_explicit(object, desired, order) \ + __c11_atomic_store(object, desired, order) + +#elif (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 + +#define atomic_init(obj, value) ((void)(*(obj) = (value))) +#define atomic_thread_fence(order) __atomic_thread_fence(order) +#define atomic_signal_fence(order) __atomic_signal_fence(order) +#define atomic_compare_exchange_strong_explicit(pObject, pExpected, desired, \ + success, failure) \ + __atomic_compare_exchange_n(pObject, pExpected, desired, 0, success, failure) +#define atomic_compare_exchange_weak_explicit(pObject, pExpected, desired, \ + success, failure) \ + __atomic_compare_exchange_n(pObject, pExpected, desired, 1, success, failure) +#define atomic_exchange_explicit(pObject, desired, order) \ + __atomic_exchange_n(pObject, desired, order) +#define atomic_fetch_add_explicit(pObject, operand, order) \ + __atomic_fetch_add(pObject, operand, order) +#define atomic_fetch_and_explicit(pObject, operand, order) \ + __atomic_fetch_and(pObject, operand, order) +#define atomic_fetch_or_explicit(pObject, operand, order) \ + __atomic_fetch_or(pObject, operand, order) +#define atomic_fetch_sub_explicit(pObject, operand, order) \ + __atomic_fetch_sub(pObject, operand, order) +#define atomic_fetch_xor_explicit(pObject, operand, order) \ + __atomic_fetch_xor(pObject, operand, order) +#define atomic_load_explicit(pObject, order) __atomic_load_n(pObject, order) +#define atomic_store_explicit(pObject, desired, order) \ + __atomic_store_n(pObject, desired, order) + +#else + +#define atomic_init(obj, value) ((void)(*(obj) = (value))) +#define atomic_thread_fence(order) __sync_synchronize() +#define atomic_signal_fence(order) __asm__ volatile("" ::: "memory") +#define __atomic_apply_stride(object, operand) \ + (((__typeof__(__atomic_val(object)))0) + (operand)) +#define atomic_compare_exchange_strong_explicit(object, expected, desired, \ + success, failure) \ + __extension__({ \ + __typeof__(expected) __ep = (expected); \ + __typeof__(*__ep) __e = *__ep; \ + (void)(success); \ + (void)(failure); \ + (_Bool)((*__ep = __sync_val_compare_and_swap(object, __e, desired)) == \ + __e); \ }) -#define atomic_init(PTR, VAL) atomic_store(PTR, VAL) -#define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL)) -#define atomic_compare_exchange_strong(X, Y, Z) _lockcmpxchg(X, Y, Z) -#define atomic_compare_exchange_weak(X, Y, Z) _lockcmpxchg(X, Y, Z) -#define atomic_load_explicit(PTR, ORDER) atomic_load(PTR) -#define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL) -#define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0) -#define atomic_exchange_explicit(PTR, VAL, ORDER) lockxchg(PTR, &(VAL)) -#define atomic_flag_test_and_set_explicit(PTR, ORDER) lockcmpxchg(PTR, 0, 1) -#define atomic_compare_exchange_strong_explicit(X, Y, Z, S, F) \ - lockcmpxchg(X, Y, Z) -#define atomic_compare_exchange_weak_explicit(X, Y, Z, S, F) \ - lockcmpxchg(X, Y, Z) +#define atomic_compare_exchange_weak_explicit(object, expected, desired, \ + success, failure) \ + atomic_compare_exchange_strong_explicit(object, expected, desired, success, \ + failure) +#if __has_builtin(__sync_swap) +#define atomic_exchange_explicit(object, desired, order) \ + ((void)(order), __sync_swap(object, desired)) +#else +#define atomic_exchange_explicit(object, desired, order) \ + __extension__({ \ + __typeof__(object) __o = (object); \ + __typeof__(desired) __d = (desired); \ + (void)(order); \ + __sync_synchronize(); \ + __sync_lock_test_and_set(&__atomic_val(__o), __d); \ + }) +#endif +#define atomic_fetch_add_explicit(object, operand, order) \ + ((void)(order), \ + __sync_fetch_and_add(object, __atomic_apply_stride(object, operand))) +#define atomic_fetch_and_explicit(object, operand, order) \ + ((void)(order), __sync_fetch_and_and(object, operand)) +#define atomic_fetch_or_explicit(object, operand, order) \ + ((void)(order), __sync_fetch_and_or(object, operand)) +#define atomic_fetch_sub_explicit(object, operand, order) \ + ((void)(order), \ + __sync_fetch_and_sub(object, __atomic_apply_stride(object, operand))) +#define atomic_fetch_xor_explicit(object, operand, order) \ + ((void)(order), __sync_fetch_and_xor(object, operand)) +#define atomic_load_explicit(object, order) \ + ((void)(order), __sync_fetch_and_add(object, 0)) +#define atomic_store_explicit(object, desired, order) \ + ((void)atomic_exchange_explicit(object, desired, order)) -struct AtomicFlag { - uint32_t __cacheline[16]; /* Intel V.O §9.4.6 */ -} forcealign(64); +#endif -COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ */ diff --git a/libc/stdio/unlocked/fflush_unlocked.S b/libc/calls/__clock_gettime.S similarity index 85% rename from libc/stdio/unlocked/fflush_unlocked.S rename to libc/calls/__clock_gettime.S index c91963f1c..3e5d052c9 100644 --- a/libc/stdio/unlocked/fflush_unlocked.S +++ b/libc/calls/__clock_gettime.S @@ -1,7 +1,7 @@ /*-*- 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 │ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -18,12 +18,13 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" -// Blocks until data from stream buffer is written out. -// -// @param rdi is the stream handle -// @return 0 on success or -1 w/ errno -// @see fflush_unlocked() -fflush: mov %rdi,%r11 - ezlea fflush_unlocked,ax - jmp stdio_unlock - .endfn fflush,globl + .initbss 201,_init___clock_gettime +__clock_gettime: + .quad 0 + .endobj __clock_gettime,globl,hidden + .previous + + .init.start 201,_init___clock_gettime + ezlea __clock_gettime_init,ax + stosq + .init.end 201,_init___clock_gettime diff --git a/libc/calls/asan.internal.h b/libc/calls/asan.internal.h new file mode 100644 index 000000000..e73bbd39c --- /dev/null +++ b/libc/calls/asan.internal.h @@ -0,0 +1,19 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ +#include "libc/bits/asmflag.h" +#include "libc/calls/struct/timespec.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +forceinline bool __asan_is_valid_timespec(const struct timespec *ts) { + bool zf; + asm(ZFLAG_ASM("cmpw\t$0,0x7fff8000(%1)") + : ZFLAG_CONSTRAINT(zf) + : "r"((intptr_t)ts >> 3) + : "memory"); + return zf; +} + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ */ diff --git a/libc/calls/calls.h b/libc/calls/calls.h index 5d29a9a98..455136d21 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -130,18 +130,18 @@ int geteuid(void) nosideeffect; int getgid(void) nosideeffect; int gethostname(char *, size_t); int getloadavg(double *, int); -int getpgid(int); +int getpgid(int) nosideeffect libcesque; int getpgrp(void) nosideeffect; -int getpid(void); +int getpid(void) nosideeffect libcesque; int getppid(void); int getpriority(int, unsigned); int getresgid(uint32_t *, uint32_t *, uint32_t *); int getresuid(uint32_t *, uint32_t *, uint32_t *); int getrlimit(int, struct rlimit *); int getrusage(int, struct rusage *); -int getsid(int) nosideeffect; -int gettid(void); -int getuid(void) nosideeffect; +int getsid(int) nosideeffect libcesque; +int gettid(void) libcesque; +int getuid(void) nosideeffect libcesque; int kill(int, int); int killpg(int, int); int link(const char *, const char *) dontthrow; diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index c5cf3aadd..cceeec7e3 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.mk @@ -65,20 +65,39 @@ $(LIBC_CALLS_A).pkg: \ $(LIBC_CALLS_A_OBJS) \ $(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/libc/calls/vdsofunc.greg.o \ -o/$(MODE)/libc/calls/directmap.o \ -o/$(MODE)/libc/calls/directmap-nt.o \ -o/$(MODE)/libc/calls/mapstack.greg.o \ -o/$(MODE)/libc/calls/getcwd.greg.o \ -o/$(MODE)/libc/calls/getcwd-xnu.greg.o \ -o/$(MODE)/libc/calls/getprogramexecutablename.greg.o \ -o/$(MODE)/libc/calls/raise.o: \ +# we can't use asan because: +# ucontext_t memory is owned by xnu kernel +o/$(MODE)/libc/calls/sigenter-xnu.o: \ OVERRIDE_COPTS += \ -ffreestanding \ - $(NO_MAGIC) + -fno-sanitize=address -o/$(MODE)/libc/calls/termios2linux.o \ -o/$(MODE)/libc/calls/termios2host.o \ +# we can't use asan because: +# vdso memory is owned by linux kernel +o/$(MODE)/libc/calls/vdsofunc.greg.o: \ + OVERRIDE_COPTS += \ + -ffreestanding \ + -fno-sanitize=address + +# we can't use asan because: +# asan guard pages haven't been allocated yet +o/$(MODE)/libc/calls/directmap.o \ +o/$(MODE)/libc/calls/directmap-nt.o: \ + OVERRIDE_COPTS += \ + -ffreestanding \ + -fno-sanitize=address + +# we can't use asan because: +# ntspawn allocates 128kb of heap memory via win32 +o/$(MODE)/libc/calls/ntspawn.o \ +o/$(MODE)/libc/calls/mkntcmdline.o \ +o/$(MODE)/libc/calls/mkntenvblock.o: \ + OVERRIDE_COPTS += \ + -ffreestanding \ + -fno-sanitize=address + +# we always want -O3 because: +# it makes the code size smaller too o/$(MODE)/libc/calls/sigenter-freebsd.o \ o/$(MODE)/libc/calls/sigenter-netbsd.o \ o/$(MODE)/libc/calls/sigenter-openbsd.o \ @@ -87,7 +106,43 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: \ OVERRIDE_COPTS += \ -O3 -# TODO(jart): make va_arg optimize well in default mode +# we must disable static stack safety because: +# these functions use alloca(n) +o/$(MODE)/libc/calls/execl.o \ +o/$(MODE)/libc/calls/execle.o \ +o/$(MODE)/libc/calls/execlp.o \ +o/$(MODE)/libc/calls/execve-sysv.o \ +o/$(MODE)/libc/calls/execve-nt.greg.o \ +o/$(MODE)/libc/calls/mkntenvblock.o: \ + OVERRIDE_CPPFLAGS += \ + -DSTACK_FRAME_UNLIMITED + +# we must disable static stack safety because: +# PATH_MAX*sizeof(char16_t)*2 exceeds 4096 byte frame limit +o/$(MODE)/libc/calls/copyfile.o \ +o/$(MODE)/libc/calls/symlinkat-nt.o \ +o/$(MODE)/libc/calls/readlinkat-nt.o \ +o/$(MODE)/libc/calls/linkat-nt.o \ +o/$(MODE)/libc/calls/renameat-nt.o: \ + OVERRIDE_CPPFLAGS += \ + -DSTACK_FRAME_UNLIMITED + +# we must segregate codegen because: +# file contains multiple independently linkable apis +o/$(MODE)/libc/calls/ioctl-siocgifconf.o \ +o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: \ + OVERRIDE_COPTS += \ + -ffunction-sections \ + -fdata-sections + +# we want small code size because: +# to keep .text.head under 4096 bytes +o/$(MODE)/libc/calls/mman.greg.o: \ + OVERRIDE_COPTS += \ + -Os + +# we always want -Os because: +# va_arg codegen is very bloated in default mode o//libc/calls/open.o \ o//libc/calls/openat.o \ o//libc/calls/prctl.o \ @@ -109,27 +164,6 @@ o//libc/calls/fcntl.o: \ OVERRIDE_CFLAGS += \ -Os -# must use alloca() or path_max*2*2 -o/$(MODE)/libc/calls/execl.o \ -o/$(MODE)/libc/calls/execle.o \ -o/$(MODE)/libc/calls/execlp.o \ -o/$(MODE)/libc/calls/copyfile.o \ -o/$(MODE)/libc/calls/execve-nt.o \ -o/$(MODE)/libc/calls/linkat-nt.o \ -o/$(MODE)/libc/calls/renameat-nt.o \ -o/$(MODE)/libc/calls/execve-sysv.o \ -o/$(MODE)/libc/calls/symlinkat-nt.o \ -o/$(MODE)/libc/calls/readlinkat-nt.o \ -o/$(MODE)/libc/calls/mkntenvblock.o: \ - OVERRIDE_CPPFLAGS += \ - -DSTACK_FRAME_UNLIMITED - -o/$(MODE)/libc/calls/ioctl-siocgifconf.o \ -o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: \ - OVERRIDE_COPTS += \ - -ffunction-sections \ - -fdata-sections - LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x))) LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS)) LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/calls/chdir-nt.c b/libc/calls/chdir-nt.c index 65c027ce5..75a3e0ad0 100644 --- a/libc/calls/chdir-nt.c +++ b/libc/calls/chdir-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/errno.h" #include "libc/macros.internal.h" #include "libc/nt/errors.h" diff --git a/libc/calls/chdir.c b/libc/calls/chdir.c index 0b42d5a95..8afec0deb 100644 --- a/libc/calls/chdir.c +++ b/libc/calls/chdir.c @@ -16,8 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/chroot.c b/libc/calls/chroot.c index 2f654f7a4..0ea2f439e 100644 --- a/libc/calls/chroot.c +++ b/libc/calls/chroot.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Changes root directory. diff --git a/libc/calls/clock_gettime-nt.c b/libc/calls/clock_gettime-nt.c index 2d7ecef12..50dcb25de 100644 --- a/libc/calls/clock_gettime-nt.c +++ b/libc/calls/clock_gettime-nt.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/fmt/conv.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nt/synchronization.h" @@ -28,6 +27,7 @@ textwindows int sys_clock_gettime_nt(int clockid, struct timespec *ts) { struct timespec res; struct NtFileTime ft; static struct timespec mono; + if (!ts) return efault(); if (clockid == CLOCK_REALTIME) { GetSystemTimeAsFileTime(&ft); *ts = FileTimeToTimeSpec(ft); diff --git a/libc/calls/clock_gettime-xnu.c b/libc/calls/clock_gettime-xnu.c new file mode 100644 index 000000000..3b911f9c2 --- /dev/null +++ b/libc/calls/clock_gettime-xnu.c @@ -0,0 +1,35 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" + +int sys_clock_gettime_xnu(int clockid, struct timespec *ts) { + axdx_t ad; + ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); + if (ad.ax != -1) { + if (ad.ax) { + ts->tv_sec = ad.ax; + ts->tv_nsec = ad.dx; + } + ts->tv_nsec *= 1000; + return 0; + } else { + return -1; + } +} diff --git a/libc/calls/clock_gettime.c b/libc/calls/clock_gettime.c index f7deab6e6..254273c63 100644 --- a/libc/calls/clock_gettime.c +++ b/libc/calls/clock_gettime.c @@ -17,18 +17,23 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/asmflag.h" +#include "libc/bits/bits.h" +#include "libc/calls/asan.internal.h" +#include "libc/calls/clock_gettime.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/timeval.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/fmt/conv.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" +#include "libc/mem/alloca.h" #include "libc/nt/synchronization.h" #include "libc/sysv/errfuns.h" -static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; - /** * Returns nanosecond time. * @@ -36,6 +41,13 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; * time. Among the more popular is CLOCK_MONOTONIC. This function has a * zero syscall implementation of that on modern x86. * + * nowl l: 45𝑐 15𝑛𝑠 + * rdtsc l: 13𝑐 4𝑛𝑠 + * gettimeofday l: 44𝑐 14𝑛𝑠 + * clock_gettime l: 40𝑐 13𝑛𝑠 + * __clock_gettime l: 35𝑐 11𝑛𝑠 + * sys_clock_gettime l: 220𝑐 71𝑛𝑠 + * * @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc. * @param ts is where the result is stored * @return 0 on success, or -1 w/ errno @@ -44,54 +56,49 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; * @asyncsignalsafe */ noinstrument int clock_gettime(int clockid, struct timespec *ts) { - int rc, e; - axdx_t ad; - char buf[45]; - if (!ts) { + int rc; + char *buf; + if (IsAsan() && !__asan_is_valid_timespec(ts)) { rc = efault(); - } else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) { - rc = efault(); - } else if (clockid == -1) { - rc = einval(); - } else if (!IsWindows()) { - e = errno; - if ((rc = __clock_gettime(clockid, ts))) { - errno = e; - ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); - assert(ad.ax != -1); - if (SupportsXnu() && ad.ax) { - ts->tv_sec = ad.ax; - ts->tv_nsec = ad.dx; - } - ts->tv_nsec *= 1000; - rc = 0; - } } else { - rc = sys_clock_gettime_nt(clockid, ts); + rc = __clock_gettime(clockid, ts); } +#if SYSDEBUG if (!__time_critical) { + buf = alloca(45); STRACE("clock_gettime(%d, [%s]) → %d% m", clockid, - DescribeTimespec(buf, sizeof(buf), rc, ts), rc); + DescribeTimespec(buf, 45, rc, ts), rc); } +#endif return rc; } /** - * Returns fast system clock_gettime() if it exists. + * Returns pointer to fastest clock_gettime(). */ -void *__get_clock_gettime(void) { - void *vdso; - static bool once; - static void *result; - if (!once) { - if ((vdso = __vdsofunc("__vdso_clock_gettime"))) { - __clock_gettime = result = vdso; - } - once = true; +clock_gettime_f *__clock_gettime_get(bool *opt_out_isfast) { + bool isfast; + clock_gettime_f *res; + if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_clock_gettime"))) { + isfast = true; + } else if (IsXnu()) { + isfast = false; + res = sys_clock_gettime_xnu; + } else if (IsWindows()) { + isfast = true; + res = sys_clock_gettime_nt; + } else { + isfast = false; + res = sys_clock_gettime; } - return result; + if (opt_out_isfast) { + *opt_out_isfast = isfast; + } + return res; } -const void *const __clock_gettime_ctor[] initarray = { - __get_clock_gettime, -}; +hidden int __clock_gettime_init(int clockid, struct timespec *ts) { + clock_gettime_f *gettime; + __clock_gettime = gettime = __clock_gettime_get(0); + return gettime(clockid, ts); +} diff --git a/libc/calls/clock_gettime.h b/libc/calls/clock_gettime.h new file mode 100644 index 000000000..e6afedd45 --- /dev/null +++ b/libc/calls/clock_gettime.h @@ -0,0 +1,15 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ +#define COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ +#include "libc/calls/struct/timespec.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +typedef int clock_gettime_f(int, struct timespec *); + +extern clock_gettime_f *__clock_gettime; +hidden clock_gettime_f __clock_gettime_init; +hidden clock_gettime_f *__clock_gettime_get(bool *); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ */ diff --git a/libc/calls/close-nt.c b/libc/calls/close-nt.c index a6270628a..ef9bfe2fd 100644 --- a/libc/calls/close-nt.c +++ b/libc/calls/close-nt.c @@ -21,7 +21,6 @@ #include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" -#include "libc/sock/ntstdin.internal.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" @@ -42,12 +41,7 @@ textwindows int sys_close_nt(struct Fd *fd) { // if this file descriptor is wrapped in a named pipe worker thread // then we need to close our copy of the worker thread handle. it's // also required that whatever install a worker use malloc, so free - if (fd->worker) { - if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false; - fd->worker = 0; - } else { - if (!CloseHandle(fd->handle)) ok = false; - } + if (!CloseHandle(fd->handle)) ok = false; if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) { if (!CloseHandle(fd->extra)) ok = false; } diff --git a/libc/calls/close.c b/libc/calls/close.c index 13cfe7b21..1a241f007 100644 --- a/libc/calls/close.c +++ b/libc/calls/close.c @@ -17,11 +17,13 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" -#include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" -#include "libc/macros.internal.h" -#include "libc/sock/internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/intrin/spinlock.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" #include "libc/zipos/zipos.internal.h" @@ -46,6 +48,7 @@ */ int close(int fd) { int rc; + _spinlock(&__fds_lock); if (fd == -1) { rc = 0; } else if (fd < 0) { @@ -74,9 +77,10 @@ int close(int fd) { } } if (!__vforked) { - __releasefd(fd); + __releasefd_unlocked(fd); } } + _spunlock(&__fds_lock); STRACE("%s(%d) → %d% m", "close", fd, rc); return rc; } diff --git a/libc/calls/copyfile.c b/libc/calls/copyfile.c index 270532537..31cd2422f 100644 --- a/libc/calls/copyfile.c +++ b/libc/calls/copyfile.c @@ -16,9 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" #include "libc/calls/copyfile.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/intrin/kprintf.h" #include "libc/nt/createfile.h" diff --git a/test/libc/time/nowl_test.c b/libc/calls/describesigaltstack.greg.c similarity index 73% rename from test/libc/time/nowl_test.c rename to libc/calls/describesigaltstack.greg.c index a09d77df7..dbfc830cb 100644 --- a/test/libc/time/nowl_test.c +++ b/libc/calls/describesigaltstack.greg.c @@ -16,24 +16,22 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/struct/timespec.h" -#include "libc/nexgen32e/rdtscp.h" -#include "libc/sysv/consts/clock.h" -#include "libc/testlib/ezbench.h" -#include "libc/testlib/testlib.h" -#include "libc/time/time.h" +#include "libc/calls/struct/sigaltstack.h" +#include "libc/dce.h" +#include "libc/intrin/asan.internal.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/kprintf.h" -TEST(nowl, testIsMonotonic) { - long double a = nowl(); - long double b = nowl(); - EXPECT_TRUE(b > a); -} - -BENCH(nowl, bench) { - volatile int64_t c; - volatile long double x; - volatile struct timespec ts; - EZBENCH2("rdtsc", donothing, c = rdtsc()); - EZBENCH2("nowl", donothing, x = nowl()); - EZBENCH2("clock_gettime", donothing, clock_gettime(CLOCK_MONOTONIC, &ts)); +const char *DescribeSigaltstk(char *buf, size_t bufsize, int rc, + const struct sigaltstack *ss) { + if (rc == -1) return "n/a"; + if (!ss) return "NULL"; + if ((!IsAsan() && kisdangerous(ss)) || + (IsAsan() && !__asan_is_valid(ss, sizeof(*ss)))) { + ksnprintf(buf, sizeof(buf), "%p", ss); + } else { + ksnprintf(buf, bufsize, "{.ss_sp=%p, .ss_flags=%#lx, .ss_size=%'zu}", + ss->ss_sp, ss->ss_flags, ss->ss_size); + } + return buf; } diff --git a/libc/calls/directmap-nt.c b/libc/calls/directmap-nt.c index e8f015ede..fb4921776 100644 --- a/libc/calls/directmap-nt.c +++ b/libc/calls/directmap-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/intrin/kprintf.h" #include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/pageflags.h" diff --git a/libc/calls/directmap.c b/libc/calls/directmap.c index 7c8a12d6d..502f0fbd4 100644 --- a/libc/calls/directmap.c +++ b/libc/calls/directmap.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/errno.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/runtime.h" diff --git a/libc/calls/dup-nt.c b/libc/calls/dup-nt.c index ba52b9e20..8e5894427 100644 --- a/libc/calls/dup-nt.c +++ b/libc/calls/dup-nt.c @@ -20,11 +20,13 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/mem/mem.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" #include "libc/sock/internal.h" -#include "libc/sock/ntstdin.internal.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" @@ -32,39 +34,49 @@ * Implements dup(), dup2(), dup3(), and F_DUPFD for Windows. */ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) { - int64_t proc, handle; + int64_t rc, proc, handle; // validate the api usage if (oldfd < 0) return einval(); if (flags & ~O_CLOEXEC) return einval(); + + _spinlock(&__fds_lock); + if (oldfd >= g_fds.n || (g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket && g_fds.p[oldfd].kind != kFdConsole)) { + _spunlock(&__fds_lock); return ebadf(); } // allocate a new file descriptor - if (newfd == -1) { - if ((newfd = __reservefd(start)) == -1) { - return -1; + for (;;) { + if (newfd == -1) { + if ((newfd = __reservefd_unlocked(start)) == -1) { + _spunlock(&__fds_lock); + return -1; + } + break; + } else { + if (__ensurefds_unlocked(newfd) == -1) { + _spunlock(&__fds_lock); + return -1; + } + if (g_fds.p[newfd].kind) { + _spunlock(&__fds_lock); + close(newfd); + _spinlock(&__fds_lock); + } + if (!g_fds.p[newfd].kind) { + g_fds.p[newfd].kind = kFdReserved; + break; + } } - } else { - if (__ensurefds(newfd) == -1) return -1; - if (g_fds.p[newfd].kind) close(newfd); - g_fds.p[newfd].kind = kFdReserved; - } - - // if this file descriptor is wrapped in a named pipe worker thread - // then we should clone the original authentic handle rather than the - // stdin worker's named pipe. we won't clone the worker, since that - // can always be recreated again on demand. - if (g_fds.p[oldfd].worker) { - handle = g_fds.p[oldfd].worker->reader; - } else { - handle = g_fds.p[oldfd].handle; } + handle = g_fds.p[oldfd].handle; proc = GetCurrentProcess(); + if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, true, kNtDuplicateSameAccess)) { g_fds.p[newfd].kind = g_fds.p[oldfd].kind; @@ -77,12 +89,12 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) { } else { g_fds.p[newfd].extra = g_fds.p[oldfd].extra; } - if (g_fds.p[oldfd].worker) { - g_fds.p[newfd].worker = weaken(RefNtStdinWorker)(g_fds.p[oldfd].worker); - } - return newfd; + rc = newfd; } else { - __releasefd(newfd); - return __winerr(); + __releasefd_unlocked(newfd); + rc = __winerr(); } + + _spunlock(&__fds_lock); + return rc; } diff --git a/libc/calls/dup.c b/libc/calls/dup.c index 84ce876ee..4bcea1e12 100644 --- a/libc/calls/dup.c +++ b/libc/calls/dup.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/dup2.c b/libc/calls/dup2.c index ab8b79449..bb78e74dd 100644 --- a/libc/calls/dup2.c +++ b/libc/calls/dup2.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/dup3-sysv.c b/libc/calls/dup3-sysv.c index ec9f64650..2bbea134c 100644 --- a/libc/calls/dup3-sysv.c +++ b/libc/calls/dup3-sysv.c @@ -16,8 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/errno.h" int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) { diff --git a/libc/calls/dup3.c b/libc/calls/dup3.c index f19dccab9..05128a0a5 100644 --- a/libc/calls/dup3.c +++ b/libc/calls/dup3.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/execve-nt.c b/libc/calls/execve-nt.greg.c similarity index 54% rename from libc/calls/execve-nt.c rename to libc/calls/execve-nt.greg.c index c45128e8c..4bb7c8794 100644 --- a/libc/calls/execve-nt.c +++ b/libc/calls/execve-nt.greg.c @@ -16,44 +16,112 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#define ShouldUseMsabiAttribute() 1 +#include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/ntspawn.h" +#include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/mem/alloca.h" #include "libc/nt/accounting.h" +#include "libc/nt/console.h" #include "libc/nt/enum/startf.h" #include "libc/nt/enum/status.h" +#include "libc/nt/memory.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/processinformation.h" #include "libc/nt/struct/startupinfo.h" #include "libc/nt/synchronization.h" +#include "libc/nt/thunk/msabi.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" +#include "libc/sysv/consts/at.h" +#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/ok.h" +#include "libc/sysv/errfuns.h" + +__msabi extern typeof(CloseHandle) *const __imp_CloseHandle; +__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject; +__msabi extern typeof(GetExitCodeProcess) *const __imp_GetExitCodeProcess; +__msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile; + +static noinstrument __msabi bool32 +BlockExecveConsoleEvent(uint32_t dwCtrlType) { + // block SIGINT and SIGQUIT in execve() parent process + return true; +} textwindows int sys_execve_nt(const char *program, char *const argv[], char *const envp[]) { int rc; size_t i; uint32_t dwExitCode; + char progbuf[PATH_MAX]; + struct MemoryIntervals *mm; struct NtStartupInfo startinfo; struct NtProcessInformation procinfo; + + if (strlen(program) + 4 + 1 > PATH_MAX) { + return enametoolong(); + } + + // this is a non-recoverable operation, so do some manual validation + if (sys_faccessat_nt(AT_FDCWD, program, X_OK, 0) == -1) { + stpcpy(stpcpy(progbuf, program), ".com"); + if (sys_faccessat_nt(AT_FDCWD, progbuf, X_OK, 0) != -1) { + program = progbuf; + } else { + stpcpy(stpcpy(progbuf, program), ".exe"); + if (sys_faccessat_nt(AT_FDCWD, progbuf, X_OK, 0) != -1) { + program = progbuf; + } else { + return eacces(); + } + } + } + + ////////////////////////////////////////////////////////////////////////////// + // execve operation is unrecoverable from this point + + // close cloexec handles + for (i = 3; i < g_fds.n; ++i) { + if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) { + __imp_CloseHandle(g_fds.p[i].handle); + } + } + bzero(&startinfo, sizeof(startinfo)); startinfo.cb = sizeof(struct NtStartupInfo); startinfo.dwFlags = kNtStartfUsestdhandles; startinfo.hStdInput = __getfdhandleactual(0); startinfo.hStdOutput = __getfdhandleactual(1); startinfo.hStdError = __getfdhandleactual(2); + + // spawn the process rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo); - if (rc == -1) return -1; - CloseHandle(g_fds.p[0].handle); - CloseHandle(g_fds.p[1].handle); - CloseHandle(procinfo.hThread); + if (rc == -1) { + STRACE("panic: unrecoverable ntspawn(%#s) error: %m", program); + __imp_ExitProcess(6543); + } + + ////////////////////////////////////////////////////////////////////////////// + // zombie shell process remains, to wait for child and propagate its exit + // code + + __imp_CloseHandle(g_fds.p[0].handle); + __imp_CloseHandle(g_fds.p[1].handle); + __imp_CloseHandle(procinfo.hThread); + __imp_SetConsoleCtrlHandler((void *)BlockExecveConsoleEvent, 1); do { - WaitForSingleObject(procinfo.hProcess, -1); + __imp_WaitForSingleObject(procinfo.hProcess, -1); dwExitCode = kNtStillActive; - GetExitCodeProcess(procinfo.hProcess, &dwExitCode); + __imp_GetExitCodeProcess(procinfo.hProcess, &dwExitCode); } while (dwExitCode == kNtStillActive); - CloseHandle(procinfo.hProcess); - _Exit(dwExitCode); + __imp_CloseHandle(procinfo.hProcess); + __imp_ExitProcess(dwExitCode); + unreachable; } diff --git a/libc/calls/execve-sysv.c b/libc/calls/execve-sysv.c index 60c4f5189..bcf848537 100644 --- a/libc/calls/execve-sysv.c +++ b/libc/calls/execve-sysv.c @@ -16,28 +16,80 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/errno.h" #include "libc/mem/alloca.h" #include "libc/paths.h" +#include "libc/runtime/runtime.h" #include "libc/str/str.h" +#include "libc/sysv/consts/at.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/ok.h" +#include "libc/sysv/errfuns.h" + +static bool CanExecute(const char *path) { + return !sys_faccessat(AT_FDCWD, path, X_OK, 0); +} + +static bool IsApeBinary(const char *path) { + int fd; + char buf[8]; + bool res = false; + if ((fd = sys_open(path, O_RDONLY, 0)) != -1) { + if (sys_read(fd, buf, 8) == 8 && READ64LE(buf) == READ64LE("MZqFpD='")) { + res = true; + } + sys_close(fd); + } + return res; +} + +static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) { + size_t n, m; + n = strlen(a); + m = strlen(b); + if (n + 1 + m + 1 < PATH_MAX) { + stpcpy(stpcpy(stpcpy(buf, a), "/"), b); + return buf; + } else { + return ""; + } +} int sys_execve(const char *prog, char *const argv[], char *const envp[]) { + int e; size_t i; + char *buf; char **shargs; + const char *ape; + e = errno; __sys_execve(prog, argv, envp); if (errno != ENOEXEC) return -1; for (i = 0; argv[i];) ++i; - shargs = alloca((i + 2) * sizeof(char *)); - memcpy(shargs + 2, argv + 1, i * sizeof(char *)); - if (IsFreebsd() || IsNetbsd()) { - shargs[0] = firstnonnull(commandv("bash", alloca(PATH_MAX), PATH_MAX), - _PATH_BSHELL); + buf = alloca(PATH_MAX); + shargs = alloca((i + 4) * sizeof(char *)); + if (IsApeBinary(prog) && + (CanExecute((ape = "/usr/bin/ape")) || + CanExecute( + (ape = Join(firstnonnull(getenv("TMPDIR"), "/tmp"), "ape", buf))))) { + shargs[0] = ape; + shargs[1] = "-"; + shargs[2] = prog; + memcpy(shargs + 3, argv, (i + 1) * sizeof(char *)); + } else if (CanExecute(prog)) { + if (IsFreebsd() || IsNetbsd()) { + shargs[0] = firstnonnull(commandv("bash", buf, PATH_MAX), _PATH_BSHELL); + } else { + shargs[0] = _PATH_BSHELL; + } + shargs[1] = prog; + memcpy(shargs + 2, argv + 1, i * sizeof(char *)); } else { - shargs[0] = _PATH_BSHELL; + return enoexec(); } - shargs[1] = prog; + errno = e; return __sys_execve(shargs[0], shargs, envp); } diff --git a/libc/calls/execve.c b/libc/calls/execve.c index 9df027a14..df59f26fa 100644 --- a/libc/calls/execve.c +++ b/libc/calls/execve.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/kprintf.h" @@ -63,11 +64,6 @@ int execve(const char *prog, char *const argv[], char *const envp[]) { kprintf("})\n"); } #endif - for (i = 3; i < g_fds.n; ++i) { - if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) { - close(i); - } - } if (!IsWindows()) { rc = sys_execve(prog, argv, envp); } else { diff --git a/libc/calls/faccessat-nt.c b/libc/calls/faccessat-nt.c index 2630da0fb..96b717084 100644 --- a/libc/calls/faccessat-nt.c +++ b/libc/calls/faccessat-nt.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/sysv/consts/at.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/faccessat.c b/libc/calls/faccessat.c index 2e602e121..e682d4f83 100644 --- a/libc/calls/faccessat.c +++ b/libc/calls/faccessat.c @@ -18,8 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" diff --git a/libc/calls/fadvise-nt.c b/libc/calls/fadvise-nt.c index 82d818be8..9c8cae641 100644 --- a/libc/calls/fadvise-nt.c +++ b/libc/calls/fadvise-nt.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/enum/filesharemode.h" diff --git a/libc/calls/fadvise.c b/libc/calls/fadvise.c index 31044b604..31425e4f7 100644 --- a/libc/calls/fadvise.c +++ b/libc/calls/fadvise.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/fchdir-nt.c b/libc/calls/fchdir-nt.c index ab8db742c..f01d804b3 100644 --- a/libc/calls/fchdir-nt.c +++ b/libc/calls/fchdir-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/nt/files.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/fchdir.c b/libc/calls/fchdir.c index 614a7fb57..83f7ad7d2 100644 --- a/libc/calls/fchdir.c +++ b/libc/calls/fchdir.c @@ -17,7 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/fchmod.c b/libc/calls/fchmod.c index 39baf82e0..27996c8fb 100644 --- a/libc/calls/fchmod.c +++ b/libc/calls/fchmod.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/fchmodat-nt.c b/libc/calls/fchmodat-nt.c index 7b0ba5f7c..ee9966a9f 100644 --- a/libc/calls/fchmodat-nt.c +++ b/libc/calls/fchmodat-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/files.h" diff --git a/libc/calls/fchmodat.c b/libc/calls/fchmodat.c index f8b617442..5ea267d00 100644 --- a/libc/calls/fchmodat.c +++ b/libc/calls/fchmodat.c @@ -18,8 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" diff --git a/libc/calls/fchown.c b/libc/calls/fchown.c index 6f7f5f1c5..f447de5fe 100644 --- a/libc/calls/fchown.c +++ b/libc/calls/fchown.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/sysv/consts/at.h" /** diff --git a/libc/calls/fchownat.c b/libc/calls/fchownat.c index cec5ab92b..bf743aa5c 100644 --- a/libc/calls/fchownat.c +++ b/libc/calls/fchownat.c @@ -18,8 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" diff --git a/libc/calls/fcntl-nt.c b/libc/calls/fcntl-nt.c index d51cdc0a9..3eaf7fb6a 100644 --- a/libc/calls/fcntl-nt.c +++ b/libc/calls/fcntl-nt.c @@ -19,6 +19,8 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/flock.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/cmpxchg.h" #include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" diff --git a/libc/calls/fcntl-sysv.c b/libc/calls/fcntl-sysv.c index 0e9a04ff2..9e9bca098 100644 --- a/libc/calls/fcntl-sysv.c +++ b/libc/calls/fcntl-sysv.c @@ -16,8 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/struct/flock.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/sysv/consts/f.h" int sys_fcntl(int fd, int cmd, uintptr_t arg) { diff --git a/libc/calls/fcntl.c b/libc/calls/fcntl.c index 44d469619..b87653c85 100644 --- a/libc/calls/fcntl.c +++ b/libc/calls/fcntl.c @@ -20,6 +20,8 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/sysv/errfuns.h" #include "libc/zipos/zipos.internal.h" diff --git a/libc/calls/fdatasync.c b/libc/calls/fdatasync.c index 2f63c4281..c2c12dd81 100644 --- a/libc/calls/fdatasync.c +++ b/libc/calls/fdatasync.c @@ -17,24 +17,32 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" +#include "libc/runtime/runtime.h" /** * Blocks until kernel flushes non-metadata buffers for fd to disk. * * @return 0 on success, or -1 w/ errno - * @see fsync(), sync_file_range() + * @see sync(), fsync(), sync_file_range() + * @see __nosync to secretly disable * @asyncsignalsafe */ int fdatasync(int fd) { int rc; - if (!IsWindows()) { - rc = sys_fdatasync(fd); + if (__nosync != 0x5453455454534146) { + if (!IsWindows()) { + rc = sys_fdatasync(fd); + } else { + rc = sys_fdatasync_nt(fd); + } + STRACE("fdatasync(%d) → %d% m", fd, rc); } else { - rc = sys_fdatasync_nt(fd); + rc = 0; + STRACE("fdatasync(%d) → disabled% m", fd); } - STRACE("%s(%d) → %d% m", "fdatasync", fd, rc); return rc; } diff --git a/libc/calls/fileexists.c b/libc/calls/fileexists.c index 876a1cac9..f5301a8fb 100644 --- a/libc/calls/fileexists.c +++ b/libc/calls/fileexists.c @@ -18,10 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/metastat.internal.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/calls/fixenotdir.c b/libc/calls/fixenotdir.c index 8b982fca4..5b9146b38 100644 --- a/libc/calls/fixenotdir.c +++ b/libc/calls/fixenotdir.c @@ -16,11 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/errno.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/errors.h" #include "libc/nt/files.h" +#include "libc/str/str.h" static textwindows bool SubpathExistsThatsNotDirectory(char16_t *path) { int e; diff --git a/libc/calls/fixupnewfd.c b/libc/calls/fixupnewfd.c index c7a65c920..93911893a 100644 --- a/libc/calls/fixupnewfd.c +++ b/libc/calls/fixupnewfd.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/fd.h" #include "libc/sysv/consts/o.h" diff --git a/libc/calls/flock-nt.c b/libc/calls/flock-nt.c index 85a9a879d..764905d20 100644 --- a/libc/calls/flock-nt.c +++ b/libc/calls/flock-nt.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/byhandlefileinformation.h" diff --git a/libc/calls/flock.c b/libc/calls/flock.c index b48232f7e..2f0afbdb3 100644 --- a/libc/calls/flock.c +++ b/libc/calls/flock.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/fstat-nt.c b/libc/calls/fstat-nt.c index 125ef8e09..c869fb6d9 100644 --- a/libc/calls/fstat-nt.c +++ b/libc/calls/fstat-nt.c @@ -17,9 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/fmt/conv.h" #include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" diff --git a/libc/calls/fstat-sysv.c b/libc/calls/fstat-sysv.c index e05714552..22c4cd7f7 100644 --- a/libc/calls/fstat-sysv.c +++ b/libc/calls/fstat-sysv.c @@ -17,6 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/metastat.internal.h" +#include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/fstatat-nt.c b/libc/calls/fstatat-nt.c index 468752e70..853744b91 100644 --- a/libc/calls/fstatat-nt.c +++ b/libc/calls/fstatat-nt.c @@ -17,6 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/stat.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/creationdisposition.h" diff --git a/libc/calls/fstatat-sysv.c b/libc/calls/fstatat-sysv.c index 4c64f3986..45a9f78f3 100644 --- a/libc/calls/fstatat-sysv.c +++ b/libc/calls/fstatat-sysv.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" #include "libc/calls/struct/metastat.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/fstatat.c b/libc/calls/fstatat.c index 0a13947a1..b59ca4639 100644 --- a/libc/calls/fstatat.c +++ b/libc/calls/fstatat.c @@ -19,6 +19,7 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/errno.h" diff --git a/libc/calls/fsync.c b/libc/calls/fsync.c index 99b6286ec..859c858f6 100644 --- a/libc/calls/fsync.c +++ b/libc/calls/fsync.c @@ -17,24 +17,32 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" +#include "libc/runtime/runtime.h" /** * Blocks until kernel flushes buffers for fd to disk. * * @return 0 on success, or -1 w/ errno * @see fdatasync(), sync_file_range() + * @see __nosync to secretly disable * @asyncsignalsafe */ int fsync(int fd) { int rc; - if (!IsWindows()) { - rc = sys_fsync(fd); + if (__nosync != 0x5453455454534146) { + if (!IsWindows()) { + rc = sys_fsync(fd); + } else { + rc = sys_fdatasync_nt(fd); + } + STRACE("fysnc(%d) → %d% m", fd, rc); } else { - rc = sys_fdatasync_nt(fd); + rc = 0; + STRACE("fsync(%d) → disabled% m", fd); } - STRACE("%s(%d) → %d% m", "fsync", fd, rc); return rc; } diff --git a/libc/calls/ftruncate-nt.c b/libc/calls/ftruncate-nt.c index 9c1e79288..46574efa2 100644 --- a/libc/calls/ftruncate-nt.c +++ b/libc/calls/ftruncate-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/enum/filemovemethod.h" #include "libc/nt/files.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/ftruncate.c b/libc/calls/ftruncate.c index 5c17d5780..109c7b2f6 100644 --- a/libc/calls/ftruncate.c +++ b/libc/calls/ftruncate.c @@ -19,6 +19,8 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/g_sighandrvas.c b/libc/calls/g_sighandrvas.c index 97964a95d..e1da914a5 100644 --- a/libc/calls/g_sighandrvas.c +++ b/libc/calls/g_sighandrvas.c @@ -16,8 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" -_Alignas(64) char __sig_lock; +_Alignas(64) int __sig_lock; unsigned __sighandrvas[NSIG]; unsigned __sighandflags[NSIG]; diff --git a/libc/calls/getcwd-nt.c b/libc/calls/getcwd-nt.c index 475824679..3982ef5cb 100644 --- a/libc/calls/getcwd-nt.c +++ b/libc/calls/getcwd-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/macros.internal.h" #include "libc/nt/files.h" #include "libc/str/str.h" @@ -32,14 +32,21 @@ textwindows char *sys_getcwd_nt(char *buf, size_t size) { if ((n = GetCurrentDirectory(ARRAYLEN(p), p))) { if (4 + n + 1 <= size && 4 + n + 1 <= ARRAYLEN(p)) { tprecode16to8(buf, size, p); + i = 0; j = 0; if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') { + // turn c:\... into \c\... + p[1] = p[0]; + p[0] = '\\'; + } else if (n >= 7 && p[0] == '\\' && p[1] == '\\' && p[2] == '?' && + p[3] == '\\' && isalpha(p[4]) && p[5] == ':' && p[6] == '\\') { + // turn \\?\c:\... into \c\... buf[j++] = '/'; + buf[j++] = p[4]; buf[j++] = '/'; - buf[j++] = '?'; - buf[j++] = '/'; + i += 7; } - for (i = 0; i < n;) { + while (i < n) { x = p[i++] & 0xffff; if (!IsUcs2(x)) { if (i < n) { diff --git a/libc/calls/getcwd-xnu.greg.c b/libc/calls/getcwd-xnu.greg.c index 63bfac438..7d3cb5b19 100644 --- a/libc/calls/getcwd-xnu.greg.c +++ b/libc/calls/getcwd-xnu.greg.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/struct/metastat.internal.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/at.h" #include "libc/sysv/consts/o.h" diff --git a/libc/calls/getcwd.greg.c b/libc/calls/getcwd.greg.c index 158185a56..52dacfbe3 100644 --- a/libc/calls/getcwd.greg.c +++ b/libc/calls/getcwd.greg.c @@ -19,8 +19,10 @@ #include "libc/assert.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/log/backtrace.internal.h" #include "libc/mem/mem.h" diff --git a/libc/calls/getdomainname.c b/libc/calls/getdomainname.c index 87dd1d748..691d08b7d 100644 --- a/libc/calls/getdomainname.c +++ b/libc/calls/getdomainname.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/utsname.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/macros.internal.h" #include "libc/nt/enum/computernameformat.h" diff --git a/libc/calls/getegid.c b/libc/calls/getegid.c index e142d34f1..e4516baca 100644 --- a/libc/calls/getegid.c +++ b/libc/calls/getegid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/geteuid.c b/libc/calls/geteuid.c index ad16d7419..4db32a100 100644 --- a/libc/calls/geteuid.c +++ b/libc/calls/geteuid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Returns effective user ID of calling process. diff --git a/libc/calls/getfiledescriptorsize.c b/libc/calls/getfiledescriptorsize.c index 045e3ecd0..8011608cd 100644 --- a/libc/calls/getfiledescriptorsize.c +++ b/libc/calls/getfiledescriptorsize.c @@ -22,6 +22,7 @@ #include "libc/calls/strace.internal.h" #include "libc/calls/struct/metastat.internal.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/limits.h" #include "libc/nt/enum/fileinfobyhandleclass.h" diff --git a/libc/calls/getfilesize.c b/libc/calls/getfilesize.c index 8ef96630c..69da98ad1 100644 --- a/libc/calls/getfilesize.c +++ b/libc/calls/getfilesize.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/stat.h" #include "libc/dce.h" #include "libc/limits.h" diff --git a/libc/calls/gethostname-linux.c b/libc/calls/gethostname-linux.c index fac5b9b9c..979cfb6e2 100644 --- a/libc/calls/gethostname-linux.c +++ b/libc/calls/gethostname-linux.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/utsname.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/gethostname-nt.c b/libc/calls/gethostname-nt.c index 2cdf8c0f6..906d29980 100644 --- a/libc/calls/gethostname-nt.c +++ b/libc/calls/gethostname-nt.c @@ -17,7 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/macros.internal.h" #include "libc/nt/enum/computernameformat.h" #include "libc/nt/systeminfo.h" #include "libc/str/str.h" diff --git a/libc/calls/gethostname.c b/libc/calls/gethostname.c index eaafb2b43..743525483 100644 --- a/libc/calls/gethostname.c +++ b/libc/calls/gethostname.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/nt/enum/computernameformat.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/getitimer.c b/libc/calls/getitimer.c index 57b8937a9..0467eb522 100644 --- a/libc/calls/getitimer.c +++ b/libc/calls/getitimer.c @@ -19,6 +19,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/struct/itimerval.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/getntsyspath.S b/libc/calls/getntsyspath.S index f4969bcf4..d3e4466fb 100644 --- a/libc/calls/getntsyspath.S +++ b/libc/calls/getntsyspath.S @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" #include "libc/macros.internal.h" // Obtains WIN32 magic path, e.g. GetTempPathA. @@ -33,7 +34,13 @@ __getntsyspath: movpp %rdi,%rcx # call f=%rax(p1=%rcx,p2=%rdx) sub $40,%rsp call *%rax - xor %edx,%edx + testb IsWindows() + jz 3f + mov (%rdi),%cl # turn c:\... into \c\... + movb $'\\',(%rdi) + mov %cl,1(%rdi) + movb $'\\',2(%rdi) +3: xor %edx,%edx mov -8(%rbp),%ecx # restore %edx param as %ecx cmp %eax,%ecx # use current dir on overflow cmovbe %edx,%eax diff --git a/libc/calls/getpgid.c b/libc/calls/getpgid.c index 8ae485a7e..a072d98c1 100644 --- a/libc/calls/getpgid.c +++ b/libc/calls/getpgid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/getpgrp.c b/libc/calls/getpgrp.c index 9a15d1c6e..d083b42c3 100644 --- a/libc/calls/getpgrp.c +++ b/libc/calls/getpgrp.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/getppid-nt.c b/libc/calls/getppid-nt.c index b6f7c0d5a..0410b704a 100644 --- a/libc/calls/getppid-nt.c +++ b/libc/calls/getppid-nt.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/nt/nt/process.h" #include "libc/nt/ntdll.h" diff --git a/libc/calls/getppid.c b/libc/calls/getppid.c index d997f6134..2d6c24133 100644 --- a/libc/calls/getppid.c +++ b/libc/calls/getppid.c @@ -16,8 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Returns parent process id. diff --git a/libc/calls/getpriority-nt.c b/libc/calls/getpriority-nt.c index 3f89a9401..5bd4a2b98 100644 --- a/libc/calls/getpriority-nt.c +++ b/libc/calls/getpriority-nt.c @@ -16,20 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/bits.h" -#include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/kntprioritycombos.internal.h" -#include "libc/fmt/conv.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nexgen32e/ffs.h" -#include "libc/nt/enum/processcreationflags.h" -#include "libc/nt/enum/threadpriority.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" #include "libc/nt/thread.h" #include "libc/runtime/runtime.h" -#include "libc/sysv/consts/prio.h" -#include "libc/sysv/errfuns.h" textwindows int sys_getpriority_nt(int ignored) { size_t i; diff --git a/libc/calls/getpriority.c b/libc/calls/getpriority.c index 6a65f48d1..fb7a61967 100644 --- a/libc/calls/getpriority.c +++ b/libc/calls/getpriority.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Returns nice value of thing. diff --git a/libc/calls/getprocaddressmodule.c b/libc/calls/getprocaddressmodule.c index cba122484..f45c39471 100644 --- a/libc/calls/getprocaddressmodule.c +++ b/libc/calls/getprocaddressmodule.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/nt/dll.h" /** diff --git a/libc/calls/getprogramexecutablename.greg.c b/libc/calls/getprogramexecutablename.greg.c index f3ecbab09..7a516ebb8 100644 --- a/libc/calls/getprogramexecutablename.greg.c +++ b/libc/calls/getprogramexecutablename.greg.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/macros.internal.h" @@ -34,34 +34,52 @@ char program_executable_name[PATH_MAX]; +static inline int IsAlpha(int c) { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); +} + +static inline char *StrCat(char buf[PATH_MAX], const char *a, const char *b) { + char *p, *e; + p = buf; + e = buf + PATH_MAX; + while (*a && p < e) *p++ = *a++; + while (*b && p < e) *p++ = *b++; + return buf; +} + static inline void GetProgramExecutableNameImpl(char *p, char *e) { char *q; ssize_t rc; size_t i, n; union { int cmd[4]; + char path[PATH_MAX]; char16_t path16[PATH_MAX]; } u; if (IsWindows()) { n = GetModuleFileName(0, u.path16, ARRAYLEN(u.path16)); for (i = 0; i < n; ++i) { + // turn c:\foo\bar into c:/foo/bar if (u.path16[i] == '\\') { u.path16[i] = '/'; } } - if (isalpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') { - p[0] = '/'; - p[1] = '/'; - p[2] = '?'; - p[3] = '/'; - p += 4; + if (IsAlpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') { + // turn c:/... into /c/... + u.path16[1] = u.path16[0]; + u.path16[0] = '/'; + u.path16[2] = '/'; } tprecode16to8(p, e - p, u.path16); return; } - if (__argc && (q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) { + // if argv[0] exists then turn it into an absolute path. we also try + // adding a .com suffix since the ape auto-appends it when resolving + if (__argc && (((q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) || + ((q = StrCat(u.path, __argv[0], ".com")) && + !sys_faccessat(AT_FDCWD, q, F_OK, 0)))) { if (*q != '/') { if (q[0] == '.' && q[1] == '/') { q += 2; @@ -78,12 +96,12 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) { return; } + // if argv[0] doesn't exist, then fallback to interpreter name if ((rc = sys_readlinkat(AT_FDCWD, "/proc/self/exe", p, e - p - 1)) > 0 || (rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, e - p - 1)) > 0) { p[rc] = 0; return; } - if (IsFreebsd() || IsNetbsd()) { u.cmd[0] = CTL_KERN; u.cmd[1] = KERN_PROC; @@ -101,7 +119,7 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) { } /** - * Returns absolute path of executable. + * Returns absolute path of program. */ char *GetProgramExecutableName(void) { int e; diff --git a/libc/calls/getresgid.c b/libc/calls/getresgid.c index 1760de051..36aa25dd8 100644 --- a/libc/calls/getresgid.c +++ b/libc/calls/getresgid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/getresuid.c b/libc/calls/getresuid.c index 80a0f10a7..d67c4c28a 100644 --- a/libc/calls/getresuid.c +++ b/libc/calls/getresuid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/getrusage-nt.c b/libc/calls/getrusage-nt.c index 35bb44e50..8c4fa79c8 100644 --- a/libc/calls/getrusage-nt.c +++ b/libc/calls/getrusage-nt.c @@ -17,9 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/struct/rusage.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/fmt/conv.h" #include "libc/intrin/spinlock.h" #include "libc/nt/accounting.h" diff --git a/libc/calls/getsid.c b/libc/calls/getsid.c index 1d199e2b0..057aeb54e 100644 --- a/libc/calls/getsid.c +++ b/libc/calls/getsid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Creates session and sets the process group id. diff --git a/libc/calls/gettimeofday-nt.c b/libc/calls/gettimeofday-nt.c index cf113f721..8b808db05 100644 --- a/libc/calls/gettimeofday-nt.c +++ b/libc/calls/gettimeofday-nt.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/struct/timeval.h" #include "libc/fmt/conv.h" #include "libc/nt/struct/filetime.h" diff --git a/libc/calls/gettimeofday.c b/libc/calls/gettimeofday.c index 927e785a4..5b129ec60 100644 --- a/libc/calls/gettimeofday.c +++ b/libc/calls/gettimeofday.c @@ -19,6 +19,7 @@ #include "libc/assert.h" #include "libc/calls/internal.h" #include "libc/calls/struct/timeval.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/errfuns.h" @@ -58,7 +59,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) { static textstartup void __gettimeofday_init(void) { void *vdso; - if ((vdso = __vdsofunc("__vdso_gettimeofday"))) { + if ((vdso = __vdsosym("LINUX_2.6", "__vdso_gettimeofday"))) { __gettimeofday = vdso; } } diff --git a/libc/calls/getuid.c b/libc/calls/getuid.c index 4c0d49be4..4136a304e 100644 --- a/libc/calls/getuid.c +++ b/libc/calls/getuid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/macros.internal.h" #include "libc/nt/accounting.h" diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 8ec7a418c..84d6cb098 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -1,7 +1,6 @@ #ifndef COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ #define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/itimerval.h" #include "libc/calls/struct/metastat.internal.h" @@ -62,34 +61,31 @@ struct Fd { unsigned mode; int64_t handle; int64_t extra; - struct NtStdinWorker *worker; bool zombie; }; struct Fds { - size_t f; /* lowest free slot */ + int f; /* lowest free slot */ size_t n; /* monotonic capacity */ struct Fd *p; struct Fd __init_p[OPEN_MAX]; }; -extern const struct Fd kEmptyFd; - -hidden extern int __vforked; -hidden extern char __fds_lock; -hidden extern char __sig_lock; -hidden extern bool __time_critical; -hidden extern unsigned __sighandrvas[NSIG]; -hidden extern unsigned __sighandflags[NSIG]; hidden extern struct Fds g_fds; -hidden extern const struct NtSecurityAttributes kNtIsInheritable; +hidden extern const struct Fd kEmptyFd; int __reservefd(int) hidden; +int __reservefd_unlocked(int) hidden; void __releasefd(int) hidden; +void __releasefd_unlocked(int) hidden; int __ensurefds(int) hidden; -int64_t __getfdhandleactual(int) hidden; +int __ensurefds_unlocked(int) hidden; void __printfds(void) hidden; +forceinline int64_t __getfdhandleactual(int fd) { + return g_fds.p[fd].handle; +} + forceinline bool __isfdopen(int fd) { return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty; } @@ -116,253 +112,79 @@ forceinline size_t _clampio(size_t size) { │ cosmopolitan § syscalls » system five » synthetic jump slots ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -axdx_t __sys_pipe(i32[hasatleast 2], i32) hidden; -axdx_t sys_fork(void) hidden; -axdx_t sys_getpid(void) hidden; axdx_t sys_gettimeofday(struct timeval *, struct timezone *, void *) hidden; -char *sys_getcwd(char *, u64) hidden; -char *sys_getcwd_xnu(char *, u64) hidden; -i32 __sys_dup3(i32, i32, i32) hidden; -i32 __sys_execve(const char *, char *const[], char *const[]) hidden; -i32 __sys_fcntl(i32, i32, ...) hidden; -i32 __sys_fstat(i32, void *) hidden; -i32 __sys_fstatat(i32, const char *, void *, i32) hidden; i32 __sys_getrusage(i32, struct rusage *) hidden; -i32 __sys_munmap(void *, u64) hidden; -i32 __sys_openat(i32, const char *, i32, u32) hidden; -i32 __sys_pipe2(i32[hasatleast 2], u32) hidden; i32 __sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden; i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden; i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden; -i32 sys_chdir(const char *) hidden; -i32 sys_chroot(const char *) hidden; i32 sys_clock_gettime(i32, struct timespec *) hidden; -i32 sys_close(i32) hidden; -i32 sys_dup(i32) hidden; -i32 sys_dup2(i32, i32) hidden; -i32 sys_dup3(i32, i32, i32) hidden; -i32 sys_execve(const char *, char *const[], char *const[]) hidden; -i32 sys_faccessat(i32, const char *, i32, u32) hidden; -i32 sys_fadvise(i32, i64, i64, i32) hidden; -i32 sys_fchdir(i32) hidden; -i32 sys_fchmod(i32, u32) hidden; -i32 sys_fchmodat(i32, const char *, u32, u32) hidden; -i32 sys_fchown(i64, u32, u32) hidden; -i32 sys_fchownat(i32, const char *, u32, u32, u32) hidden; -i32 sys_fcntl(i32, i32, u64) hidden; -i32 sys_fdatasync(i32) hidden; -i32 sys_flock(i32, i32) hidden; +i32 sys_clock_gettime_xnu(i32, struct timespec *) hidden; i32 sys_fstat(i32, struct stat *) hidden; i32 sys_fstatat(i32, const char *, struct stat *, i32) hidden; -i32 sys_fsync(i32) hidden; -i32 sys_ftruncate(i32, i64, i64) hidden; i32 sys_futimes(i32, const struct timeval *) hidden; i32 sys_futimesat(i32, const char *, const struct timeval *) hidden; -i32 sys_getcontext(void *) hidden; i32 sys_getitimer(i32, struct itimerval *) hidden; -i32 sys_getpgid(i32) hidden; -i32 sys_getpgrp(void) hidden; -i32 sys_getppid(void) hidden; -i32 sys_getpriority(i32, u32) hidden; -i32 sys_getresgid(u32 *, u32 *, u32 *); -i32 sys_getresuid(u32 *, u32 *, u32 *); i32 sys_getrlimit(i32, struct rlimit *) hidden; i32 sys_getrusage(i32, struct rusage *) hidden; -i32 sys_getsid(int) hidden; -i32 sys_ioctl(i32, u64, ...) hidden; -i32 sys_kill(i32, i32, i32) hidden; -i32 sys_linkat(i32, const char *, i32, const char *, i32) hidden; -i32 sys_lseek(i32, i64, i64, i64) hidden; i32 sys_lutimes(const char *, const struct timeval *) hidden; -i32 sys_madvise(void *, size_t, i32) hidden; -i32 sys_memfd_create(const char *, u32) hidden; -i32 sys_mincore(void *, u64, unsigned char *) hidden; -i32 sys_mkdirat(i32, const char *, u32) hidden; -i32 sys_mkfifo(const char *, u32) hidden; -i32 sys_mknod(const char *, u32, u64) hidden; -i32 sys_mprotect(void *, u64, i32) hidden; -i32 sys_msync(void *, u64, i32) hidden; -i32 sys_munmap(void *, u64) hidden; i32 sys_nanosleep(const struct timespec *, struct timespec *) hidden; -i32 sys_openat(i32, const char *, i32, u32) hidden; -i32 sys_pause(void) hidden; -i32 sys_pipe(i32[hasatleast 2]) hidden; -i32 sys_pipe2(i32[hasatleast 2], u32) hidden; -i32 sys_pledge(const char *, const char *) hidden; -i32 sys_posix_openpt(i32) hidden; -i32 sys_renameat(i32, const char *, i32, const char *) hidden; -i32 sys_sched_setaffinity(i32, u64, const void *) hidden; -i32 sys_sched_yield(void) hidden; -i32 sys_setgid(i32) hidden; i32 sys_setitimer(i32, const struct itimerval *, struct itimerval *) hidden; -i32 sys_setpgid(i32, i32) hidden; -i32 sys_setpriority(i32, u32, i32) hidden; -i32 sys_setregid(u32, u32) hidden; -i32 sys_setresgid(u32, u32, u32) hidden; -i32 sys_setresuid(u32, u32, u32) hidden; -i32 sys_setreuid(u32, u32) hidden; i32 sys_setrlimit(i32, const struct rlimit *) hidden; -i32 sys_setsid(void) hidden; -i32 sys_setuid(i32) hidden; -i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden; -i32 sys_sigaltstack(const void *, void *) hidden; i32 sys_sigprocmask(i32, const sigset *, sigset *) hidden; i32 sys_sigqueue(i32, i32, const union sigval) hidden; i32 sys_sigqueueinfo(i32, const siginfo_t *) hidden; i32 sys_sigsuspend(const sigset *, u64) hidden; -i32 sys_symlinkat(const char *, i32, const char *) hidden; -i32 sys_sync(void) hidden; -i32 sys_sync_file_range(i32, i64, i64, u32) hidden; i32 sys_sysinfo(struct sysinfo *) hidden; -i32 sys_tgkill(i32, i32, i32) hidden; -i32 sys_tkill(i32, i32, void *) hidden; -i32 sys_truncate(const char *, u64, u64) hidden; -i32 sys_uname(char *) hidden; -i32 sys_unlinkat(i32, const char *, i32) hidden; i32 sys_utime(const char *, const struct utimbuf *) hidden; i32 sys_utimensat(i32, const char *, const struct timespec *, i32) hidden; i32 sys_utimes(const char *, const struct timeval *) hidden; i32 sys_wait4(i32, i32 *, i32, struct rusage *) hidden; -i64 sys_copy_file_range(i32, long *, i32, long *, u64, u32) hidden; -i64 sys_getrandom(void *, u64, u32) hidden; -i64 sys_pread(i32, void *, u64, i64, i64) hidden; i64 sys_preadv(i32, struct iovec *, i32, i64, i64) hidden; -i64 sys_ptrace(int, i32, void *, void *) hidden; -i64 sys_pwrite(i32, const void *, u64, i64, i64) hidden; i64 sys_pwritev(i32, const struct iovec *, i32, i64, i64) hidden; -i64 sys_read(i32, void *, u64) hidden; -i64 sys_readlink(const char *, char *, u64) hidden; -i64 sys_readlinkat(int, const char *, char *, u64) hidden; -i64 sys_sched_getaffinity(i32, u64, void *) hidden; -i64 sys_sendfile(i32, i32, i64 *, u64) hidden; -i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden; i64 sys_vmsplice(i32, const struct iovec *, i64, u32) hidden; -i64 sys_write(i32, const void *, u64) hidden; -u32 sys_getegid(void) hidden; -u32 sys_geteuid(void) hidden; -u32 sys_getgid(void) hidden; -u32 sys_gettid(void) hidden; -u32 sys_getuid(void) hidden; -u32 sys_umask(u32) hidden; -void *__sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden; -void *sys_mremap(void *, u64, u64, i32, void *) hidden; -void sys_exit(int) hidden; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § syscalls » system five » support ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -void __onfork(void) hidden; -void *__vdsofunc(const char *) hidden; -void *__get_clock_gettime(void) hidden; -i32 __fixupnewfd(i32, i32) hidden; -void __restore_rt() hidden; -int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden; int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden; -void __stat2cosmo(struct stat *restrict, const union metastat *) hidden; -void __restore_rt_netbsd(void) hidden; +int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden; +size_t __iovec_size(const struct iovec *, size_t) hidden; +ssize_t WritevUninterruptible(int, struct iovec *, int); +void __rusage2linux(struct rusage *) hidden; void __sigenter_xnu(void *, i32, i32, struct siginfo_xnu *, struct __darwin_ucontext *) hidden; -int gethostname_linux(char *, size_t) hidden; -int gethostname_bsd(char *, size_t) hidden; -int gethostname_nt(char *, size_t, int) hidden; -size_t __iovec_size(const struct iovec *, size_t) hidden; -void __rusage2linux(struct rusage *) hidden; -int __notziposat(int, const char *); -ssize_t WritevUninterruptible(int, struct iovec *, int); -void flock2cosmo(uintptr_t); -void cosmo2flock(uintptr_t); - -int sys_sendfile_xnu(int32_t infd, int32_t outfd, int64_t offset, - int64_t *out_opt_sbytes, const void *opt_hdtr, - int32_t flags) asm("sys_sendfile") hidden; -int sys_sendfile_freebsd(int32_t infd, int32_t outfd, int64_t offset, - size_t nbytes, const void *opt_hdtr, - int64_t *out_opt_sbytes, - int32_t flags) asm("sys_sendfile") hidden; +void __stat2cosmo(struct stat *restrict, const union metastat *) hidden; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -bool32 sys_isatty_nt(int) hidden; -char *sys_getcwd_nt(char *, size_t) hidden; -i64 sys_lseek_nt(int, i64, int) hidden; -int sys_chdir_nt(const char *) hidden; -int sys_close_epoll_nt(int) hidden; +int ioctl_tiocgwinsz_nt(struct Fd *, struct winsize *) hidden; int sys_close_nt(struct Fd *) hidden; -int sys_dup_nt(int, int, int, int) hidden; -int sys_execve_nt(const char *, char *const[], char *const[]) hidden; -int sys_faccessat_nt(int, const char *, int, uint32_t) hidden; -int sys_fadvise_nt(int, u64, u64, int) hidden; -int sys_fchdir_nt(int) hidden; -int sys_fchmodat_nt(int, const char *, uint32_t, int) hidden; -int sys_fcntl_nt(int, int, uintptr_t) hidden; -int sys_fdatasync_nt(int) hidden; -int sys_flock_nt(int, int) hidden; -int sys_fork_nt(void) hidden; int sys_fstat_nt(i64, struct stat *) hidden; int sys_fstatat_nt(int, const char *, struct stat *, int) hidden; -int sys_ftruncate_nt(i64, u64) hidden; -int sys_getppid_nt(void) hidden; -int sys_getpriority_nt(int) hidden; int sys_getrusage_nt(int, struct rusage *) hidden; int sys_gettimeofday_nt(struct timeval *, struct timezone *) hidden; -int sys_kill_nt(int, int) hidden; -int sys_linkat_nt(int, const char *, int, const char *) hidden; int sys_lstat_nt(const char *, struct stat *) hidden; -int sys_madvise_nt(void *, size_t, int) hidden; -int sys_mkdirat_nt(int, const char *, uint32_t) hidden; -int sys_msync_nt(char *, size_t, int) hidden; int sys_nanosleep_nt(const struct timespec *, struct timespec *) hidden; -int sys_pipe_nt(int[hasatleast 2], unsigned) hidden; -int sys_renameat_nt(int, const char *, int, const char *) hidden; -int sys_sched_yield_nt(void) hidden; int sys_setitimer_nt(int, const struct itimerval *, struct itimerval *) hidden; -int sys_setpriority_nt(int) hidden; -int sys_symlinkat_nt(const char *, int, const char *) hidden; -int sys_sync_nt(void) hidden; -int sys_sysinfo_nt(struct sysinfo *) hidden; -int sys_truncate_nt(const char *, u64) hidden; -int sys_unlinkat_nt(int, const char *, int) hidden; int sys_setrlimit_nt(int, const struct rlimit *) hidden; +int sys_sysinfo_nt(struct sysinfo *) hidden; int sys_utimensat_nt(int, const char *, const struct timespec *, int) hidden; int sys_utimes_nt(const char *, const struct timeval[2]) hidden; -ssize_t sys_open_nt(int, const char *, u32, i32) dontdiscard hidden; ssize_t sys_read_nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden; -ssize_t sys_readlinkat_nt(int, const char *, char *, size_t) hidden; ssize_t sys_write_nt(int, const struct iovec *, size_t, ssize_t) hidden; -int ioctl_tiocgwinsz_nt(struct Fd *, struct winsize *) hidden; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § syscalls » windows nt » support ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -bool __is_linux_2_6_23(void) hidden; -int64_t __fix_enotdir(int64_t, char16_t *) hidden; -int64_t __fix_enotdir3(int64_t, char16_t *, char16_t *) hidden; bool _check_interrupts(bool, struct Fd *) hidden; -void _check_sigchld(void) hidden; -void _check_sigalrm(void) hidden; -int __sample_pids(int[hasatleast 64], int64_t[hasatleast 64], bool) hidden; -bool isdirectory_nt(const char *) hidden; -bool isregularfile_nt(const char *) hidden; -bool issymlink_nt(const char *) hidden; -bool32 ntsetprivilege(i64, const char16_t *, u32) hidden; -char16_t *CreatePipeName(char16_t *) hidden; -int __mkntpath(const char *, char16_t[hasatleast PATH_MAX]) hidden; -int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX], int) hidden; -int __mkntpathat(int, const char *, int, char16_t[hasatleast PATH_MAX]) hidden; int sys_clock_gettime_nt(int, struct timespec *) hidden; -int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden; -int sys_getsetpriority_nt(int, int, int, int (*)(int)); -int64_t __winerr(void) nocallback privileged; -int64_t ntreturn(uint32_t); ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int) hidden; ssize_t sys_writev_nt(int, const struct iovec *, int) hidden; unsigned __wincrash_nt(struct NtExceptionPointers *); -void *GetProcAddressModule(const char *, const char *) hidden; -void WinMainForked(void) hidden; void _ntcontext2linux(struct ucontext *, const struct NtContext *) hidden; void _ntlinux2context(struct NtContext *, const ucontext_t *) hidden; struct NtOverlapped *_offset2overlap(int64_t, int64_t, diff --git a/libc/calls/interrupts-nt.c b/libc/calls/interrupts-nt.c index a77b28bfd..458f5a93a 100644 --- a/libc/calls/interrupts-nt.c +++ b/libc/calls/interrupts-nt.c @@ -18,16 +18,46 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/bits/weaken.h" +#include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigaction.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" +#include "libc/intrin/lockcmpxchgp.h" +#include "libc/nexgen32e/threaded.h" + +_Alignas(64) static int rlock; + +// return 0 on success, or tid of other owner +static privileged inline int AcquireInterruptPollLock(void) { + // any thread can poll for interrupts + // but it's wasteful to have every single thread doing it + int me, owner = 0; + if (__threaded) { + me = gettid(); + if (!_lockcmpxchgp(&rlock, &owner, me) && owner == me) { + owner = 0; + } + } + return owner; +} + +static textwindows inline void ReleaseInterruptPollLock(void) { + int zero = 0; + __atomic_store(&rlock, &zero, __ATOMIC_RELAXED); +} textwindows bool _check_interrupts(bool restartable, struct Fd *fd) { + bool res; if (__time_critical) return false; + if (AcquireInterruptPollLock()) return false; if (weaken(_check_sigalrm)) weaken(_check_sigalrm)(); if (weaken(_check_sigchld)) weaken(_check_sigchld)(); if (fd && weaken(_check_sigwinch)) weaken(_check_sigwinch)(fd); - return weaken(__sig_check) && weaken(__sig_check)(restartable); + res = weaken(__sig_check) && weaken(__sig_check)(restartable); + ReleaseInterruptPollLock(); + return res; } diff --git a/libc/calls/ioctl_default.c b/libc/calls/ioctl_default.c index 11886fb1a..9df7412fa 100644 --- a/libc/calls/ioctl_default.c +++ b/libc/calls/ioctl_default.c @@ -19,6 +19,8 @@ #include "libc/bits/weaken.h" #include "libc/calls/internal.h" #include "libc/calls/ioctl.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/dce.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/ioctl_fioclex.c b/libc/calls/ioctl_fioclex.c index 8c0de779c..9eca2f40a 100644 --- a/libc/calls/ioctl_fioclex.c +++ b/libc/calls/ioctl_fioclex.c @@ -19,6 +19,7 @@ #include "libc/calls/internal.h" #include "libc/calls/ioctl.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/ioctl_siocgifconf-nt.c b/libc/calls/ioctl_siocgifconf-nt.c index d693df24c..05ef547a0 100644 --- a/libc/calls/ioctl_siocgifconf-nt.c +++ b/libc/calls/ioctl_siocgifconf-nt.c @@ -19,7 +19,6 @@ #include "libc/assert.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/intrin/cmpxchg.h" #include "libc/nt/errors.h" #include "libc/nt/iphlpapi.h" diff --git a/libc/calls/ioctl_siocgifconf.c b/libc/calls/ioctl_siocgifconf.c index 4f395736c..d9752d391 100644 --- a/libc/calls/ioctl_siocgifconf.c +++ b/libc/calls/ioctl_siocgifconf.c @@ -19,9 +19,10 @@ #include "libc/assert.h" #include "libc/bits/bits.h" #include "libc/bits/weaken.h" -#include "libc/calls/internal.h" #include "libc/calls/ioctl.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/mem/mem.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/str/str.h" diff --git a/libc/calls/ioctl_tcgets.c b/libc/calls/ioctl_tcgets.c index 14860ee24..2a27d4987 100644 --- a/libc/calls/ioctl_tcgets.c +++ b/libc/calls/ioctl_tcgets.c @@ -20,10 +20,12 @@ #include "libc/calls/ioctl.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/metatermios.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.internal.h" #include "libc/calls/ttydefaults.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" +#include "libc/str/str.h" #include "libc/sysv/consts/termios.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/ioctl_tcsets-nt.c b/libc/calls/ioctl_tcsets-nt.c index 9eb023cad..126b57d2f 100644 --- a/libc/calls/ioctl_tcsets-nt.c +++ b/libc/calls/ioctl_tcsets-nt.c @@ -24,6 +24,7 @@ #include "libc/nt/console.h" #include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/enum/version.h" +#include "libc/nt/version.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/termios.h" #include "libc/sysv/errfuns.h" @@ -57,7 +58,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request, if (tio->c_lflag & (IEXTEN | ISIG)) { inmode |= kNtEnableProcessedInput; } - if (NtGetVersion() >= kNtVersionWindows10) { + if (IsAtLeastWindows10()) { inmode |= kNtEnableVirtualTerminalInput; } ok = SetConsoleMode(in, inmode); @@ -71,7 +72,7 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request, if (!(tio->c_oflag & ONLCR)) { outmode |= kNtDisableNewlineAutoReturn; } - if (NtGetVersion() >= kNtVersionWindows10) { + if (IsAtLeastWindows10()) { outmode |= kNtEnableVirtualTerminalProcessing; } ok = SetConsoleMode(out, outmode); diff --git a/libc/calls/ioctl_tcsets.c b/libc/calls/ioctl_tcsets.c index 34e2592fa..77fc8b76e 100644 --- a/libc/calls/ioctl_tcsets.c +++ b/libc/calls/ioctl_tcsets.c @@ -20,6 +20,7 @@ #include "libc/calls/ioctl.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/metatermios.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/calls/ioctl_tiocgwinsz-nt.c b/libc/calls/ioctl_tiocgwinsz-nt.c index 5080a3df5..c6805d11b 100644 --- a/libc/calls/ioctl_tiocgwinsz-nt.c +++ b/libc/calls/ioctl_tiocgwinsz-nt.c @@ -19,9 +19,12 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/termios.h" #include "libc/calls/struct/winsize.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/log/log.h" #include "libc/nt/console.h" #include "libc/nt/enum/startf.h" @@ -31,13 +34,15 @@ #include "libc/sysv/errfuns.h" textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) { - int i, e; + int i, e, rc; uint32_t mode; struct Fd *fds[3]; struct NtStartupInfo startinfo; struct NtConsoleScreenBufferInfoEx sbinfo; + rc = -1; e = errno; if (ws) { + _spinlock(&__fds_lock); fds[0] = fd, fds[1] = g_fds.p + 1, fds[2] = g_fds.p + 0; GetStartupInfo(&startinfo); for (i = 0; i < ARRAYLEN(fds); ++i) { @@ -51,14 +56,16 @@ textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) { ws->ws_xpixel = 0; ws->ws_ypixel = 0; errno = e; - return 0; + rc = 0; + break; } else if (startinfo.dwFlags & kNtStartfUsecountchars) { ws->ws_col = startinfo.dwXCountChars; ws->ws_row = startinfo.dwYCountChars; ws->ws_xpixel = 0; ws->ws_ypixel = 0; errno = e; - return 0; + rc = 0; + break; } else { __winerr(); } @@ -69,8 +76,9 @@ textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) { ebadf(); } } + _spunlock(&__fds_lock); } else { efault(); } - return -1; + return rc; } diff --git a/libc/calls/ioctl_tiocgwinsz.c b/libc/calls/ioctl_tiocgwinsz.c index 91abae9f8..62bc117ae 100644 --- a/libc/calls/ioctl_tiocgwinsz.c +++ b/libc/calls/ioctl_tiocgwinsz.c @@ -20,6 +20,7 @@ #include "libc/calls/ioctl.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/winsize.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/consts/termios.h" diff --git a/libc/calls/ioctl_tiocswinsz-nt.c b/libc/calls/ioctl_tiocswinsz-nt.c index 1b80cd24f..658638c7f 100644 --- a/libc/calls/ioctl_tiocswinsz-nt.c +++ b/libc/calls/ioctl_tiocswinsz-nt.c @@ -20,6 +20,7 @@ #include "libc/calls/internal.h" #include "libc/calls/struct/termios.h" #include "libc/calls/struct/winsize.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/console.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/ioctl_tiocswinsz.c b/libc/calls/ioctl_tiocswinsz.c index dd0db0000..d6bb7b341 100644 --- a/libc/calls/ioctl_tiocswinsz.c +++ b/libc/calls/ioctl_tiocswinsz.c @@ -19,6 +19,7 @@ #include "libc/calls/internal.h" #include "libc/calls/ioctl.h" #include "libc/calls/struct/winsize.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/consts/termios.h" diff --git a/libc/calls/iovecsize.c b/libc/calls/iovecsize.c index 21b71dcd3..d4366a32c 100644 --- a/libc/calls/iovecsize.c +++ b/libc/calls/iovecsize.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/iovec.h" size_t __iovec_size(const struct iovec *v, size_t n) { size_t i, sum; diff --git a/libc/calls/isatty.c b/libc/calls/isatty.c index 3498b7bc3..63e669867 100644 --- a/libc/calls/isatty.c +++ b/libc/calls/isatty.c @@ -20,6 +20,8 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/winsize.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/sysv/consts/termios.h" diff --git a/libc/calls/ischardev.c b/libc/calls/ischardev.c index 82fbe7d51..9e51bf4c8 100644 --- a/libc/calls/ischardev.c +++ b/libc/calls/ischardev.c @@ -16,17 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/metastat.internal.h" -#include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" -#include "libc/sysv/errfuns.h" -#include "libc/zipos/zipos.internal.h" /** * Returns true if file descriptor is backed by character i/o. @@ -44,15 +41,7 @@ bool32 ischardev(int fd) { int e; union metastat st; if (__isfdkind(fd, kFdZip)) { - e = errno; - if (weaken(__zipos_fstat)( - (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, &st.cosmo) != - -1) { - return S_ISCHR(st.cosmo.st_mode); - } else { - errno = e; - return false; - } + return false; } else if (IsMetal()) { return true; } else if (!IsWindows()) { diff --git a/libc/calls/isdirectory-nt.c b/libc/calls/isdirectory-nt.c index d0579a967..a986333e4 100644 --- a/libc/calls/isdirectory-nt.c +++ b/libc/calls/isdirectory-nt.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/errno.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/files.h" diff --git a/libc/calls/isdirectory.c b/libc/calls/isdirectory.c index c68af54d4..84262b49d 100644 --- a/libc/calls/isdirectory.c +++ b/libc/calls/isdirectory.c @@ -18,10 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/metastat.internal.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/calls/islinux.c b/libc/calls/islinux.c index 1209f959e..536545fcc 100644 --- a/libc/calls/islinux.c +++ b/libc/calls/islinux.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/sysv/consts/pr.h" diff --git a/libc/calls/isregularfile-nt.c b/libc/calls/isregularfile-nt.c index 45614ef64..959623e00 100644 --- a/libc/calls/isregularfile-nt.c +++ b/libc/calls/isregularfile-nt.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/errno.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/files.h" diff --git a/libc/calls/isregularfile.c b/libc/calls/isregularfile.c index 35b145b9c..b7112bced 100644 --- a/libc/calls/isregularfile.c +++ b/libc/calls/isregularfile.c @@ -18,9 +18,10 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/metastat.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/calls/issymlink-nt.c b/libc/calls/issymlink-nt.c index 4c074cadb..a474d4134 100644 --- a/libc/calls/issymlink-nt.c +++ b/libc/calls/issymlink-nt.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/errno.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/files.h" diff --git a/libc/calls/issymlink.c b/libc/calls/issymlink.c index 2e2ddcfb5..9ff983f40 100644 --- a/libc/calls/issymlink.c +++ b/libc/calls/issymlink.c @@ -18,10 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/metastat.internal.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/calls/kill-nt.c b/libc/calls/kill-nt.c index 9dc6d46a0..60f909fc3 100644 --- a/libc/calls/kill-nt.c +++ b/libc/calls/kill-nt.c @@ -20,18 +20,21 @@ #include "libc/calls/getconsolectrlevent.internal.h" #include "libc/calls/internal.h" #include "libc/dce.h" +#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/nt/console.h" #include "libc/nt/enum/ctrlevent.h" #include "libc/nt/enum/processaccess.h" +#include "libc/nt/enum/th32cs.h" #include "libc/nt/errors.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" +#include "libc/nt/struct/processentry32.h" #include "libc/sysv/errfuns.h" textwindows int sys_kill_nt(int pid, int sig) { bool32 ok; - int64_t handle; + int64_t h; int event, ntpid; // is killing everything except init really worth supporting? @@ -68,20 +71,37 @@ textwindows int sys_kill_nt(int pid, int sig) { } } - // XXX: Is this a cosmo pid that was returned by fork_nt? + // is this a cosmo pid that was returned by fork? if (__isfdkind(pid, kFdProcess)) { + // since windows can't execve we need to kill the grandchildren + // TODO(jart): should we just kill the whole tree too? there's + // no obvious way to tell if it's the execve shell + int64_t hSnap, hProc, hChildProc; + struct NtProcessEntry32 pe = {.dwSize = sizeof(struct NtProcessEntry32)}; + ntpid = GetProcessId(g_fds.p[pid].handle); + hSnap = CreateToolhelp32Snapshot(kNtTh32csSnapprocess, 0); + if (Process32First(hSnap, &pe)) { + do { + if (pe.th32ParentProcessID == ntpid) { + if ((h = OpenProcess(kNtProcessTerminate, false, pe.th32ProcessID))) { + TerminateProcess(h, 128 + sig); + CloseHandle(h); + } + } + } while (Process32Next(hSnap, &pe)); + } ok = TerminateProcess(g_fds.p[pid].handle, 128 + sig); if (!ok && GetLastError() == kNtErrorAccessDenied) ok = true; return 0; } // XXX: Is this a raw new technology pid? Because that's messy. - if ((handle = OpenProcess(kNtProcessTerminate, false, pid))) { - ok = TerminateProcess(handle, 128 + sig); + if ((h = OpenProcess(kNtProcessTerminate, false, pid))) { + ok = TerminateProcess(h, 128 + sig); if (!ok && GetLastError() == kNtErrorAccessDenied) { ok = true; // cargo culting other codebases here } - CloseHandle(handle); + CloseHandle(h); return 0; } else { return -1; diff --git a/libc/calls/kill.c b/libc/calls/kill.c index a77ff7564..58caee509 100644 --- a/libc/calls/kill.c +++ b/libc/calls/kill.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/str/str.h" diff --git a/libc/calls/killpg.c b/libc/calls/killpg.c index 6808fcd13..4749efe45 100644 --- a/libc/calls/killpg.c +++ b/libc/calls/killpg.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" #include "libc/dce.h" -#include "libc/calls/internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/calls/lchown.c b/libc/calls/lchown.c index fabb0b4c2..b435d42f1 100644 --- a/libc/calls/lchown.c +++ b/libc/calls/lchown.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/sysv/consts/at.h" /** diff --git a/libc/calls/link.c b/libc/calls/link.c index 4ce59ad65..237a3643d 100644 --- a/libc/calls/link.c +++ b/libc/calls/link.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/sysv/consts/at.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/linkat-nt.c b/libc/calls/linkat-nt.c index 072c203f6..94d6efae1 100644 --- a/libc/calls/linkat-nt.c +++ b/libc/calls/linkat-nt.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" diff --git a/libc/calls/linkat.c b/libc/calls/linkat.c index 7b6b86888..4f02f6286 100644 --- a/libc/calls/linkat.c +++ b/libc/calls/linkat.c @@ -18,8 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" diff --git a/libc/calls/lseek-nt.c b/libc/calls/lseek-nt.c index da27f64cf..ca5c3cbf5 100644 --- a/libc/calls/lseek-nt.c +++ b/libc/calls/lseek-nt.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/lseek.c b/libc/calls/lseek.c index 07961309f..7b8daec86 100644 --- a/libc/calls/lseek.c +++ b/libc/calls/lseek.c @@ -20,6 +20,8 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/log/backtrace.internal.h" #include "libc/zipos/zipos.internal.h" diff --git a/libc/calls/madvise-nt.c b/libc/calls/madvise-nt.c index ce50c0002..6686a4d5f 100644 --- a/libc/calls/madvise-nt.c +++ b/libc/calls/madvise-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/macros.internal.h" #include "libc/nt/enum/offerpriority.h" #include "libc/nt/memory.h" diff --git a/libc/calls/madvise.c b/libc/calls/madvise.c index d4f2c7b51..2610d9968 100644 --- a/libc/calls/madvise.c +++ b/libc/calls/madvise.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/metaflock.c b/libc/calls/metaflock.c index a13b891cc..2874c77e4 100644 --- a/libc/calls/metaflock.c +++ b/libc/calls/metaflock.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/struct/flock.h" +#include "libc/dce.h" union metaflock { struct flock cosmo; diff --git a/libc/calls/mincore.c b/libc/calls/mincore.c index 16b9cf1f4..053fbd4e1 100644 --- a/libc/calls/mincore.c +++ b/libc/calls/mincore.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Tells you which pages are resident in memory. diff --git a/libc/calls/mkdir.c b/libc/calls/mkdir.c index d41c67814..01a42f386 100644 --- a/libc/calls/mkdir.c +++ b/libc/calls/mkdir.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" diff --git a/libc/calls/mkdirat-nt.c b/libc/calls/mkdirat-nt.c index 16133342a..5faa232e8 100644 --- a/libc/calls/mkdirat-nt.c +++ b/libc/calls/mkdirat-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/mkdirat.c b/libc/calls/mkdirat.c index 67c5536fc..cc42bbeb5 100644 --- a/libc/calls/mkdirat.c +++ b/libc/calls/mkdirat.c @@ -18,8 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" diff --git a/libc/calls/mkfifo.c b/libc/calls/mkfifo.c index 2f85e7251..fece40a90 100644 --- a/libc/calls/mkfifo.c +++ b/libc/calls/mkfifo.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/nt/ipc.h" diff --git a/libc/calls/mknod.c b/libc/calls/mknod.c index 63d2b9715..c677fa0cc 100644 --- a/libc/calls/mknod.c +++ b/libc/calls/mknod.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/consts/s.h" diff --git a/libc/calls/mkntcmdline.c b/libc/calls/mkntcmdline.c index 29eacc9b1..372c392eb 100644 --- a/libc/calls/mkntcmdline.c +++ b/libc/calls/mkntcmdline.c @@ -31,7 +31,7 @@ } \ } while (0) -static noasan bool NeedsQuotes(const char *s) { +static bool NeedsQuotes(const char *s) { if (!*s) return true; do { if (*s == ' ' || *s == '\t') { @@ -54,8 +54,8 @@ static noasan bool NeedsQuotes(const char *s) { * @return freshly allocated lpCommandLine or NULL w/ errno * @see libc/runtime/dosargv.c */ -textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX / 2], - const char *prog, char *const argv[]) { +textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog, + char *const argv[]) { char *arg; uint64_t w; wint_t x, y; diff --git a/libc/calls/mkntenvblock.c b/libc/calls/mkntenvblock.c index 95287bb6d..e076efbe5 100644 --- a/libc/calls/mkntenvblock.c +++ b/libc/calls/mkntenvblock.c @@ -17,8 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/alg/arraylist2.internal.h" +#include "libc/bits/bits.h" #include "libc/calls/ntspawn.h" #include "libc/fmt/conv.h" +#include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" #include "libc/mem/alloca.h" #include "libc/mem/mem.h" @@ -31,15 +33,85 @@ #define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c)) -static noasan int CompareStrings(const char *l, const char *r) { +static inline int IsAlpha(int c) { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); +} + +static inline char *StrChr(char *s, int c) { + for (;; ++s) { + if ((*s & 255) == (c & 255)) return s; + if (!*s) return 0; + } +} + +static textwindows inline int CompareStrings(const char *l, const char *r) { int a, b; size_t i = 0; while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i; return a - b; } -static noasan void InsertString(char **a, size_t i, char *s) { - size_t j; +static textwindows void FixPath(char *path) { + char *p; + size_t i; + + // skip over variable name + while (*path++) { + if (path[-1] == '=') { + break; + } + } + + // turn colon into semicolon + // unless it already looks like a dos path + for (p = path; *p; ++p) { + if (p[0] == ':' && p[1] != '\\') { + p[0] = ';'; + } + } + + // turn \c\... into c:\... + p = path; + if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') { + p[0] = p[1]; + p[1] = ':'; + } + for (; *p; ++p) { + if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') { + p[1] = p[2]; + p[2] = ':'; + } + } + + // turn slash into backslash + for (p = path; *p; ++p) { + if (*p == '/') { + *p = '\\'; + } + } +} + +static textwindows void InsertString(char **a, size_t i, char *s, + char buf[ARG_MAX], size_t *bufi) { + char *v; + size_t j, k; + + // apply fixups to var=/c/... + if ((v = StrChr(s, '=')) && v[1] == '/' && IsAlpha(v[2]) && v[3] == '/') { + v = buf + *bufi; + for (k = 0; s[k]; ++k) { + if (*bufi + 1 < ARG_MAX) { + buf[(*bufi)++] = s[k]; + } + } + if (*bufi < ARG_MAX) { + buf[(*bufi)++] = 0; + FixPath(v); + s = v; + } + } + + // append to sorted list for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) { a[j] = a[j - 1]; } @@ -57,19 +129,19 @@ static noasan void InsertString(char **a, size_t i, char *s) { * @return 0 on success, or -1 w/ errno * @error E2BIG if total number of shorts exceeded ARG_MAX/2 (32767) */ -textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX / 2], - char *const envp[], const char *extravar) { +textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[], + const char *extravar, char buf[ARG_MAX]) { bool v; char *t; axdx_t rc; uint64_t w; char **vars; wint_t x, y; - size_t i, j, k, n, m; + size_t i, j, k, n, m, bufi = 0; for (n = 0; envp[n];) n++; vars = alloca((n + 1) * sizeof(char *)); - for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]); - if (extravar) InsertString(vars, n++, extravar); + for (i = 0; i < n; ++i) InsertString(vars, i, envp[i], buf, &bufi); + if (extravar) InsertString(vars, n++, extravar, buf, &bufi); for (k = i = 0; i < n; ++i) { j = 0; v = false; diff --git a/libc/calls/mkntpath.c b/libc/calls/mkntpath.c index a2a36a28a..9342bffd6 100644 --- a/libc/calls/mkntpath.c +++ b/libc/calls/mkntpath.c @@ -16,9 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/ntmagicpaths.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/macros.internal.h" #include "libc/nt/systeminfo.h" #include "libc/str/oldutf16.internal.h" @@ -31,6 +31,10 @@ static inline bool IsSlash(char c) { return c == '/' || c == '\\'; } +static inline int IsAlpha(int c) { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); +} + textwindows static const char *FixNtMagicPath(const char *path, unsigned flags) { const struct NtMagicPaths *mp = &kNtMagicPaths; @@ -78,18 +82,51 @@ textwindows int __mkntpath2(const char *path, */ char16_t *p; const char *q; - size_t i, n, m, z; + bool isdospath; + size_t i, n, m, x, z; if (!path) return efault(); path = FixNtMagicPath(path, flags); p = path16; q = path; - if (IsSlash(path[0]) && IsSlash(path[1]) && path[2] == '?' && - IsSlash(path[3])) { + + if (IsSlash(q[0]) && IsAlpha(q[1]) && IsSlash(q[2])) { z = MIN(32767, PATH_MAX); + // turn "\c\foo" into "\\?\c:\foo" + p[0] = '\\'; + p[1] = '\\'; + p[2] = '?'; + p[3] = '\\'; + p[4] = q[1]; + p[5] = ':'; + p[6] = '\\'; + p += 7; + q += 3; + z -= 7; + x = 7; + } else if (IsSlash(q[0]) && IsAlpha(q[1]) && IsSlash(q[2])) { + z = MIN(32767, PATH_MAX); + // turn "c:\foo" into "\\?\c:\foo" + p[0] = '\\'; + p[1] = '\\'; + p[2] = '?'; + p[3] = '\\'; + p[4] = q[0]; + p[5] = ':'; + p[6] = '\\'; + p += 7; + q += 3; + z -= 7; + x = 7; + } else if (IsSlash(q[0]) && IsSlash(q[1]) && q[2] == '?' && IsSlash(q[3])) { + z = MIN(32767, PATH_MAX); + x = 0; } else { z = MIN(260, PATH_MAX); + x = 0; } - if (IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' && + + // turn /tmp into GetTempPath() + if (!x && IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' && (IsSlash(q[4]) || !q[4])) { m = GetTempPath(z, p); if (!q[4]) return m; @@ -99,15 +136,20 @@ textwindows int __mkntpath2(const char *path, } else { m = 0; } + + // turn utf-8 into utf-16 n = tprecode8to16(p, z, q).ax; if (n >= z - 1) { STRACE("path too long for windows: %#s", path); return enametoolong(); } + + // turn slash into backslash for (i = 0; i < n; ++i) { if (p[i] == '/') { p[i] = '\\'; } } - return m + n; + + return x + m + n; } diff --git a/libc/calls/mkntpathat.c b/libc/calls/mkntpathat.c index f2258721b..204db959a 100644 --- a/libc/calls/mkntpathat.c +++ b/libc/calls/mkntpathat.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/macros.internal.h" #include "libc/nt/files.h" #include "libc/str/str.h" diff --git a/libc/calls/mman.greg.c b/libc/calls/mman.greg.c index bc50271a4..fa0623e50 100644 --- a/libc/calls/mman.greg.c +++ b/libc/calls/mman.greg.c @@ -64,7 +64,7 @@ noasan texthead uint64_t __new_page(struct mman *mm) { * Returns pointer to page table entry for page at virtual address. * Additional page tables are allocated if needed as a side-effect. */ -noasan texthead uint64_t *__get_virtual(struct mman *mm, uint64_t *t, +noasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t, int64_t vaddr, bool maketables) { uint64_t *e, p; unsigned char h; @@ -83,7 +83,7 @@ noasan texthead uint64_t *__get_virtual(struct mman *mm, uint64_t *t, /** * Sorts, rounds, and filters BIOS memory map. */ -static noasan texthead void __normalize_e820(struct mman *mm) { +static noasan textreal void __normalize_e820(struct mman *mm) { uint64_t a, b; uint64_t x, y; unsigned i, j, n; @@ -113,7 +113,7 @@ static noasan texthead void __normalize_e820(struct mman *mm) { /** * Identity maps all usable physical memory to its negative address. */ -static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) { +static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) { uint64_t i, j, *m, p, pe; for (i = 0; i < mm->e820n; ++i) { for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size; @@ -126,7 +126,7 @@ static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) { } } -noasan texthead void __setup_mman(struct mman *mm, uint64_t *pml4t) { +noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) { __normalize_e820(mm); __invert_memory(mm, pml4t); } diff --git a/libc/calls/munmap-sysv.c b/libc/calls/munmap-sysv.c index d2ea45e00..95b697034 100644 --- a/libc/calls/munmap-sysv.c +++ b/libc/calls/munmap-sysv.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/runtime/directmap.internal.h" #include "libc/runtime/memtrack.internal.h" diff --git a/libc/calls/nanos.c b/libc/calls/nanos.c new file mode 100644 index 000000000..14728f272 --- /dev/null +++ b/libc/calls/nanos.c @@ -0,0 +1,34 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/struct/timespec.h" +#include "libc/time/time.h" + +/** + * Returns nanoseconds since UNIX epoch. + */ +int128_t _nanos(int timer) { + int128_t nanos; + struct timespec ts; + clock_gettime(timer, &ts); + nanos = ts.tv_sec; + nanos *= 1000000000; + nanos += ts.tv_nsec; + return nanos; +} diff --git a/libc/calls/nanos.h b/libc/calls/nanos.h new file mode 100644 index 000000000..547557290 --- /dev/null +++ b/libc/calls/nanos.h @@ -0,0 +1,10 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_NANOS_H_ +#define COSMOPOLITAN_LIBC_CALLS_NANOS_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +int128_t _nanos(int); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_NANOS_H_ */ diff --git a/libc/calls/nanosleep-nt.c b/libc/calls/nanosleep-nt.c index 275bf3086..4de595513 100644 --- a/libc/calls/nanosleep-nt.c +++ b/libc/calls/nanosleep-nt.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/errno.h" #include "libc/limits.h" diff --git a/libc/calls/nanosleep.c b/libc/calls/nanosleep.c index 226eeba81..4f0e6edc3 100644 --- a/libc/calls/nanosleep.c +++ b/libc/calls/nanosleep.c @@ -16,8 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/asan.internal.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/describeflags.internal.h" @@ -30,7 +32,8 @@ noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) { int rc; char buf[2][45]; - if (!req) { + if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) || + (rem && !__asan_is_valid_timespec(rem))))) { rc = efault(); } else if (req->tv_sec < 0 || !(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) { diff --git a/libc/calls/nosync.c b/libc/calls/nosync.c new file mode 100644 index 000000000..fd0a71df8 --- /dev/null +++ b/libc/calls/nosync.c @@ -0,0 +1,30 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" + +/** + * Tunes sync system call availability. + * + * If this value is set to 0x5453455454534146, then the system calls + * sync(), fsync(), and fdatasync() system calls will do nothing and + * return success. This is intended to be used for things like making + * things like Python unit tests go faster because fsync is extremely + * slow and using tmpfs requires root privileges. + */ +uint64_t __nosync; diff --git a/libc/calls/now.c b/libc/calls/now.c index a7ec88b88..62ec67940 100644 --- a/libc/calls/now.c +++ b/libc/calls/now.c @@ -20,8 +20,11 @@ #include "libc/bits/initializer.internal.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" +#include "libc/calls/clock_gettime.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" @@ -30,10 +33,11 @@ #include "libc/sysv/consts/clock.h" #include "libc/time/time.h" +static clock_gettime_f *__gettime; + static struct Now { uint64_t k0; long double r0, cpn; - typeof(sys_clock_gettime) *clock_gettime; } g_now; static long double GetTimeSample(void) { @@ -88,7 +92,7 @@ static long double nowl_art(void) { static long double nowl_vdso(void) { long double secs; struct timespec tv; - g_now.clock_gettime(CLOCK_REALTIME, &tv); + __gettime(CLOCK_REALTIME, &tv); secs = tv.tv_nsec; secs *= 1 / 1e9L; secs += tv.tv_sec; @@ -96,8 +100,10 @@ static long double nowl_vdso(void) { } long double nowl_setup(void) { + bool isfast; uint64_t ticks; - if ((g_now.clock_gettime = __get_clock_gettime())) { + __gettime = __clock_gettime_get(&isfast); + if (isfast) { nowl = nowl_vdso; } else if (X86_HAVE(INVTSC)) { RefreshTime(); @@ -107,5 +113,3 @@ long double nowl_setup(void) { } return nowl(); } - -long double (*nowl)(void) = nowl_setup; diff --git a/libc/calls/nowl.S b/libc/calls/nowl.S new file mode 100644 index 000000000..d83b1f59d --- /dev/null +++ b/libc/calls/nowl.S @@ -0,0 +1,29 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + + .initbss 201,_init_nowl +nowl: .quad 0 + .endobj nowl,globl + .previous + + .init.start 201,_init_nowl + ezlea nowl_setup,ax + stosq + .init.end 201,_init_nowl diff --git a/libc/calls/ntaccesscheck.c b/libc/calls/ntaccesscheck.c index a06f7188b..367811257 100644 --- a/libc/calls/ntaccesscheck.c +++ b/libc/calls/ntaccesscheck.c @@ -18,8 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/fmt/fmt.h" #include "libc/mem/mem.h" #include "libc/nt/enum/accessmask.h" @@ -94,15 +94,15 @@ TryAgain: } } else { rc = __winerr(); - STRACE("%s failed: %m", "AccessCheck"); + STRACE("%s(%#hs) failed: %m", "AccessCheck", pathname); } } else { rc = __winerr(); - STRACE("%s failed: %m", "DuplicateToken"); + STRACE("%s(%#hs) failed: %m", "DuplicateToken", pathname); } } else { rc = __winerr(); - STRACE("%s failed: %m", "OpenProcessToken"); + STRACE("%s(%#hs) failed: %m", "OpenProcessToken", pathname); } } else { e = GetLastError(); @@ -112,9 +112,11 @@ TryAgain: goto TryAgain; } else { rc = enomem(); + STRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname); } } else { errno = e; + STRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname); rc = -1; } } diff --git a/libc/calls/ntcontext2linux.c b/libc/calls/ntcontext2linux.c index c1a509b1e..8d527ee9e 100644 --- a/libc/calls/ntcontext2linux.c +++ b/libc/calls/ntcontext2linux.c @@ -16,12 +16,12 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/ucontext.h" +#include "libc/log/libfatal.internal.h" #include "libc/nt/struct/context.h" #include "libc/str/str.h" -textwindows void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) { +privileged void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) { if (!cr) return; ctx->uc_flags = cr->EFlags; ctx->uc_mcontext.eflags = cr->EFlags; @@ -46,10 +46,10 @@ textwindows void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) { ctx->uc_mcontext.gs = cr->SegGs; ctx->uc_mcontext.fs = cr->SegFs; ctx->uc_mcontext.fpregs = &ctx->__fpustate; - memcpy(&ctx->__fpustate, &cr->FltSave, sizeof(ctx->__fpustate)); + __repmovsb(&ctx->__fpustate, &cr->FltSave, sizeof(ctx->__fpustate)); } -textwindows void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) { +privileged void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) { if (!cr) return; cr->EFlags = ctx->uc_flags; cr->EFlags = ctx->uc_mcontext.eflags; @@ -73,5 +73,5 @@ textwindows void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) { cr->SegCs = ctx->uc_mcontext.cs; cr->SegGs = ctx->uc_mcontext.gs; cr->SegFs = ctx->uc_mcontext.fs; - memcpy(&cr->FltSave, &ctx->__fpustate, sizeof(ctx->__fpustate)); + __repmovsb(&cr->FltSave, &ctx->__fpustate, sizeof(ctx->__fpustate)); } diff --git a/libc/calls/ntreturn.c b/libc/calls/ntreturn.c index da63a2f0f..f6301a6b1 100644 --- a/libc/calls/ntreturn.c +++ b/libc/calls/ntreturn.c @@ -19,7 +19,6 @@ #include "libc/errno.h" #include "libc/nt/errors.h" #include "libc/nt/ntdll.h" -#include "libc/calls/internal.h" /** * Exitpoint for Windows NT system calls. diff --git a/libc/calls/ntsetprivilege.c b/libc/calls/ntsetprivilege.c index 8dd6994a4..79c36083f 100644 --- a/libc/calls/ntsetprivilege.c +++ b/libc/calls/ntsetprivilege.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/nt/privilege.h" #include "libc/nt/struct/tokenprivileges.h" diff --git a/libc/calls/ntspawn.c b/libc/calls/ntspawn.c index fe63fa82a..9f99129b6 100644 --- a/libc/calls/ntspawn.c +++ b/libc/calls/ntspawn.c @@ -17,9 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/pushpop.h" -#include "libc/calls/internal.h" #include "libc/calls/ntspawn.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/macros.internal.h" #include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/pageflags.h" @@ -36,8 +36,9 @@ struct SpawnBlock { struct { char16_t cmdline[ARG_MAX / 2]; char16_t envvars[ARG_MAX / 2]; + char buf[ARG_MAX]; }; - char __pad[ROUNDUP(ARG_MAX / 2 * 2 * sizeof(char16_t), FRAMESIZE)]; + char __pad[ROUNDUP(ARG_MAX / 2 * 3 * sizeof(char16_t), FRAMESIZE)]; }; }; @@ -83,7 +84,7 @@ textwindows int ntspawn( (block = MapViewOfFileEx(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0, sizeof(*block), 0)) && mkntcmdline(block->cmdline, prog, argv) != -1 && - mkntenvblock(block->envvars, envp, extravar) != -1 && + mkntenvblock(block->envvars, envp, extravar, block->buf) != -1 && CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes, opt_lpThreadAttributes, bInheritHandles, dwCreationFlags | kNtCreateUnicodeEnvironment, diff --git a/libc/calls/ntspawn.h b/libc/calls/ntspawn.h index df1955b43..167b431f1 100644 --- a/libc/calls/ntspawn.h +++ b/libc/calls/ntspawn.h @@ -7,7 +7,8 @@ COSMOPOLITAN_C_START_ int mkntcmdline(char16_t[ARG_MAX / 2], const char *, char *const[]) hidden; -int mkntenvblock(char16_t[ARG_MAX / 2], char *const[], const char *) hidden; +int mkntenvblock(char16_t[ARG_MAX / 2], char *const[], const char *, + char[ARG_MAX]) hidden; int ntspawn(const char *, char *const[], char *const[], const char *, struct NtSecurityAttributes *, struct NtSecurityAttributes *, bool32, uint32_t, const char16_t *, const struct NtStartupInfo *, diff --git a/libc/calls/offset2overlap.c b/libc/calls/offset2overlap.c index e50d99811..0b5eb2961 100644 --- a/libc/calls/offset2overlap.c +++ b/libc/calls/offset2overlap.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/nt/struct/overlapped.h" +#include "libc/str/str.h" textwindows struct NtOverlapped *_offset2overlap(int64_t handle, int64_t opt_offset, diff --git a/libc/calls/oldbench.c b/libc/calls/oldbench.c index ee1ab4c41..3f233e32a 100644 --- a/libc/calls/oldbench.c +++ b/libc/calls/oldbench.c @@ -20,7 +20,7 @@ #include "libc/bits/initializer.internal.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/macros.internal.h" diff --git a/libc/calls/open-nt.c b/libc/calls/open-nt.c index 1955a5d18..f2b6001d3 100644 --- a/libc/calls/open-nt.c +++ b/libc/calls/open-nt.c @@ -16,28 +16,20 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" #include "libc/calls/internal.h" #include "libc/calls/ntmagicpaths.internal.h" -#include "libc/calls/strace.internal.h" +#include "libc/calls/state.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/nt/createfile.h" -#include "libc/nt/enum/accessmask.h" -#include "libc/nt/enum/creationdisposition.h" -#include "libc/nt/enum/fileflagandattributes.h" -#include "libc/nt/enum/filesharemode.h" #include "libc/nt/enum/filetype.h" -#include "libc/nt/enum/fsctl.h" -#include "libc/nt/errors.h" #include "libc/nt/files.h" -#include "libc/nt/runtime.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/o.h" -#include "libc/sysv/errfuns.h" -static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, - uint32_t flags, int32_t mode) { +static textwindows int sys_open_nt_impl(int dirfd, const char *path, + uint32_t flags, int32_t mode) { char16_t path16[PATH_MAX]; uint32_t perm, share, disp, attr; if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; @@ -47,10 +39,10 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, path16); } -static textwindows ssize_t sys_open_nt_console(int dirfd, - const struct NtMagicPaths *mp, - uint32_t flags, int32_t mode, - size_t fd) { +static textwindows int sys_open_nt_console(int dirfd, + const struct NtMagicPaths *mp, + uint32_t flags, int32_t mode, + size_t fd) { if (GetFileType(g_fds.p[STDIN_FILENO].handle) == kNtFileTypeChar && GetFileType(g_fds.p[STDOUT_FILENO].handle) == kNtFileTypeChar) { g_fds.p[fd].handle = g_fds.p[STDIN_FILENO].handle; @@ -70,9 +62,9 @@ static textwindows ssize_t sys_open_nt_console(int dirfd, return fd; } -static textwindows ssize_t sys_open_nt_file(int dirfd, const char *file, - uint32_t flags, int32_t mode, - size_t fd) { +static textwindows int sys_open_nt_file(int dirfd, const char *file, + uint32_t flags, int32_t mode, + size_t fd) { if ((g_fds.p[fd].handle = sys_open_nt_impl(dirfd, file, flags, mode)) != -1) { g_fds.p[fd].kind = kFdFile; g_fds.p[fd].flags = flags; @@ -83,18 +75,21 @@ static textwindows ssize_t sys_open_nt_file(int dirfd, const char *file, } } -textwindows ssize_t sys_open_nt(int dirfd, const char *file, uint32_t flags, - int32_t mode) { +textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags, + int32_t mode) { int fd; ssize_t rc; - if ((fd = __reservefd(-1)) == -1) return -1; - if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) { - rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd); - } else { - rc = sys_open_nt_file(dirfd, file, flags, mode, fd); - } - if (rc == -1) { - __releasefd(fd); + _spinlock(&__fds_lock); + if ((rc = fd = __reservefd_unlocked(-1)) != -1) { + if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) { + rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd); + } else { + rc = sys_open_nt_file(dirfd, file, flags, mode, fd); + } + if (rc == -1) { + __releasefd_unlocked(fd); + } + _spunlock(&__fds_lock); } return rc; } diff --git a/libc/calls/openat-sysv.c b/libc/calls/openat-sysv.c index d9c3bc659..8088d5e59 100644 --- a/libc/calls/openat-sysv.c +++ b/libc/calls/openat-sysv.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/str/str.h" diff --git a/libc/calls/openat.c b/libc/calls/openat.c index 19968a080..0ce7c46f6 100644 --- a/libc/calls/openat.c +++ b/libc/calls/openat.c @@ -19,7 +19,10 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/fmt/magnumstrs.internal.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/calls/openpty.c b/libc/calls/openpty.c index 2e1b282ab..080d6ef8c 100644 --- a/libc/calls/openpty.c +++ b/libc/calls/openpty.c @@ -17,33 +17,44 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/ioctl.h" #include "libc/calls/termios.h" +#include "libc/fmt/itoa.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/pty.h" +#include "libc/sysv/consts/termios.h" #include "libc/sysv/errfuns.h" /** * Opens new pseudo teletypewriter. * - * @param ilduce receives controlling tty rw fd on success - * @param aworker receives subordinate tty rw fd on success - * @param termp may be passed to tune a century of legacy behaviors - * @param winp may be passed to set terminal display dimensions + * @param mfd receives controlling tty rw fd on success + * @param sfd receives subordinate tty rw fd on success + * @param tio may be passed to tune a century of legacy behaviors + * @param wsz may be passed to set terminal display dimensions * @params flags is usually O_RDWR|O_NOCTTY - * @return file descriptor, or -1 w/ errno + * @return 0 on success, or -1 w/ errno */ -int openpty(int *ilduce, int *aworker, char *name, const struct termios *termp, - const struct winsize *winp) { - return enosys(); - /* TODO(jart) */ - /* int fd, flags; */ - /* flags = O_RDWR | O_NOCTTY; */ - /* if ((fd = posix_openpt(flags)) != -1) { */ - /* if (ioctl(m, TIOCSPTLCK, &n) || ioctl(m, TIOCGPTN, &n)) { */ - /* } else { */ - /* close(fd); */ - /* } */ - /* } else { */ - /* return -1; */ - /* } */ +int openpty(int *mfd, int *sfd, char *name, const struct termios *tio, + const struct winsize *wsz) { + int m, s, n; + char buf[20]; + if ((m = open("/dev/ptmx", O_RDWR | O_NOCTTY)) != -1) { + n = 0; + if (!ioctl(m, TIOCSPTLCK, &n) || !ioctl(m, TIOCGPTN, &n)) { + if (!name) name = buf; + name[0] = '/', name[1] = 'd', name[2] = 'e', name[3] = 'v'; + name[4] = '/', name[5] = 'p', name[6] = 't', name[7] = 's'; + name[8] = '/', FormatInt32(name + 9, n); + if ((s = open(name, O_RDWR | O_NOCTTY)) != -1) { + if (tio) ioctl(s, TCSETS, tio); + if (wsz) ioctl(s, TIOCSWINSZ, wsz); + *mfd = m; + *sfd = s; + return 0; + } + } + close(m); + } + return -1; } diff --git a/libc/calls/pause.c b/libc/calls/pause.c index b58303702..23886a070 100644 --- a/libc/calls/pause.c +++ b/libc/calls/pause.c @@ -17,9 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigset.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/nt/synchronization.h" diff --git a/libc/calls/pipe-nt.c b/libc/calls/pipe-nt.c index 0c0db0823..c38e6c8c7 100644 --- a/libc/calls/pipe-nt.c +++ b/libc/calls/pipe-nt.c @@ -17,6 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/creationdisposition.h" @@ -33,9 +36,14 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) { int reader, writer; char16_t pipename[64]; CreatePipeName(pipename); - if ((reader = __reservefd(-1)) == -1) return -1; - if ((writer = __reservefd(-1)) == -1) { - __releasefd(reader); + _spinlock(&__fds_lock); + if ((reader = __reservefd_unlocked(-1)) == -1) { + _spunlock(&__fds_lock); + return -1; + } + if ((writer = __reservefd_unlocked(-1)) == -1) { + __releasefd_unlocked(reader); + _spunlock(&__fds_lock); return -1; } if (~flags & O_DIRECT) { @@ -43,9 +51,11 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) { } else { mode = kNtPipeTypeMessage | kNtPipeReadmodeMessage; } - if ((hin = CreateNamedPipe( - pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped, mode, 1, - PIPE_BUF, PIPE_BUF, 0, &kNtIsInheritable)) != -1) { + _spunlock(&__fds_lock); + hin = CreateNamedPipe(pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped, + mode, 1, PIPE_BUF, PIPE_BUF, 0, &kNtIsInheritable); + _spinlock(&__fds_lock); + if (hin != -1) { if ((hout = CreateFile(pipename, kNtGenericWrite, 0, &kNtIsInheritable, kNtOpenExisting, kNtFileFlagOverlapped, 0)) != -1) { g_fds.p[reader].kind = kFdFile; @@ -58,12 +68,14 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) { g_fds.p[writer].handle = hout; pipefd[0] = reader; pipefd[1] = writer; + _spunlock(&__fds_lock); return 0; } else { CloseHandle(hin); } } - __releasefd(writer); - __releasefd(reader); + __releasefd_unlocked(writer); + __releasefd_unlocked(reader); + _spunlock(&__fds_lock); return -1; } diff --git a/libc/calls/pipe-sysv.c b/libc/calls/pipe-sysv.c index 575337099..eb9da6ada 100644 --- a/libc/calls/pipe-sysv.c +++ b/libc/calls/pipe-sysv.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" int sys_pipe(int fds[2]) { diff --git a/libc/calls/pipe.c b/libc/calls/pipe.c index bbced47d4..94f65eed1 100644 --- a/libc/calls/pipe.c +++ b/libc/calls/pipe.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/pipe2-sysv.c b/libc/calls/pipe2-sysv.c index 34cb734ae..526917b8b 100644 --- a/libc/calls/pipe2-sysv.c +++ b/libc/calls/pipe2-sysv.c @@ -16,7 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/sysv/consts/o.h" diff --git a/libc/calls/pipe2.c b/libc/calls/pipe2.c index 2c916775a..738260ae4 100644 --- a/libc/calls/pipe2.c +++ b/libc/calls/pipe2.c @@ -16,8 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sysv/consts/o.h" diff --git a/libc/calls/poll-metal.c b/libc/calls/poll-metal.c index 60c77a423..d3f9c93a7 100644 --- a/libc/calls/poll-metal.c +++ b/libc/calls/poll-metal.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/safemacros.internal.h" +#include "libc/calls/internal.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/uart.internal.h" #include "libc/runtime/pc.internal.h" diff --git a/libc/calls/poll-nt.c b/libc/calls/poll-nt.c index b8664c48a..c6b575f88 100644 --- a/libc/calls/poll-nt.c +++ b/libc/calls/poll-nt.c @@ -22,6 +22,7 @@ #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/sigbits.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigaction.h" #include "libc/errno.h" @@ -38,13 +39,12 @@ #include "libc/nt/synchronization.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" -#include "libc/sock/ntstdin.internal.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" -_Alignas(64) static char poll_lock; +_Alignas(64) static int poll_lock; /** * Polls on the New Technology. diff --git a/libc/calls/poll.c b/libc/calls/poll.c index 6fb4d8ae0..052674750 100644 --- a/libc/calls/poll.c +++ b/libc/calls/poll.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/errno.h" diff --git a/libc/calls/posix_openpt.c b/libc/calls/posix_openpt.c index 13fedf2f2..93bd3309f 100644 --- a/libc/calls/posix_openpt.c +++ b/libc/calls/posix_openpt.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" #include "libc/dce.h" #include "libc/errno.h" diff --git a/libc/calls/pread.c b/libc/calls/pread.c index 1f4370e63..6361e17b3 100644 --- a/libc/calls/pread.c +++ b/libc/calls/pread.c @@ -22,6 +22,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/macros.internal.h" diff --git a/libc/calls/preadv.c b/libc/calls/preadv.c index 4b527d88c..2a8d7c0ce 100644 --- a/libc/calls/preadv.c +++ b/libc/calls/preadv.c @@ -20,8 +20,10 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/calls/printfds.c b/libc/calls/printfds.c index 26ad273b2..f3a45a039 100644 --- a/libc/calls/printfds.c +++ b/libc/calls/printfds.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" @@ -54,7 +55,6 @@ void __printfds(void) { if (g_fds.p[i].mode) kprintf(" mode=%#o", g_fds.p[i].mode); if (g_fds.p[i].handle) kprintf(" handle=%ld", g_fds.p[i].handle); if (g_fds.p[i].extra) kprintf(" extra=%ld", g_fds.p[i].extra); - if (g_fds.p[i].worker) kprintf(" worker=%p", g_fds.p[i].worker); kprintf("\n"); } _spunlock(&__fds_lock); diff --git a/libc/calls/ptrace.c b/libc/calls/ptrace.c index 8eb15c3c9..a2e8d2c62 100644 --- a/libc/calls/ptrace.c +++ b/libc/calls/ptrace.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/sysv/consts/ptrace.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/pwrite.c b/libc/calls/pwrite.c index 0335cbe28..c202ae0f8 100644 --- a/libc/calls/pwrite.c +++ b/libc/calls/pwrite.c @@ -21,6 +21,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/macros.internal.h" diff --git a/libc/calls/pwritev.c b/libc/calls/pwritev.c index 3d8744415..4a90d8201 100644 --- a/libc/calls/pwritev.c +++ b/libc/calls/pwritev.c @@ -21,6 +21,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/calls/raise.c b/libc/calls/raise.c index 6b47956d6..57481ec80 100644 --- a/libc/calls/raise.c +++ b/libc/calls/raise.c @@ -18,9 +18,10 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/getconsolectrlevent.internal.h" -#include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/kprintf.h" #include "libc/nt/console.h" #include "libc/nt/errors.h" diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index 9c2d44692..6bbc9ded3 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -19,6 +19,7 @@ #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/enum/filetype.h" #include "libc/nt/errors.h" #include "libc/nt/files.h" diff --git a/libc/calls/read.c b/libc/calls/read.c index 31ffff570..2f42ea22a 100644 --- a/libc/calls/read.c +++ b/libc/calls/read.c @@ -21,6 +21,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/kprintf.h" diff --git a/libc/calls/readansi.c b/libc/calls/readansi.c index e7ee617fb..854ad59cd 100644 --- a/libc/calls/readansi.c +++ b/libc/calls/readansi.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/str/thompike.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/readlinkat-nt.c b/libc/calls/readlinkat-nt.c index e55136d35..3e75adefc 100644 --- a/libc/calls/readlinkat-nt.c +++ b/libc/calls/readlinkat-nt.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/mem/alloca.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/creationdisposition.h" @@ -58,10 +58,9 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer + rdb->SymbolicLinkReparseBuffer.PrintNameOffset); if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') { - buf[j++] = '/'; - buf[j++] = '/'; - buf[j++] = '?'; - buf[j++] = '/'; + p[1] = p[0]; + p[0] = '/'; + p[2] = '/'; } while (i < n) { x = p[i++] & 0xffff; diff --git a/libc/calls/readlinkat.c b/libc/calls/readlinkat.c index d35116378..b06d285e3 100644 --- a/libc/calls/readlinkat.c +++ b/libc/calls/readlinkat.c @@ -16,12 +16,15 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/bits/weaken.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" +#include "libc/runtime/runtime.h" #include "libc/sysv/errfuns.h" #include "libc/zipos/zipos.internal.h" @@ -50,6 +53,7 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) { (bytes = __zipos_notat(dirfd, path)) == -1) { STRACE("TOOD: zipos support for readlinkat"); } else if (!IsWindows()) { + assert(bufsiz); bytes = sys_readlinkat(dirfd, path, buf, bufsiz); } else { bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz); diff --git a/libc/calls/readv-nt.c b/libc/calls/readv-nt.c index a9b55edd5..e4aa2ebf7 100644 --- a/libc/calls/readv-nt.c +++ b/libc/calls/readv-nt.c @@ -19,6 +19,7 @@ #include "libc/bits/weaken.h" #include "libc/calls/internal.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" textwindows ssize_t sys_readv_nt(struct Fd *fd, const struct iovec *iov, diff --git a/libc/calls/readv.c b/libc/calls/readv.c index 54ae7ee12..d54ddbe48 100644 --- a/libc/calls/readv.c +++ b/libc/calls/readv.c @@ -21,6 +21,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/kprintf.h" diff --git a/libc/calls/realpath.c b/libc/calls/realpath.c index cb79c7142..559529652 100644 --- a/libc/calls/realpath.c +++ b/libc/calls/realpath.c @@ -30,6 +30,7 @@ #include "libc/bits/safemacros.internal.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/errno.h" #include "libc/limits.h" #include "libc/log/backtrace.internal.h" @@ -81,7 +82,9 @@ char *realpath(const char *filename, char *resolved) ssize_t rc; int e, up, check_dir=0; size_t k, p, q, l, l0, cnt=0, nup=0; - char output[PATH_MAX], stack[PATH_MAX], *z; + char output[PATH_MAX], stack[PATH_MAX+1], *z; + + /* STRACE("realpath(%#s, %#s)", filename, resolved); */ if (!filename) { einval(); diff --git a/libc/calls/reboot.c b/libc/calls/reboot.c index 3077f7be5..6f422393c 100644 --- a/libc/calls/reboot.c +++ b/libc/calls/reboot.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/framebuffervirtualscreeninfo.h" #include "libc/dce.h" #include "libc/nt/enum/version.h" diff --git a/libc/calls/renameat-nt.c b/libc/calls/renameat-nt.c index 949d05d84..8b094783d 100644 --- a/libc/calls/renameat-nt.c +++ b/libc/calls/renameat-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/enum/movefileexflags.h" #include "libc/nt/files.h" diff --git a/libc/calls/renameat.c b/libc/calls/renameat.c index 107ef3b69..f3084e9bc 100644 --- a/libc/calls/renameat.c +++ b/libc/calls/renameat.c @@ -18,8 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" diff --git a/libc/calls/reservefd.c b/libc/calls/reservefd.c index a68a56e7c..528b25e4b 100644 --- a/libc/calls/reservefd.c +++ b/libc/calls/reservefd.c @@ -20,6 +20,7 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" @@ -29,35 +30,64 @@ #include "libc/str/str.h" #include "libc/sysv/errfuns.h" +// XXX: until we can add read locks to all the code that uses g_fds.p +// (right now we only have write locks) we need to keep old copies +// of g_fds.p around after it's been extended, so that threads +// which are using an fd they de facto own can continue reading +static void FreeOldFdsArray(void *p) { + weaken(free)(p); +} + +/** + * Grows file descriptor array memory if needed. + */ +int __ensurefds_unlocked(int fd) { + size_t n1, n2; + struct Fd *p1, *p2; + if (fd < g_fds.n) return fd; + STRACE("__ensurefds(%d) extending", fd); + if (!weaken(malloc)) return emfile(); + p1 = g_fds.p; + n1 = g_fds.n; + if (p1 == g_fds.__init_p) { + if (!(p2 = weaken(malloc)(sizeof(g_fds.__init_p)))) return -1; + memcpy(p2, p1, sizeof(g_fds.__init_p)); + g_fds.p = p1 = p2; + } + n2 = n1; + while (n2 <= fd) n2 *= 2; + if (!(p2 = weaken(malloc)(n2 * sizeof(*p1)))) return -1; + __cxa_atexit(FreeOldFdsArray, p1, 0); + memcpy(p2, p1, n1 * sizeof(*p1)); + bzero(p2 + n1, (n2 - n1) * sizeof(*p1)); + g_fds.p = p2; + g_fds.n = n2; + return fd; +} + /** * Grows file descriptor array memory if needed. */ int __ensurefds(int fd) { - size_t n1, n2; - struct Fd *p1, *p2; _spinlock(&__fds_lock); - n1 = g_fds.n; - if (fd >= n1) { - STRACE("__ensurefds(%d) extending", fd); - if (weaken(malloc)) { - // TODO(jart): we need a semaphore for this - p1 = g_fds.p; - n2 = fd + (fd >> 1); - if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) { - memcpy(p2, p1, n1 * sizeof(*p1)); - g_fds.p = p2; - g_fds.n = n2; - if (p1 != g_fds.__init_p) { - weaken(free)(p1); - } - } else { - fd = enomem(); - } - } else { - fd = emfile(); + fd = __ensurefds_unlocked(fd); + _spunlock(&__fds_lock); + return fd; +} + +/** + * Finds open file descriptor slot. + */ +int __reservefd_unlocked(int start) { + int fd; + for (fd = MAX(start, g_fds.f); fd < g_fds.n; ++fd) { + if (!g_fds.p[fd].kind) { + break; } } - _spunlock(&__fds_lock); + fd = __ensurefds_unlocked(fd); + bzero(g_fds.p + fd, sizeof(*g_fds.p)); + g_fds.p[fd].kind = kFdReserved; return fd; } @@ -66,42 +96,36 @@ int __ensurefds(int fd) { */ int __reservefd(int start) { int fd; - for (;;) { - _spinlock(&__fds_lock); - fd = start < 0 ? g_fds.f : start; - while (fd < g_fds.n && g_fds.p[fd].kind) ++fd; - if (fd < g_fds.n) { - g_fds.f = fd + 1; - bzero(g_fds.p + fd, sizeof(*g_fds.p)); - g_fds.p[fd].kind = kFdReserved; - _spunlock(&__fds_lock); - return fd; - } else { - _spunlock(&__fds_lock); - if (__ensurefds(fd) == -1) { - return -1; - } - } - } + _spinlock(&__fds_lock); + fd = __reservefd_unlocked(start); + _spunlock(&__fds_lock); + return fd; } /** * Closes non-stdio file descriptors to free dynamic memory. */ static void FreeFds(void) { - int i; - NTTRACE("FreeFds()"); - for (i = 3; i < g_fds.n; ++i) { + int i, keep = 3; + STRACE("FreeFds()"); + _spinlock(&__fds_lock); + for (i = keep; i < g_fds.n; ++i) { if (g_fds.p[i].kind) { + _spunlock(&__fds_lock); close(i); + _spinlock(&__fds_lock); } } if (g_fds.p != g_fds.__init_p) { - memcpy(g_fds.__init_p, g_fds.p, sizeof(*g_fds.p) * 3); - weaken(free)(g_fds.p); + bzero(g_fds.__init_p, sizeof(g_fds.__init_p)); + memcpy(g_fds.__init_p, g_fds.p, sizeof(*g_fds.p) * keep); + if (weaken(free)) { + weaken(free)(g_fds.p); + } g_fds.p = g_fds.__init_p; g_fds.n = ARRAYLEN(g_fds.__init_p); } + _spunlock(&__fds_lock); } static textstartup void FreeFdsInit(void) { diff --git a/libc/calls/rusage2linux.c b/libc/calls/rusage2linux.c index 855fd8dbe..d1b62b8e9 100644 --- a/libc/calls/rusage2linux.c +++ b/libc/calls/rusage2linux.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/rusage.h" void __rusage2linux(struct rusage *ru) { if (IsXnu()) { diff --git a/libc/calls/sched_getaffinity.c b/libc/calls/sched_getaffinity.c index 023b217c3..cc9362e95 100644 --- a/libc/calls/sched_getaffinity.c +++ b/libc/calls/sched_getaffinity.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/str/str.h" /** diff --git a/libc/calls/sched_setaffinity.c b/libc/calls/sched_setaffinity.c index 99d6db694..3d917e045 100644 --- a/libc/calls/sched_setaffinity.c +++ b/libc/calls/sched_setaffinity.c @@ -18,8 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/limits.h" #include "libc/nt/enum/processaccess.h" diff --git a/libc/calls/setgid.c b/libc/calls/setgid.c index 93431f3a4..35cbe11f8 100644 --- a/libc/calls/setgid.c +++ b/libc/calls/setgid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Sets group id of current process. diff --git a/libc/calls/setitimer-nt.c b/libc/calls/setitimer-nt.c index 52272b2e2..32e8e4fa4 100644 --- a/libc/calls/setitimer-nt.c +++ b/libc/calls/setitimer-nt.c @@ -19,7 +19,6 @@ #include "libc/assert.h" #include "libc/bits/bits.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/itimerval.h" @@ -81,7 +80,13 @@ textwindows void _check_sigalrm(void) { textwindows int sys_setitimer_nt(int which, const struct itimerval *newvalue, struct itimerval *out_opt_oldvalue) { long double elapsed, untilnext; - if (which != ITIMER_REAL) return einval(); + if (which != ITIMER_REAL || + (newvalue && (!(0 <= newvalue->it_value.tv_usec && + newvalue->it_value.tv_usec < 1000000) || + !(0 <= newvalue->it_interval.tv_usec && + newvalue->it_interval.tv_usec < 1000000)))) { + return einval(); + } if (out_opt_oldvalue) { if (__hastimer) { elapsed = nowl() - __lastalrm; diff --git a/libc/calls/setpgid.c b/libc/calls/setpgid.c index 36a2aad4c..24f6591fd 100644 --- a/libc/calls/setpgid.c +++ b/libc/calls/setpgid.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/nt/console.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/setpriority-nt.c b/libc/calls/setpriority-nt.c index cb762d0eb..aadb52c2e 100644 --- a/libc/calls/setpriority-nt.c +++ b/libc/calls/setpriority-nt.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/safemacros.internal.h" -#include "libc/calls/internal.h" #include "libc/calls/kntprioritycombos.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" #include "libc/nt/thread.h" diff --git a/libc/calls/setpriority.c b/libc/calls/setpriority.c index 682e62e54..10d8bd26a 100644 --- a/libc/calls/setpriority.c +++ b/libc/calls/setpriority.c @@ -17,7 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Sets nice value of thing. diff --git a/libc/calls/setregid.c b/libc/calls/setregid.c index e2ee4dc94..0134b45f6 100644 --- a/libc/calls/setregid.c +++ b/libc/calls/setregid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Sets real and/or effective group ids. diff --git a/libc/calls/setresgid.c b/libc/calls/setresgid.c index 846df7a93..04601eccd 100644 --- a/libc/calls/setresgid.c +++ b/libc/calls/setresgid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Sets real, effective, and "saved" group ids. diff --git a/libc/calls/setresuid.c b/libc/calls/setresuid.c index a585dc91c..8e05da8cf 100644 --- a/libc/calls/setresuid.c +++ b/libc/calls/setresuid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Sets real, effective, and "saved" user ids. diff --git a/libc/calls/setreuid.c b/libc/calls/setreuid.c index e3ff17143..9e9e4f14c 100644 --- a/libc/calls/setreuid.c +++ b/libc/calls/setreuid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Sets real and/or effective user ids. diff --git a/libc/calls/setsid.c b/libc/calls/setsid.c index adcfff21b..c63b255cf 100644 --- a/libc/calls/setsid.c +++ b/libc/calls/setsid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Creates session and sets the process group id. diff --git a/libc/calls/setuid.c b/libc/calls/setuid.c index f46735559..abaa567b8 100644 --- a/libc/calls/setuid.c +++ b/libc/calls/setuid.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Sets user id of current process. diff --git a/libc/calls/sig.c b/libc/calls/sig.c index 5412f0bf5..9c8717b6d 100644 --- a/libc/calls/sig.c +++ b/libc/calls/sig.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" +#include "libc/calls/state.internal.h" #include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/sysv/consts/sig.h" diff --git a/libc/calls/sig2.c b/libc/calls/sig2.c index 45626eff3..2aba4946f 100644 --- a/libc/calls/sig2.c +++ b/libc/calls/sig2.c @@ -16,12 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/sigbits.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/intrin/cmpxchg.h" +#include "libc/intrin/lockcmpxchg.h" #include "libc/intrin/spinlock.h" +#include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" @@ -90,8 +92,8 @@ static textwindows struct Signal *__sig_remove(void) { * @note called from main thread * @return true if EINTR should be returned by caller */ -static textwindows bool __sig_deliver(bool restartable, int sig, int si_code, - ucontext_t *ctx) { +static privileged bool __sig_deliver(bool restartable, int sig, int si_code, + ucontext_t *ctx) { unsigned rva, flags; siginfo_t info, *infop; STRACE("delivering %G", sig); @@ -113,7 +115,7 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code, // setup the somewhat expensive information args // only if they're requested by the user in sigaction() if (flags & SA_SIGINFO) { - bzero(&info, sizeof(info)); + __repstosb(&info, 0, sizeof(info)); info.si_signo = sig; info.si_code = si_code; infop = &info; @@ -130,9 +132,7 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code, // since sigaction() is @asyncsignalsafe we only restore it if the // user didn't change it during the signal handler. we also don't // need to do anything if this was a oneshot signal or nodefer. - _spinlock(&__sig_lock); - _cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva); - _spunlock(&__sig_lock); + _lockcmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva); } if (!restartable) { @@ -162,8 +162,8 @@ static textwindows bool __sig_isfatal(int sig) { * @param restartable can be used to suppress true return if SA_RESTART * @return true if signal was delivered */ -textwindows bool __sig_handle(bool restartable, int sig, int si_code, - ucontext_t *ctx) { +privileged bool __sig_handle(bool restartable, int sig, int si_code, + ucontext_t *ctx) { bool delivered; switch (__sighandrvas[sig]) { case (intptr_t)SIG_DFL: diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index eb36e030d..0270839d6 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -22,6 +22,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/sigbits.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/sigaction-linux.internal.h" @@ -29,6 +30,8 @@ #include "libc/calls/struct/sigaction-openbsd.internal.h" #include "libc/calls/struct/sigaction-xnu.internal.h" #include "libc/calls/struct/sigaction.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/ucontext.h" #include "libc/dce.h" @@ -223,7 +226,6 @@ static int __sigaction(int sig, const struct sigaction *act, rc = 0; } if (rc != -1 && !__vforked) { - _spinlock(&__sig_lock); if (oldact) { oldrva = __sighandrvas[sig]; oldact->sa_sigaction = (sigaction_f)( @@ -233,7 +235,6 @@ static int __sigaction(int sig, const struct sigaction *act, __sighandrvas[sig] = rva; __sighandflags[sig] = act->sa_flags; } - _spunlock(&__sig_lock); } return rc; } @@ -447,7 +448,9 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) { if (sig == SIGKILL || sig == SIGSTOP) { rc = einval(); } else { + _spinlock(&__sig_lock); rc = __sigaction(sig, act, oldact); + _spunlock(&__sig_lock); } STRACE("sigaction(%G, %s, [%s]) → %d% m", sig, DescribeSigaction(buf[0], sizeof(buf[0]), 0, act), diff --git a/libc/calls/sigaltstack.c b/libc/calls/sigaltstack.c index 3f2a74eb0..d150d27ac 100644 --- a/libc/calls/sigaltstack.c +++ b/libc/calls/sigaltstack.c @@ -16,16 +16,17 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/metasigaltstack.h" #include "libc/calls/struct/sigaltstack.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/describeflags.internal.h" #include "libc/sysv/errfuns.h" -static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd, - const struct sigaltstack *linux) { +static void sigaltstack2bsd(struct sigaltstack_bsd *bsd, + const struct sigaltstack *linux) { void *sp; int flags; size_t size; @@ -37,8 +38,8 @@ static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd, bsd->ss_size = size; } -static noasan void sigaltstack2linux(struct sigaltstack *linux, - const struct sigaltstack_bsd *bsd) { +static void sigaltstack2linux(struct sigaltstack *linux, + const struct sigaltstack_bsd *bsd) { void *sp; int flags; size_t size; @@ -56,8 +57,9 @@ static noasan void sigaltstack2linux(struct sigaltstack *linux, * struct sigaction sa; * struct sigaltstack ss; * ss.ss_flags = 0; - * ss.ss_size = SIGSTKSZ; - * ss.ss_sp = malloc(ss.ss_size); + * ss.ss_size = GetStackSize(); + * ss.ss_sp = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, + * MAP_STACK | MAP_ANONYMOUS, -1, 0); * sa.sa_flags = SA_ONSTACK; * sa.sa_handler = OnStackOverflow; * __cxa_atexit(free, ss[0].ss_sp, 0); @@ -65,14 +67,20 @@ static noasan void sigaltstack2linux(struct sigaltstack *linux, * sigaltstack(&ss, 0); * sigaction(SIGSEGV, &sa, 0); * + * It's strongly recommended that you allocate a stack with the same + * size as GetStackSize() and that it have GetStackSize() alignment. + * Otherwise some of your runtime support code (e.g. ftrace stack use + * logging, kprintf() memory safety) won't be able to work as well. + * * @param neu if non-null will install new signal alt stack * @param old if non-null will receive current signal alt stack * @return 0 on success, or -1 w/ errno */ -noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) { +int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) { int rc; void *b; const void *a; + char buf[2][128]; struct sigaltstack_bsd bsd; if (IsAsan() && ((old && __asan_check(old, sizeof(*old)).kind) || (neu && (__asan_check(neu, sizeof(*neu)).kind || @@ -106,6 +114,8 @@ noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) { } else { rc = enosys(); } - STRACE("sigaltstack() → %d% m", rc); + STRACE("sigaltstack(%s, [%s]) → %d% m", + DescribeSigaltstk(buf[0], sizeof(buf[0]), 0, neu), + DescribeSigaltstk(buf[0], sizeof(buf[0]), 0, old), rc); return rc; } diff --git a/libc/calls/sigchld-nt.c b/libc/calls/sigchld-nt.c index 6d8b7a073..14c278bcc 100644 --- a/libc/calls/sigchld-nt.c +++ b/libc/calls/sigchld-nt.c @@ -19,8 +19,11 @@ #include "libc/assert.h" #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" +#include "libc/intrin/spinlock.h" #include "libc/nt/enum/wait.h" #include "libc/nt/runtime.h" #include "libc/nt/synchronization.h" @@ -38,7 +41,10 @@ void _check_sigchld(void) { int pids[64]; uint32_t i, n; int64_t handles[64]; - if (!(n = __sample_pids(pids, handles, true))) return; + _spinlock(&__fds_lock); + n = __sample_pids(pids, handles, true); + _spunlock(&__fds_lock); + if (!n) return; i = WaitForMultipleObjects(n, handles, false, 0); if (i == kNtWaitTimeout) return; if (i == kNtWaitFailed) { @@ -55,6 +61,8 @@ void _check_sigchld(void) { CloseHandle(handles[i]); __releasefd(pids[i]); } + _spinlock(&__fds_lock); g_fds.p[pids[i]].zombie = true; + _spunlock(&__fds_lock); __sig_add(SIGCHLD, CLD_EXITED); } diff --git a/libc/calls/sigenter-freebsd.c b/libc/calls/sigenter-freebsd.c index 352d3f5d8..4bc1d2aa9 100644 --- a/libc/calls/sigenter-freebsd.c +++ b/libc/calls/sigenter-freebsd.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/siginfo-freebsd.internal.h" #include "libc/calls/struct/siginfo.h" @@ -25,13 +26,13 @@ #include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/ucontext.h" #include "libc/intrin/kprintf.h" -#include "libc/intrin/repstosb.h" +#include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/sa.h" -void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo, - struct ucontext_freebsd *ctx) { +privileged void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo, + struct ucontext_freebsd *ctx) { int rva, flags; struct Goodies { ucontext_t uc; @@ -43,14 +44,14 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo, if (~flags & SA_SIGINFO) { ((sigaction_f)(_base + rva))(sig, 0, 0); } else { - repstosb(&g, 0, sizeof(g)); + __repstosb(&g, 0, sizeof(g)); g.uc.uc_mcontext.fpregs = &g.uc.__fpustate; g.uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp; g.uc.uc_stack.ss_size = ctx->uc_stack.ss_size; g.uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags; g.uc.uc_flags = ctx->uc_flags; - memcpy(&g.uc.uc_sigmask, &ctx->uc_sigmask, - MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask))); + __repmovsb(&g.uc.uc_sigmask, &ctx->uc_sigmask, + MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask))); g.uc.uc_mcontext.r8 = ctx->uc_mcontext.mc_r8; g.uc.uc_mcontext.r9 = ctx->uc_mcontext.mc_r9; g.uc.uc_mcontext.r10 = ctx->uc_mcontext.mc_r10; @@ -73,7 +74,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo, g.uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs; g.uc.uc_mcontext.err = ctx->uc_mcontext.mc_err; g.uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno; - memcpy(&g.uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512); + __repmovsb(&g.uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512); g.si.si_signo = freebsdinfo->si_signo; g.si.si_errno = freebsdinfo->si_errno; g.si.si_code = freebsdinfo->si_code; @@ -89,8 +90,8 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo, ctx->uc_stack.ss_size = g.uc.uc_stack.ss_size; ctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags; ctx->uc_flags = g.uc.uc_flags; - memcpy(&ctx->uc_sigmask, &g.uc.uc_sigmask, - MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask))); + __repmovsb(&ctx->uc_sigmask, &g.uc.uc_sigmask, + MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask))); ctx->uc_mcontext.mc_rdi = g.uc.uc_mcontext.rdi; ctx->uc_mcontext.mc_rsi = g.uc.uc_mcontext.rsi; ctx->uc_mcontext.mc_rdx = g.uc.uc_mcontext.rdx; @@ -113,7 +114,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo, ctx->uc_mcontext.mc_err = g.uc.uc_mcontext.err; ctx->uc_mcontext.mc_rip = g.uc.uc_mcontext.rip; ctx->uc_mcontext.mc_rsp = g.uc.uc_mcontext.rsp; - memcpy(&ctx->uc_mcontext.mc_fpstate, &g.uc.__fpustate, 512); + __repmovsb(&ctx->uc_mcontext.mc_fpstate, &g.uc.__fpustate, 512); } } /* diff --git a/libc/calls/sigenter-netbsd.c b/libc/calls/sigenter-netbsd.c index 0d2595a96..b1531596c 100644 --- a/libc/calls/sigenter-netbsd.c +++ b/libc/calls/sigenter-netbsd.c @@ -18,18 +18,20 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/siginfo-netbsd.internal.h" #include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/ucontext-netbsd.internal.h" #include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/ucontext.h" +#include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/sa.h" -void __sigenter_netbsd(int sig, struct siginfo_netbsd *si, - struct ucontext_netbsd *ctx) { +privileged void __sigenter_netbsd(int sig, struct siginfo_netbsd *si, + struct ucontext_netbsd *ctx) { int rva, flags; ucontext_t uc; struct siginfo si2; @@ -39,8 +41,8 @@ void __sigenter_netbsd(int sig, struct siginfo_netbsd *si, if (~flags & SA_SIGINFO) { ((sigaction_f)(_base + rva))(sig, 0, 0); } else { - bzero(&uc, sizeof(uc)); - bzero(&si2, sizeof(si2)); + __repstosb(&uc, 0, sizeof(uc)); + __repstosb(&si2, 0, sizeof(si2)); si2.si_signo = si->si_signo; si2.si_code = si->si_code; si2.si_errno = si->si_errno; @@ -52,8 +54,8 @@ void __sigenter_netbsd(int sig, struct siginfo_netbsd *si, uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp; uc.uc_stack.ss_size = ctx->uc_stack.ss_size; uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags; - memcpy(&uc.uc_sigmask, &ctx->uc_sigmask, - MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask))); + __repmovsb(&uc.uc_sigmask, &ctx->uc_sigmask, + MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask))); uc.uc_mcontext.rdi = ctx->uc_mcontext.rdi; uc.uc_mcontext.rsi = ctx->uc_mcontext.rsi; uc.uc_mcontext.rdx = ctx->uc_mcontext.rdx; diff --git a/libc/calls/sigenter-openbsd.c b/libc/calls/sigenter-openbsd.c index 78a1dc0aa..cd503f4de 100644 --- a/libc/calls/sigenter-openbsd.c +++ b/libc/calls/sigenter-openbsd.c @@ -18,19 +18,20 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/siginfo-openbsd.internal.h" #include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/ucontext-openbsd.internal.h" #include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/ucontext.h" -#include "libc/intrin/repstosb.h" +#include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/sa.h" -void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo, - struct ucontext_openbsd *ctx) { +privileged void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo, + struct ucontext_openbsd *ctx) { int rva, flags; struct Goodies { ucontext_t uc; @@ -42,7 +43,7 @@ void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo, if (~flags & SA_SIGINFO) { ((sigaction_f)(_base + rva))(sig, 0, 0); } else { - repstosb(&g, 0, sizeof(g)); + __repstosb(&g, 0, sizeof(g)); g.si.si_signo = openbsdinfo->si_signo; g.si.si_code = openbsdinfo->si_code; g.si.si_errno = openbsdinfo->si_errno; @@ -54,8 +55,8 @@ void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo, } g.si.si_value = openbsdinfo->si_value; g.uc.uc_mcontext.fpregs = &g.uc.__fpustate; - memcpy(&g.uc.uc_sigmask, &ctx->sc_mask, - MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask))); + __repmovsb(&g.uc.uc_sigmask, &ctx->sc_mask, + MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask))); g.uc.uc_mcontext.rdi = ctx->sc_rdi; g.uc.uc_mcontext.rsi = ctx->sc_rsi; g.uc.uc_mcontext.rdx = ctx->sc_rdx; diff --git a/libc/calls/sigenter-xnu.c b/libc/calls/sigenter-xnu.c index 4065ab3ce..03fdc9a97 100644 --- a/libc/calls/sigenter-xnu.c +++ b/libc/calls/sigenter-xnu.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/struct/metasigaltstack.h" #include "libc/calls/struct/siginfo-xnu.internal.h" #include "libc/calls/struct/siginfo.h" @@ -25,6 +26,7 @@ #include "libc/calls/ucontext.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/repstosb.h" +#include "libc/log/libfatal.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/sa.h" @@ -355,19 +357,19 @@ struct __darwin_ucontext { struct __darwin_mcontext64 *uc_mcontext; }; -noasan static void xnuexceptionstate2linux( +static privileged void xnuexceptionstate2linux( mcontext_t *mc, struct __darwin_x86_exception_state64 *xnues) { mc->trapno = xnues->__trapno; mc->err = xnues->__err; } -noasan static void linuxexceptionstate2xnu( +static privileged void linuxexceptionstate2xnu( struct __darwin_x86_exception_state64 *xnues, mcontext_t *mc) { xnues->__trapno = mc->trapno; xnues->__err = mc->err; } -noasan static void xnuthreadstate2linux( +static privileged void xnuthreadstate2linux( mcontext_t *mc, struct __darwin_x86_thread_state64 *xnuss) { mc->rdi = xnuss->__rdi; mc->rsi = xnuss->__rsi; @@ -392,7 +394,7 @@ noasan static void xnuthreadstate2linux( mc->r15 = xnuss->__r15; } -noasan static void linuxthreadstate2xnu( +static privileged void linuxthreadstate2xnu( struct __darwin_x86_thread_state64 *xnuss, ucontext_t *uc, mcontext_t *mc) { xnuss->__rdi = mc->rdi; xnuss->__rsi = mc->rsi; @@ -417,14 +419,14 @@ noasan static void linuxthreadstate2xnu( xnuss->__r15 = mc->r15; } -noasan static void CopyFpXmmRegs(void *d, const void *s) { +static privileged void CopyFpXmmRegs(void *d, const void *s) { size_t i; for (i = 0; i < (8 + 16) * 16; i += 16) { __builtin_memcpy((char *)d + i, (const char *)s + i, 16); } } -noasan static void xnussefpustate2linux( +static privileged void xnussefpustate2linux( struct FpuState *fs, struct __darwin_x86_float_state64 *xnufs) { fs->cwd = xnufs->__fpu_fcw; fs->swd = xnufs->__fpu_fsw; @@ -437,7 +439,7 @@ noasan static void xnussefpustate2linux( CopyFpXmmRegs(fs->st, &xnufs->__fpu_stmm0); } -noasan static void linuxssefpustate2xnu( +static privileged void linuxssefpustate2xnu( struct __darwin_x86_float_state64 *xnufs, struct FpuState *fs) { xnufs->__fpu_fcw = fs->cwd; xnufs->__fpu_fsw = fs->swd; @@ -450,9 +452,9 @@ noasan static void linuxssefpustate2xnu( CopyFpXmmRegs(&xnufs->__fpu_stmm0, fs->st); } -noasan void __sigenter_xnu(void *fn, int infostyle, int sig, - struct siginfo_xnu *xnuinfo, - struct __darwin_ucontext *xnuctx) { +privileged void __sigenter_xnu(void *fn, int infostyle, int sig, + struct siginfo_xnu *xnuinfo, + struct __darwin_ucontext *xnuctx) { intptr_t ax; int rva, flags; struct Goodies { @@ -465,7 +467,7 @@ noasan void __sigenter_xnu(void *fn, int infostyle, int sig, if (~flags & SA_SIGINFO) { ((sigaction_f)(_base + rva))(sig, 0, 0); } else { - repstosb(&g, 0, sizeof(g)); + __repstosb(&g, 0, sizeof(g)); if (xnuctx) { g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0; g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask; diff --git a/libc/calls/sigprocmask-sysv.c b/libc/calls/sigprocmask-sysv.greg.c similarity index 98% rename from libc/calls/sigprocmask-sysv.c rename to libc/calls/sigprocmask-sysv.greg.c index 7f6ce2b41..625808d8e 100644 --- a/libc/calls/sigprocmask-sysv.c +++ b/libc/calls/sigprocmask-sysv.greg.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/sigset.h" int sys_sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) { diff --git a/libc/calls/sleep.c b/libc/calls/sleep.c index 19810c82f..f4dea02a5 100644 --- a/libc/calls/sleep.c +++ b/libc/calls/sleep.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/splice.c b/libc/calls/splice.c index 08cf2d8fc..35f8a0710 100644 --- a/libc/calls/splice.c +++ b/libc/calls/splice.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/stat2cosmo.c b/libc/calls/stat2cosmo.c index c4e28281e..4d5e3e850 100644 --- a/libc/calls/stat2cosmo.c +++ b/libc/calls/stat2cosmo.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/struct/metastat.internal.h" #include "libc/dce.h" diff --git a/libc/calls/state.internal.h b/libc/calls/state.internal.h new file mode 100644 index 000000000..b7a14781f --- /dev/null +++ b/libc/calls/state.internal.h @@ -0,0 +1,16 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +hidden extern int __vforked; +hidden extern int __fds_lock; +hidden extern int __sig_lock; +hidden extern bool __time_critical; +hidden extern unsigned __sighandrvas[NSIG]; +hidden extern unsigned __sighandflags[NSIG]; +hidden extern const struct NtSecurityAttributes kNtIsInheritable; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_STATE_INTERNAL_H_ */ diff --git a/libc/calls/strace.internal.h b/libc/calls/strace.internal.h index 1051c0044..5cd8e5c91 100644 --- a/libc/calls/strace.internal.h +++ b/libc/calls/strace.internal.h @@ -4,13 +4,14 @@ #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" +#include "libc/runtime/runtime.h" #define _KERNTRACE 0 /* not configurable w/ flag yet */ #define _POLLTRACE 0 /* not configurable w/ flag yet */ #define _DATATRACE 1 /* not configurable w/ flag yet */ #define _NTTRACE 0 /* not configurable w/ flag yet */ -#define STRACE_PROLOGUE "%rSYS %5P %'18T " +#define STRACE_PROLOGUE "%rSYS %6P %'18T " #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -50,8 +51,6 @@ COSMOPOLITAN_C_START_ #define NTTRACE(FMT, ...) (void)0 #endif -extern int __strace; - void __stracef(const char *, ...); COSMOPOLITAN_C_END_ diff --git a/libc/calls/symlinkat-nt.c b/libc/calls/symlinkat-nt.c index 1cbcc3907..ad5149afa 100644 --- a/libc/calls/symlinkat-nt.c +++ b/libc/calls/symlinkat-nt.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/errno.h" #include "libc/intrin/once.h" #include "libc/intrin/spinlock.h" diff --git a/libc/calls/symlinkat.c b/libc/calls/symlinkat.c index de4540654..cfc877f2d 100644 --- a/libc/calls/symlinkat.c +++ b/libc/calls/symlinkat.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" diff --git a/libc/calls/sync-nt.c b/libc/calls/sync-nt.c index 31dbc395b..4657e92d4 100644 --- a/libc/calls/sync-nt.c +++ b/libc/calls/sync-nt.c @@ -18,6 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/creationdisposition.h" diff --git a/libc/calls/sync.c b/libc/calls/sync.c index 231ae339f..9586a1b43 100644 --- a/libc/calls/sync.c +++ b/libc/calls/sync.c @@ -17,16 +17,24 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** * Flushes file system changes to disk by any means necessary. + * @see __nosync to secretly disable */ void sync(void) { - if (!IsWindows()) { - sys_sync(); + if (__nosync != 0x5453455454534146) { + if (!IsWindows()) { + sys_sync(); + } else { + sys_sync_nt(); + } + STRACE("sync()% m"); } else { - sys_sync_nt(); + STRACE("sync() → disabled% m"); } } diff --git a/libc/calls/sync_file_range.c b/libc/calls/sync_file_range.c index 54110b570..5c020e472 100644 --- a/libc/calls/sync_file_range.c +++ b/libc/calls/sync_file_range.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/errno.h" /** diff --git a/libc/calls/sys_utimes_nt.c b/libc/calls/sys_utimes_nt.c index 8a7638a14..225ecd90d 100644 --- a/libc/calls/sys_utimes_nt.c +++ b/libc/calls/sys_utimes_nt.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/timeval.h" #include "libc/sysv/consts/at.h" textwindows int sys_utimes_nt(const char *path, const struct timeval tv[2]) { diff --git a/libc/calls/syscall-nt.internal.h b/libc/calls/syscall-nt.internal.h new file mode 100644 index 000000000..51bba6286 --- /dev/null +++ b/libc/calls/syscall-nt.internal.h @@ -0,0 +1,43 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +bool32 sys_isatty_nt(int) hidden; +char *sys_getcwd_nt(char *, size_t) hidden; +int sys_chdir_nt(const char *) hidden; +int sys_close_epoll_nt(int) hidden; +int sys_dup_nt(int, int, int, int) hidden; +int sys_execve_nt(const char *, char *const[], char *const[]) hidden; +int sys_faccessat_nt(int, const char *, int, uint32_t) hidden; +int sys_fadvise_nt(int, uint64_t, uint64_t, int) hidden; +int sys_fchdir_nt(int) hidden; +int sys_fchmodat_nt(int, const char *, uint32_t, int) hidden; +int sys_fcntl_nt(int, int, uintptr_t) hidden; +int sys_fdatasync_nt(int) hidden; +int sys_flock_nt(int, int) hidden; +int sys_fork_nt(void) hidden; +int sys_ftruncate_nt(int64_t, uint64_t) hidden; +int sys_getppid_nt(void) hidden; +int sys_getpriority_nt(int) hidden; +int sys_getsetpriority_nt(int, int, int, int (*)(int)); +int sys_kill_nt(int, int) hidden; +int sys_linkat_nt(int, const char *, int, const char *) hidden; +int sys_madvise_nt(void *, size_t, int) hidden; +int sys_mkdirat_nt(int, const char *, uint32_t) hidden; +int sys_msync_nt(char *, size_t, int) hidden; +int sys_open_nt(int, const char *, uint32_t, int32_t) dontdiscard hidden; +int sys_pipe_nt(int[hasatleast 2], unsigned) hidden; +int sys_renameat_nt(int, const char *, int, const char *) hidden; +int sys_sched_yield_nt(void) hidden; +int sys_setpriority_nt(int) hidden; +int sys_symlinkat_nt(const char *, int, const char *) hidden; +int sys_sync_nt(void) hidden; +int sys_truncate_nt(const char *, uint64_t) hidden; +int sys_unlinkat_nt(int, const char *, int) hidden; +int64_t sys_lseek_nt(int, int64_t, int) hidden; +ssize_t sys_readlinkat_nt(int, const char *, char *, size_t) hidden; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALL_NT_INTERNAL_H_ */ diff --git a/libc/calls/syscall-sysv.internal.h b/libc/calls/syscall-sysv.internal.h new file mode 100644 index 000000000..b73fc3b50 --- /dev/null +++ b/libc/calls/syscall-sysv.internal.h @@ -0,0 +1,124 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_SYSCALL_SYSV_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_SYSCALL_SYSV_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ +#define i32 int32_t +#define i64 int64_t +#define u32 uint32_t +#define u64 uint64_t +/*───────────────────────────────────────────────────────────────────────────│─╗ +│ cosmopolitan § syscalls » system five » structless synthetic jump slots ─╬─│┼ +╚────────────────────────────────────────────────────────────────────────────│*/ + +axdx_t __sys_pipe(i32[hasatleast 2], i32) hidden; +axdx_t sys_fork(void) hidden; +axdx_t sys_getpid(void) hidden; +char *sys_getcwd(char *, u64) hidden; +char *sys_getcwd_xnu(char *, u64) hidden; +i32 __sys_dup3(i32, i32, i32) hidden; +i32 __sys_execve(const char *, char *const[], char *const[]) hidden; +i32 __sys_fcntl(i32, i32, ...) hidden; +i32 __sys_fstat(i32, void *) hidden; +i32 __sys_fstatat(i32, const char *, void *, i32) hidden; +i32 __sys_munmap(void *, u64) hidden; +i32 __sys_openat(i32, const char *, i32, u32) hidden; +i32 __sys_pipe2(i32[hasatleast 2], u32) hidden; +i32 sys_arch_prctl(i32, i64) hidden; +i32 sys_chdir(const char *) hidden; +i32 sys_chroot(const char *) hidden; +i32 sys_close(i32) hidden; +i32 sys_dup(i32) hidden; +i32 sys_dup2(i32, i32) hidden; +i32 sys_dup3(i32, i32, i32) hidden; +i32 sys_execve(const char *, char *const[], char *const[]) hidden; +i32 sys_faccessat(i32, const char *, i32, u32) hidden; +i32 sys_fadvise(i32, i64, i64, i32) hidden; +i32 sys_fchdir(i32) hidden; +i32 sys_fchmod(i32, u32) hidden; +i32 sys_fchmodat(i32, const char *, u32, u32) hidden; +i32 sys_fchown(i64, u32, u32) hidden; +i32 sys_fchownat(i32, const char *, u32, u32, u32) hidden; +i32 sys_fcntl(i32, i32, u64) hidden; +i32 sys_fdatasync(i32) hidden; +i32 sys_flock(i32, i32) hidden; +i32 sys_fsync(i32) hidden; +i32 sys_ftruncate(i32, i64, i64) hidden; +i32 sys_getcontext(void *) hidden; +i32 sys_getpgid(i32) hidden; +i32 sys_getpgrp(void) hidden; +i32 sys_getppid(void) hidden; +i32 sys_getpriority(i32, u32) hidden; +i32 sys_getresgid(u32 *, u32 *, u32 *); +i32 sys_getresuid(u32 *, u32 *, u32 *); +i32 sys_getsid(int) hidden; +i32 sys_ioctl(i32, u64, ...) hidden; +i32 sys_kill(i32, i32, i32) hidden; +i32 sys_linkat(i32, const char *, i32, const char *, i32) hidden; +i32 sys_lseek(i32, i64, i64, i64) hidden; +i32 sys_madvise(void *, size_t, i32) hidden; +i32 sys_memfd_create(const char *, u32) hidden; +i32 sys_mincore(void *, u64, unsigned char *) hidden; +i32 sys_mkdirat(i32, const char *, u32) hidden; +i32 sys_mkfifo(const char *, u32) hidden; +i32 sys_mknod(const char *, u32, u64) hidden; +i32 sys_mprotect(void *, u64, i32) hidden; +i32 sys_msync(void *, u64, i32) hidden; +i32 sys_munmap(void *, u64) hidden; +i32 sys_open(const char *, i32, u32) hidden; +i32 sys_openat(i32, const char *, i32, u32) hidden; +i32 sys_pause(void) hidden; +i32 sys_pipe(i32[hasatleast 2]) hidden; +i32 sys_pipe2(i32[hasatleast 2], u32) hidden; +i32 sys_pledge(const char *, const char *) hidden; +i32 sys_posix_openpt(i32) hidden; +i32 sys_renameat(i32, const char *, i32, const char *) hidden; +i32 sys_sched_setaffinity(i32, u64, const void *) hidden; +i32 sys_sched_yield(void) hidden; +i32 sys_setgid(i32) hidden; +i32 sys_setpgid(i32, i32) hidden; +i32 sys_setpriority(i32, u32, i32) hidden; +i32 sys_setregid(u32, u32) hidden; +i32 sys_setresgid(u32, u32, u32) hidden; +i32 sys_setresuid(u32, u32, u32) hidden; +i32 sys_setreuid(u32, u32) hidden; +i32 sys_setsid(void) hidden; +i32 sys_setuid(i32) hidden; +i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden; +i32 sys_sigaltstack(const void *, void *) hidden; +i32 sys_symlinkat(const char *, i32, const char *) hidden; +i32 sys_sync(void) hidden; +i32 sys_sync_file_range(i32, i64, i64, u32) hidden; +i32 sys_tgkill(i32, i32, i32) hidden; +i32 sys_tkill(i32, i32, void *) hidden; +i32 sys_truncate(const char *, u64, u64) hidden; +i32 sys_uname(char *) hidden; +i32 sys_unlinkat(i32, const char *, i32) hidden; +i64 sys_copy_file_range(i32, long *, i32, long *, u64, u32) hidden; +i64 sys_getrandom(void *, u64, u32) hidden; +i64 sys_pread(i32, void *, u64, i64, i64) hidden; +i64 sys_ptrace(int, i32, void *, void *) hidden; +i64 sys_pwrite(i32, const void *, u64, i64, i64) hidden; +i64 sys_read(i32, void *, u64) hidden; +i64 sys_readlink(const char *, char *, u64) hidden; +i64 sys_readlinkat(int, const char *, char *, u64) hidden; +i64 sys_sched_getaffinity(i32, u64, void *) hidden; +i64 sys_sendfile(i32, i32, i64 *, u64) hidden; +i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden; +i64 sys_write(i32, const void *, u64) hidden; +u32 sys_getegid(void) hidden; +u32 sys_geteuid(void) hidden; +u32 sys_getgid(void) hidden; +u32 sys_gettid(void) hidden; +u32 sys_getuid(void) hidden; +u32 sys_umask(u32) hidden; +void *__sys_mmap(void *, u64, u32, u32, i64, i64, i64) hidden; +void *sys_mremap(void *, u64, u64, i32, void *) hidden; +void sys_exit(int) hidden; + +#undef i32 +#undef i64 +#undef u32 +#undef u64 +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALL_SYSV_INTERNAL_H_ */ diff --git a/libc/calls/syscall_support-nt.internal.h b/libc/calls/syscall_support-nt.internal.h new file mode 100644 index 000000000..d4beaee79 --- /dev/null +++ b/libc/calls/syscall_support-nt.internal.h @@ -0,0 +1,27 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_NT_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_NT_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +bool isdirectory_nt(const char *) hidden; +bool isregularfile_nt(const char *) hidden; +bool issymlink_nt(const char *) hidden; +bool32 ntsetprivilege(int64_t, const char16_t *, uint32_t) hidden; +char16_t *CreatePipeName(char16_t *) hidden; +int __mkntpath(const char *, char16_t[hasatleast PATH_MAX]) hidden; +int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX], int) hidden; +int __mkntpathat(int, const char *, int, char16_t[hasatleast PATH_MAX]) hidden; +int __sample_pids(int[hasatleast 64], int64_t[hasatleast 64], bool) hidden; +int ntaccesscheck(const char16_t *, uint32_t) paramsnonnull() hidden; +int64_t __fix_enotdir(int64_t, char16_t *) hidden; +int64_t __fix_enotdir3(int64_t, char16_t *, char16_t *) hidden; +int64_t __winerr(void) nocallback privileged; +int64_t ntreturn(uint32_t); +void *GetProcAddressModule(const char *, const char *) hidden; +void WinMainForked(void) hidden; +void _check_sigalrm(void) hidden; +void _check_sigchld(void) hidden; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_NT_INTERNAL_H_ */ diff --git a/libc/calls/syscall_support-sysv.internal.h b/libc/calls/syscall_support-sysv.internal.h new file mode 100644 index 000000000..3312ca2b3 --- /dev/null +++ b/libc/calls/syscall_support-sysv.internal.h @@ -0,0 +1,24 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_SYSV_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_SYSV_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ +/*───────────────────────────────────────────────────────────────────────────│─╗ +│ cosmopolitan § syscalls » system five » structless support ─╬─│┼ +╚────────────────────────────────────────────────────────────────────────────│*/ + +bool __is_linux_2_6_23(void) hidden; +int __fixupnewfd(int, int) hidden; +int __notziposat(int, const char *); +int gethostname_bsd(char *, size_t) hidden; +int gethostname_linux(char *, size_t) hidden; +int gethostname_nt(char *, size_t, int) hidden; +void *__vdsosym(const char *, const char *) hidden; +void __onfork(void) hidden; +void __restore_rt() hidden; +void __restore_rt_netbsd(void) hidden; +void cosmo2flock(uintptr_t); +void flock2cosmo(uintptr_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALL_SUPPORT_SYSV_INTERNAL_H_ */ diff --git a/libc/calls/sysinfo-nt.c b/libc/calls/sysinfo-nt.c index 934d4fafc..2ee862ca9 100644 --- a/libc/calls/sysinfo-nt.c +++ b/libc/calls/sysinfo-nt.c @@ -16,9 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/loadavg.internal.h" #include "libc/calls/struct/sysinfo.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/accounting.h" #include "libc/nt/struct/memorystatusex.h" #include "libc/nt/struct/systeminfo.h" diff --git a/libc/calls/sysinfo.c b/libc/calls/sysinfo.c index 18b33083a..d04038f10 100644 --- a/libc/calls/sysinfo.c +++ b/libc/calls/sysinfo.c @@ -16,16 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/bits.h" -#include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/sysinfo.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" -#include "libc/nt/accounting.h" -#include "libc/nt/runtime.h" -#include "libc/nt/struct/memorystatusex.h" -#include "libc/nt/systeminfo.h" +#include "libc/macros.internal.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/tcdrain.c b/libc/calls/tcdrain.c index f6220eb98..c7ca74c3a 100644 --- a/libc/calls/tcdrain.c +++ b/libc/calls/tcdrain.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/termios.h" int tcdrain(int fd) { diff --git a/libc/calls/tcflow.c b/libc/calls/tcflow.c index 9468cafb3..ec1152d90 100644 --- a/libc/calls/tcflow.c +++ b/libc/calls/tcflow.c @@ -16,9 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/struct/termios.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" +#include "libc/dce.h" #include "libc/sysv/consts/termios.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/tcflush.c b/libc/calls/tcflush.c index fcef3676d..6229b6c68 100644 --- a/libc/calls/tcflush.c +++ b/libc/calls/tcflush.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" /** diff --git a/libc/calls/tcgetsid.c b/libc/calls/tcgetsid.c index 8bdbdc04c..d69a1aa6e 100644 --- a/libc/calls/tcgetsid.c +++ b/libc/calls/tcgetsid.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" #include "libc/sysv/consts/termios.h" diff --git a/libc/calls/tcsendbreak.c b/libc/calls/tcsendbreak.c index 2f8299a9d..8a9e5228f 100644 --- a/libc/calls/tcsendbreak.c +++ b/libc/calls/tcsendbreak.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" #include "libc/dce.h" #include "libc/sysv/consts/termios.h" diff --git a/libc/calls/tgkill.c b/libc/calls/tgkill.c index a729b4c6d..214be57e8 100644 --- a/libc/calls/tgkill.c +++ b/libc/calls/tgkill.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" /** * Kills thread group. diff --git a/libc/calls/timecritical.c b/libc/calls/timecritical.c index 7f32a4b50..8215b1eec 100644 --- a/libc/calls/timecritical.c +++ b/libc/calls/timecritical.c @@ -16,6 +16,5 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" bool __time_critical; diff --git a/libc/calls/tkill.c b/libc/calls/tkill.c index 69c9576ae..0d20432de 100644 --- a/libc/calls/tkill.c +++ b/libc/calls/tkill.c @@ -17,8 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/intrin/kprintf.h" #include "libc/nt/enum/threadaccess.h" diff --git a/libc/calls/truncate-nt.c b/libc/calls/truncate-nt.c index 29c0819b5..71f9c2f4f 100644 --- a/libc/calls/truncate-nt.c +++ b/libc/calls/truncate-nt.c @@ -16,7 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/creationdisposition.h" diff --git a/libc/calls/truncate.c b/libc/calls/truncate.c index a8c3f75f1..752116066 100644 --- a/libc/calls/truncate.c +++ b/libc/calls/truncate.c @@ -17,9 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" -#include "libc/sysv/errfuns.h" /** * Reduces or extends underlying physical medium of file. diff --git a/libc/calls/ttyname_r.c b/libc/calls/ttyname_r.c index fcef19b89..900895c48 100644 --- a/libc/calls/ttyname_r.c +++ b/libc/calls/ttyname_r.c @@ -21,6 +21,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/stat.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" diff --git a/libc/calls/umask.c b/libc/calls/umask.c index a6a439f8c..b1b932ecd 100644 --- a/libc/calls/umask.c +++ b/libc/calls/umask.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" /** diff --git a/libc/calls/uname.c b/libc/calls/uname.c index fa187db12..24f88ff51 100644 --- a/libc/calls/uname.c +++ b/libc/calls/uname.c @@ -18,9 +18,10 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/utsname.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/fmt/itoa.h" #include "libc/intrin/asan.internal.h" @@ -48,7 +49,7 @@ static inline textwindows noasan int NtGetBuildNumber(void) { * @return 0 on success, or -1 w/ errno */ int uname(struct utsname *lool) { - int rc, v; + int rc; char *out, *p; size_t i, j, len; char tmp[sizeof(struct utsname)]; @@ -87,7 +88,6 @@ int uname(struct utsname *lool) { rc = enosys(); } } else { - v = NtGetVersion(); p = lool->release; p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.'; p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-'; diff --git a/libc/calls/unlinkat-nt.c b/libc/calls/unlinkat-nt.c index 3b8555f03..370afe79e 100644 --- a/libc/calls/unlinkat-nt.c +++ b/libc/calls/unlinkat-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/errno.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" @@ -30,6 +30,7 @@ #include "libc/nt/struct/win32fileattributedata.h" #include "libc/nt/struct/win32finddata.h" #include "libc/nt/synchronization.h" +#include "libc/str/str.h" #include "libc/sysv/consts/at.h" /** diff --git a/libc/calls/unlinkat.c b/libc/calls/unlinkat.c index edc626d35..996bc6962 100644 --- a/libc/calls/unlinkat.c +++ b/libc/calls/unlinkat.c @@ -18,12 +18,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" -#include "libc/sysv/consts/at.h" #include "libc/sysv/errfuns.h" #include "libc/zipos/zipos.internal.h" diff --git a/libc/calls/usleep.c b/libc/calls/usleep.c index c51e26fcb..5160fb372 100644 --- a/libc/calls/usleep.c +++ b/libc/calls/usleep.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/timespec.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/utimensat-nt.c b/libc/calls/utimensat-nt.c index 0a5972cde..00b3e6d3d 100644 --- a/libc/calls/utimensat-nt.c +++ b/libc/calls/utimensat-nt.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/fmt/conv.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" diff --git a/libc/calls/utimensat.c b/libc/calls/utimensat.c index d4efa6aa2..c72ec739a 100644 --- a/libc/calls/utimensat.c +++ b/libc/calls/utimensat.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" +#include "libc/calls/asan.internal.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" @@ -39,7 +40,8 @@ int utimensat(int dirfd, const char *path, const struct timespec ts[2], int rc; char buf[12]; if (IsAsan() && (!__asan_is_valid(path, 1) || - (ts && !__asan_is_valid(ts, sizeof(struct timespec) * 2)))) { + (ts && (!__asan_is_valid_timespec(ts + 0) || + !__asan_is_valid_timespec(ts + 1))))) { rc = efault(); } else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { STRACE("zipos mkdirat not supported yet"); diff --git a/libc/calls/vdprintf.c b/libc/calls/vdprintf.c index cf4e92fdd..652d9b9dc 100644 --- a/libc/calls/vdprintf.c +++ b/libc/calls/vdprintf.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/iovec.h" #include "libc/dce.h" #include "libc/fmt/fmt.h" #include "libc/limits.h" diff --git a/libc/calls/vdsofunc.greg.c b/libc/calls/vdsofunc.greg.c index 843b45822..b54fd40e8 100644 --- a/libc/calls/vdsofunc.greg.c +++ b/libc/calls/vdsofunc.greg.c @@ -18,77 +18,136 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" #include "libc/elf/scalar.h" #include "libc/elf/struct/ehdr.h" +#include "libc/elf/struct/phdr.h" #include "libc/elf/struct/shdr.h" #include "libc/elf/struct/sym.h" -#include "libc/log/libfatal.internal.h" +#include "libc/elf/struct/verdaux.h" +#include "libc/elf/struct/verdef.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/auxv.h" -#define LAZY_RHEL7_RELOCATION 0xfffff - -#define GetStr(tab, rva) ((char *)(tab) + (rva)) -#define GetSection(e, s) ((void *)((intptr_t)(e) + (size_t)(s)->sh_offset)) -#define GetShstrtab(e) GetSection(e, GetShdr(e, (e)->e_shstrndx)) -#define GetSectionName(e, s) GetStr(GetShstrtab(e), (s)->sh_name) -#define GetPhdr(e, i) \ - ((Elf64_Phdr *)((intptr_t)(e) + (e)->e_phoff + \ - (size_t)(e)->e_phentsize * (i))) -#define GetShdr(e, i) \ - ((Elf64_Shdr *)((intptr_t)(e) + (e)->e_shoff + \ - (size_t)(e)->e_shentsize * (i))) - -static char *GetDynamicStringTable(Elf64_Ehdr *e, size_t *n) { - char *name; - Elf64_Half i; - Elf64_Shdr *shdr; - for (i = 0; i < e->e_shnum; ++i) { - shdr = GetShdr(e, i); - name = GetSectionName(e, GetShdr(e, i)); - if (shdr->sh_type == SHT_STRTAB) { - name = GetSectionName(e, GetShdr(e, i)); - if (name && READ64LE(name) == READ64LE(".dynstr")) { - if (n) *n = shdr->sh_size; - return GetSection(e, shdr); - } - } - } - return 0; +static inline int CompareStrings(const char *l, const char *r) { + size_t i = 0; + while (l[i] == r[i] && r[i]) ++i; + return (l[i] & 255) - (r[i] & 255); } -static Elf64_Sym *GetDynamicSymbolTable(Elf64_Ehdr *e, Elf64_Xword *n) { - Elf64_Half i; - Elf64_Shdr *shdr; - for (i = e->e_shnum; i > 0; --i) { - shdr = GetShdr(e, i - 1); - if (shdr->sh_type == SHT_DYNSYM) { - if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue; - if (n) *n = shdr->sh_size / shdr->sh_entsize; - return GetSection(e, shdr); +static inline int CheckDsoSymbolVersion(Elf64_Verdef *vd, int sym, + const char *name, char *strtab) { + Elf64_Verdaux *aux; + for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) { + if (!(vd->vd_flags & VER_FLG_BASE) && + (vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) { + aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux); + return !CompareStrings(name, strtab + aux->vda_name); + } + if (!vd->vd_next) { + return 0; } } - return 0; } /** - * Returns Linux Kernel Virtual Dynamic Shared Object function address. + * Returns address of vDSO function. */ -void *__vdsofunc(const char *name) { - size_t m; - char *names; +void *__vdsosym(const char *version, const char *name) { + void *p; + size_t i; Elf64_Ehdr *ehdr; - Elf64_Xword i, n; - Elf64_Sym *symtab, *sym; - if ((ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR)) && - (names = GetDynamicStringTable(ehdr, &m)) && - (symtab = GetDynamicSymbolTable(ehdr, &n))) { - for (i = 0; i < n; ++i) { - if (!__strcmp(names + symtab[i].st_name, name)) { - return (char *)ehdr + (symtab[i].st_value & LAZY_RHEL7_RELOCATION); - } + Elf64_Phdr *phdr; + char *strtab = 0; + size_t *dyn, base; + unsigned long *ap; + Elf64_Sym *symtab = 0; + uint16_t *versym = 0; + Elf_Symndx *hashtab = 0; + Elf64_Verdef *verdef = 0; + + for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) { + if (ap[0] == AT_SYSINFO_EHDR) { + ehdr = (void *)ap[1]; + break; } } + if (!ehdr || READ32LE(ehdr->e_ident) != READ32LE("\177ELF")) { + KERNTRACE("__vdsosym() → AT_SYSINFO_EHDR ELF not found"); + return 0; + } + + phdr = (void *)((char *)ehdr + ehdr->e_phoff); + for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum; + i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) { + switch (phdr->p_type) { + case PT_LOAD: + // modern linux uses the base address zero, but elders + // e.g. rhel7 uses the base address 0xffffffffff700000 + base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr; + break; + case PT_DYNAMIC: + dyn = (void *)((char *)ehdr + phdr->p_offset); + break; + default: + break; + } + } + if (!dyn || base == -1) { + KERNTRACE("__vdsosym() → missing program headers"); + return 0; + } + + for (i = 0; dyn[i]; i += 2) { + p = (void *)(base + dyn[i + 1]); + switch (dyn[i]) { + case DT_STRTAB: + strtab = p; + break; + case DT_SYMTAB: + symtab = p; + break; + case DT_HASH: + hashtab = p; + break; + case DT_VERSYM: + versym = p; + break; + case DT_VERDEF: + verdef = p; + break; + } + } + if (!strtab || !symtab || !hashtab) { + KERNTRACE("__vdsosym() → tables not found"); + return 0; + } + if (!verdef) { + versym = 0; + } + + for (i = 0; i < hashtab[1]; i++) { + if (ELF64_ST_TYPE(symtab[i].st_info) != STT_FUNC && + ELF64_ST_TYPE(symtab[i].st_info) != STT_OBJECT && + ELF64_ST_TYPE(symtab[i].st_info) != STT_NOTYPE) { + continue; + } + if (ELF64_ST_BIND(symtab[i].st_info) != STB_GLOBAL) { + continue; + } + if (!symtab[i].st_shndx) { + continue; + } + if (CompareStrings(name, strtab + symtab[i].st_name)) { + continue; + } + if (versym && !CheckDsoSymbolVersion(verdef, versym[i], version, strtab)) { + continue; + } + return (void *)(base + symtab[i].st_value); + } + + KERNTRACE("__vdsosym() → symbol not found"); return 0; } diff --git a/libc/calls/virtualmax.S b/libc/calls/virtualmax.S new file mode 100644 index 000000000..655ecba25 --- /dev/null +++ b/libc/calls/virtualmax.S @@ -0,0 +1,37 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + + .initbss 201,_init___virtualmax + +// Maximum amount of virtual memory in bytes. +// +// mmap() will return ENOMEM once this is reached. +// +// By default no limit is imposed. +__virtualmax: + .quad 0 + .endobj __virtualmax,globl + .previous + + .init.start 201,_init___virtualmax + push $-1 + pop %rax + stosq + .init.end 201,_init___virtualmax diff --git a/libc/calls/wait3.c b/libc/calls/wait3.c index c236e77af..2f9e44c3d 100644 --- a/libc/calls/wait3.c +++ b/libc/calls/wait3.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/sysv/errfuns.h" diff --git a/libc/calls/wait4-nt.c b/libc/calls/wait4-nt.c index 14e00a01b..7bd1990b6 100644 --- a/libc/calls/wait4-nt.c +++ b/libc/calls/wait4-nt.c @@ -21,10 +21,13 @@ #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/sigbits.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/rusage.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/fmt/conv.h" #include "libc/intrin/kprintf.h" +#include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/nt/accounting.h" #include "libc/nt/enum/accessmask.h" @@ -57,6 +60,7 @@ static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus, struct NtProcessMemoryCountersEx memcount; struct NtFileTime createfiletime, exitfiletime, kernelfiletime, userfiletime; if (_check_interrupts(true, g_fds.p)) return eintr(); + _spinlock(&__fds_lock); if (pid != -1 && pid != 0) { if (pid < 0) { /* XXX: this is sloppy */ @@ -67,15 +71,17 @@ static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus, if (!__isfdopen(pid) && (handle = OpenProcess(kNtSynchronize | kNtProcessQueryInformation, true, pid))) { - if ((pid = __reservefd(-1)) != -1) { + if ((pid = __reservefd_unlocked(-1)) != -1) { g_fds.p[pid].kind = kFdProcess; g_fds.p[pid].handle = handle; g_fds.p[pid].flags = O_CLOEXEC; } else { + _spunlock(&__fds_lock); CloseHandle(handle); return echild(); } } else { + _spunlock(&__fds_lock); return echild(); } } @@ -84,8 +90,12 @@ static textwindows int sys_wait4_nt_impl(int pid, int *opt_out_wstatus, count = 1; } else { count = __sample_pids(pids, handles, false); - if (!count) return echild(); + if (!count) { + _spunlock(&__fds_lock); + return echild(); + } } + _spunlock(&__fds_lock); for (;;) { if (_check_interrupts(true, 0)) return eintr(); dwExitCode = kNtStillActive; diff --git a/libc/calls/weirdtypes.h b/libc/calls/weirdtypes.h index de7973ae1..569e66226 100644 --- a/libc/calls/weirdtypes.h +++ b/libc/calls/weirdtypes.h @@ -68,66 +68,5 @@ typedef __UINT_FAST64_TYPE__ uint_fast64_t; #define INT_FAST64_MIN (-INT_FAST64_MAX - 1) #define UINT_FAST16_MIN (-UINT_FAST16_MAX - 1) -#define atomic_bool _Atomic(_Bool) -#define atomic_bool32 atomic_int_fast32_t -#define atomic_char _Atomic(char) -#define atomic_schar _Atomic(signed char) -#define atomic_uchar _Atomic(unsigned char) -#define atomic_short _Atomic(short) -#define atomic_ushort _Atomic(unsigned short) -#define atomic_int _Atomic(int) -#define atomic_uint _Atomic(unsigned int) -#define atomic_long _Atomic(long) -#define atomic_ulong _Atomic(unsigned long) -#define atomic_llong _Atomic(long long) -#define atomic_ullong _Atomic(unsigned long long) -#define atomic_char16_t _Atomic(char16_t) -#define atomic_char32_t _Atomic(char32_t) -#define atomic_wchar_t _Atomic(wchar_t) -#define atomic_int_least8_t _Atomic(int_least8_t) -#define atomic_uint_least8_t _Atomic(uint_least8_t) -#define atomic_int_least16_t _Atomic(int_least16_t) -#define atomic_uint_least16_t _Atomic(uint_least16_t) -#define atomic_int_least32_t _Atomic(int_least32_t) -#define atomic_uint_least32_t _Atomic(uint_least32_t) -#define atomic_int_least64_t _Atomic(int_least64_t) -#define atomic_uint_least64_t _Atomic(uint_least64_t) -#define atomic_int_fast8_t _Atomic(int_fast8_t) -#define atomic_uint_fast8_t _Atomic(uint_fast8_t) -#define atomic_int_fast16_t _Atomic(int_fast16_t) -#define atomic_uint_fast16_t _Atomic(uint_fast16_t) -#define atomic_int_fast32_t _Atomic(int_fast32_t) -#define atomic_uint_fast32_t _Atomic(uint_fast32_t) -#define atomic_int_fast64_t _Atomic(int_fast64_t) -#define atomic_uint_fast64_t _Atomic(uint_fast64_t) -#define atomic_intptr_t _Atomic(intptr_t) -#define atomic_uintptr_t _Atomic(uintptr_t) -#define atomic_size_t _Atomic(size_t) -#define atomic_ptrdiff_t _Atomic(ptrdiff_t) - -#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE -#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE -#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE -#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE -#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE -#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE -#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE -#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE -#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE -#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE -#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE -#else -#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE -#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE -#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE -#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE -#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE -#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE -#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE -#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE -#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE -#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE -#endif - #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_CALLS_WEIRDTYPES_H_ */ diff --git a/libc/calls/wincrash.c b/libc/calls/wincrash.c index bd2487faf..d79500212 100644 --- a/libc/calls/wincrash.c +++ b/libc/calls/wincrash.c @@ -19,6 +19,7 @@ #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/sigbits.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/ucontext.h" @@ -30,11 +31,12 @@ #include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sig.h" -textwindows unsigned __wincrash(struct NtExceptionPointers *ep) { +privileged unsigned __wincrash(struct NtExceptionPointers *ep) { int64_t rip; int sig, code; ucontext_t ctx; STRACE("__wincrash"); + switch (ep->ExceptionRecord->ExceptionCode) { case kNtSignalBreakpoint: code = TRAP_BRKPT; diff --git a/libc/calls/winerr.internal.h b/libc/calls/winerr.internal.h new file mode 100644 index 000000000..e71eb74a9 --- /dev/null +++ b/libc/calls/winerr.internal.h @@ -0,0 +1,8 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_WINERR_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_WINERR_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_WINERR_INTERNAL_H_ */ diff --git a/libc/calls/write-nt.c b/libc/calls/write-nt.c index 4999f6ce8..46110e534 100644 --- a/libc/calls/write-nt.c +++ b/libc/calls/write-nt.c @@ -16,10 +16,16 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/weaken.h" #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/errno.h" #include "libc/nt/errors.h" #include "libc/nt/runtime.h" +#include "libc/runtime/internal.h" +#include "libc/runtime/runtime.h" #include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" @@ -37,12 +43,18 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size, // return ebadf(); /* handled by consts.sh */ // case kNtErrorNotEnoughQuota: // return edquot(); /* handled by consts.sh */ - case kNtErrorBrokenPipe: // broken pipe - case kNtErrorNoData: // closing named pipe - __sig_raise(SIGPIPE, SI_KERNEL); // - return epipe(); // - case kNtErrorAccessDenied: // write doesn't return EACCESS - return ebadf(); // + case kNtErrorBrokenPipe: // broken pipe + case kNtErrorNoData: // closing named pipe + if (weaken(__sig_raise)) { + weaken(__sig_raise)(SIGPIPE, SI_KERNEL); + return epipe(); + } else { + STRACE("broken pipe"); + __restorewintty(); + _Exit(128 + EPIPE); + } + case kNtErrorAccessDenied: // write doesn't return EACCESS + return ebadf(); // default: return __winerr(); } diff --git a/libc/calls/write.c b/libc/calls/write.c index 7bcc3a7d5..5cfbcc581 100644 --- a/libc/calls/write.c +++ b/libc/calls/write.c @@ -20,6 +20,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sock/sock.h" diff --git a/libc/calls/writev-metal.c b/libc/calls/writev-metal.c index 3788b103f..596a564e8 100644 --- a/libc/calls/writev-metal.c +++ b/libc/calls/writev-metal.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/iovec.h" #include "libc/sysv/errfuns.h" ssize_t sys_writev_metal(struct Fd *fd, const struct iovec *iov, int iovlen) { diff --git a/libc/calls/writev-serial.c b/libc/calls/writev-serial.c index 0fc1e5aaf..022df1d5f 100644 --- a/libc/calls/writev-serial.c +++ b/libc/calls/writev-serial.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/iovec.h" #include "libc/nexgen32e/uart.internal.h" #include "libc/runtime/pc.internal.h" diff --git a/libc/calls/writev.c b/libc/calls/writev.c index 0f574b732..e2998dfc3 100644 --- a/libc/calls/writev.c +++ b/libc/calls/writev.c @@ -20,6 +20,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/describeflags.internal.h" diff --git a/libc/crt/crt.S b/libc/crt/crt.S index 83a86ab20..f30fde679 100644 --- a/libc/crt/crt.S +++ b/libc/crt/crt.S @@ -26,6 +26,8 @@ // // @param rsp is [n,argv₀..argvₙ₋₁,0,envp₀..,0,auxv₀..,0,..] // @note FreeBSD is special (see freebsd/lib/csu/amd64/...) +// @note NetBSD will only zero the call-clobbered registers +// @note ape.S and ape-loader both set RCX to XNU on Darwin // @noreturn _start: @@ -34,12 +36,16 @@ _start: test %rdi,%rdi cmovnz %rdi,%rsp jz 0f - movb $FREEBSD,__hostos(%rip) + movb $FREEBSD,%cl +0: #endif +// set operating system when already detected + mov %cl,__hostos(%rip) + // get startup timestamp as early as possible // its used by --strace flag and kprintf() %T -0: rdtsc + rdtsc ezlea kStartTsc,bx mov %eax,(%rbx) mov %edx,4(%rbx) @@ -85,14 +91,3 @@ _start: call cosmo 9: .unreachable .endfn _start,weak,hidden - -#if SupportsXnu() -// Macintosh userspace program entrypoint. -// -// @param rsp is [n,argv₀..argvₙ₋₁,0,envp₀..,0,auxv₀..,0,..] -// @note FreeBSD is special (see freebsd/lib/csu/amd64/...) -// @noreturn -_xnu: movb $XNU,__hostos(%rip) - jmp 0b - .endfn _xnu,weak,hidden -#endif diff --git a/libc/dns/getntnameservers.c b/libc/dns/getntnameservers.c index 7181cb13d..b906cd7a8 100644 --- a/libc/dns/getntnameservers.c +++ b/libc/dns/getntnameservers.c @@ -18,7 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/alg/arraylist.internal.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dns/dns.h" #include "libc/dns/resolvconf.h" #include "libc/nt/enum/keyaccess.h" diff --git a/libc/elf/checkelfaddress.c b/libc/elf/checkelfaddress.c index d42221a46..12e38520c 100644 --- a/libc/elf/checkelfaddress.c +++ b/libc/elf/checkelfaddress.c @@ -17,12 +17,16 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/elf/elf.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" void CheckElfAddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr, size_t addrsize) { #if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0) || ELF_UNTRUSTWORTHY + 0 if (addr < (intptr_t)elf || addr + addrsize > (intptr_t)elf + mapsize) { + /* kprintf("%p-%p falls outside interval %p-%p", // */ + /* addr, addr + addrsize, // */ + /* elf, (char *)elf + mapsize); // */ abort(); } #endif diff --git a/libc/elf/scalar.h b/libc/elf/scalar.h index d7e4c7ad3..93919c8b8 100644 --- a/libc/elf/scalar.h +++ b/libc/elf/scalar.h @@ -2,15 +2,16 @@ #define COSMOPOLITAN_LIBC_ELF_SCALAR_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) -#define Elf64_Half uint16_t -#define Elf64_Word uint32_t -#define Elf64_Sword int32_t -#define Elf64_Xword uint64_t -#define Elf64_Sxword int64_t -#define Elf64_Addr uint64_t -#define Elf64_Off uint64_t +#define Elf64_Addr uint64_t +#define Elf64_Half uint16_t +#define Elf64_Off uint64_t #define Elf64_Section uint16_t -#define Elf64_Versym Elf64_Half +#define Elf64_Sword int32_t +#define Elf64_Sxword int64_t +#define Elf64_Versym Elf64_Half +#define Elf64_Word uint32_t +#define Elf64_Xword uint64_t +#define Elf_Symndx uint32_t #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_ELF_SCALAR_H_ */ diff --git a/libc/errno.h b/libc/errno.h index 75c0e8609..da40ebf9c 100644 --- a/libc/errno.h +++ b/libc/errno.h @@ -8,7 +8,7 @@ COSMOPOLITAN_C_START_ * @see libc/sysv/consts.sh for numbers */ -extern errno_t errno; +#define errno (*__errno_location()) /** * System call unavailable. @@ -686,6 +686,10 @@ extern const long EXFULL; #define EXDEV EXDEV #define EXFULL EXFULL +extern errno_t __errno; + +errno_t *__errno_location(void); + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_ERRNO_H_ */ diff --git a/libc/fmt/fmt.mk b/libc/fmt/fmt.mk index ffd33e912..6ff36f863 100644 --- a/libc/fmt/fmt.mk +++ b/libc/fmt/fmt.mk @@ -77,6 +77,16 @@ o/$(MODE)/libc/fmt/wcstoumax.o: \ OVERRIDE_CFLAGS += \ -Os +# we can't use compiler magic because: +# kprintf() depends on these functions +o/$(MODE)/libc/fmt/strerrno.greg.o \ +o/$(MODE)/libc/fmt/strerrdoc.greg.o \ +o/$(MODE)/libc/fmt/strerror_wr.greg.o: \ + OVERRIDE_CFLAGS += \ + -fpie \ + -ffreestanding \ + $(NO_MAGIC) + LIBC_FMT_LIBS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x))) LIBC_FMT_SRCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_SRCS)) LIBC_FMT_HDRS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/fmt/leb128.h b/libc/fmt/leb128.h index 2c3419585..a16f2e960 100644 --- a/libc/fmt/leb128.h +++ b/libc/fmt/leb128.h @@ -4,9 +4,10 @@ COSMOPOLITAN_C_START_ char *sleb64(char *, int64_t); -char *zleb64(char *, int64_t); -char *uleb64(char *, uint64_t); +char *zleb64(char[hasatleast 10], int64_t); +char *uleb64(char[hasatleast 10], uint64_t); int unzleb64(const char *, size_t, int64_t *); +int unuleb64(char *, size_t, uint64_t *); #ifndef __STRICT_ANSI__ char *sleb128(char *, int128_t); diff --git a/libc/fmt/sprintf.c b/libc/fmt/sprintf.c index 46174ff2c..3cd64c860 100644 --- a/libc/fmt/sprintf.c +++ b/libc/fmt/sprintf.c @@ -16,8 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/weaken.h" #include "libc/fmt/fmt.h" #include "libc/limits.h" +#include "libc/log/log.h" /** * Formats string to buffer that's hopefully large enough. diff --git a/libc/fmt/stoa.c b/libc/fmt/stoa.c index f7efa15ac..94973bb9a 100644 --- a/libc/fmt/stoa.c +++ b/libc/fmt/stoa.c @@ -62,19 +62,6 @@ static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) { return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1); } -static int __fmt_stoa_quote(out_f out, void *arg, unsigned flags, char ch, - unsigned char signbit) { - if (flags & FLAGS_REPR) { - if (signbit == 63) { - if (out("L", arg, 1) == -1) return -1; - } else if (signbit == 15) { - if (out("u", arg, 1) == -1) return -1; - } - if (out(&ch, arg, 1) == -1) return -1; - } - return 0; -} - /** * Converts string to array. * @@ -103,8 +90,6 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data, if (flags & FLAGS_PRECISION) { precision = min(strlen(p), precision); } - } else { - if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1; } ignorenul = false; @@ -153,6 +138,9 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data, } else if (weaken(strnwidth)) { w = weaken(strnwidth)(p, precision, 0); } + if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) { + w += 2 + (signbit == 63) + (signbit == 15); + } if (w < width) { pad = width - w; } @@ -162,6 +150,16 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data, if (__fmt_pad(out, arg, pad) == -1) return -1; } + if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) { + if (signbit == 63) { + if (out("L", arg, 1) == -1) return -1; + } else if (signbit == 15) { + if (out("u", arg, 1) == -1) return -1; + } + buf[0] = qchar; + if (out(buf, arg, 1) == -1) return -1; + } + if (justdobytes) { while (precision--) { wc = *p++ & 0xff; @@ -207,14 +205,14 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data, } } - if (pad && (flags & FLAGS_LEFT)) { - if (__fmt_pad(out, arg, pad) == -1) return -1; - } - if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) { buf[0] = qchar; if (out(buf, arg, 1) == -1) return -1; } + if (pad && (flags & FLAGS_LEFT)) { + if (__fmt_pad(out, arg, pad) == -1) return -1; + } + return 0; } diff --git a/libc/fmt/strerror_r.greg.c b/libc/fmt/strerror_r.c similarity index 100% rename from libc/fmt/strerror_r.greg.c rename to libc/fmt/strerror_r.c diff --git a/libc/fmt/uleb64.c b/libc/fmt/uleb64.c index c4d6561dd..01f798490 100644 --- a/libc/fmt/uleb64.c +++ b/libc/fmt/uleb64.c @@ -36,7 +36,7 @@ * @param x is number * @return p + i */ -char *uleb64(char *p, uint64_t x) { +char *uleb64(char p[hasatleast 10], uint64_t x) { int c; for (;;) { c = x & 127; diff --git a/libc/fmt/unuleb64.c b/libc/fmt/unuleb64.c new file mode 100644 index 000000000..80c83a771 --- /dev/null +++ b/libc/fmt/unuleb64.c @@ -0,0 +1,41 @@ +/*-*- 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 │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/fmt/leb128.h" + +/** + * Decodes unsigned integer from array. + * + * @param p is input array + * @param n is capacity of p + * @param x receives number number + * @return bytes decoded or -1 on error + */ +int unuleb64(char *p, size_t n, uint64_t *x) { + int k; + size_t i; + uint64_t t; + for (k = t = i = 0; i < n; ++i, k += 7) { + t |= (uint64_t)(p[i] & 127) << k; + if (~p[i] & 128) { + *x = t; + return i + 1; + } + } + return -1; +} diff --git a/libc/fmt/zleb64.c b/libc/fmt/zleb64.c index 1ca96cd52..48a3f5c58 100644 --- a/libc/fmt/zleb64.c +++ b/libc/fmt/zleb64.c @@ -44,7 +44,7 @@ * @return p + i * @see unzleb64() */ -char *zleb64(char *p, int64_t x) { +char *zleb64(char p[hasatleast 10], int64_t x) { int c; uint64_t u; u = x; diff --git a/libc/integral/c.inc b/libc/integral/c.inc index c2186bdf3..05234e6d8 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -67,8 +67,8 @@ } while (0) #endif -#if __STDC_VERSION__ + 0 < 201112 && defined(__x86__) -#define _Atomic(TYPE) TYPE +#if __STDC_VERSION__ + 0 < 201112 +#define _Atomic(TYPE) TYPE volatile #endif #ifdef __llvm__ @@ -123,7 +123,7 @@ typedef __UINT64_TYPE__ uint64_t; typedef __INTMAX_TYPE__ intmax_t; typedef __UINTMAX_TYPE__ uintmax_t; -#if __GNUC__ * 100 + __GNUC_MINOR__ >= 406 || defined(__llvm__) +#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406 || defined(__llvm__) typedef signed __int128 int128_t; typedef unsigned __int128 uint128_t; #endif @@ -195,9 +195,9 @@ typedef struct { #ifndef privileged #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__visibility__) || defined(__GNUC__)) -#define privileged _Section(".privileged") noinstrument +#define privileged _Section(".privileged") #else -#define privileged _Section(".privileged") noinstrument +#define privileged _Section(".privileged") #endif #endif diff --git a/libc/integral/normalize.inc b/libc/integral/normalize.inc index 4cf6d3d06..c675eff38 100644 --- a/libc/integral/normalize.inc +++ b/libc/integral/normalize.inc @@ -50,6 +50,9 @@ #ifndef __has_cpp_attribute #define __has_cpp_attribute(x) 0 #endif +#ifndef __has_extension +#define __has_extension(x) 0 +#endif #ifdef unix #undef unix diff --git a/test/libc/calls/execve_test.c b/libc/intrin/_spinlock_debug_4.c similarity index 61% rename from test/libc/calls/execve_test.c rename to libc/intrin/_spinlock_debug_4.c index 88cbd140f..40416c2af 100644 --- a/test/libc/calls/execve_test.c +++ b/libc/intrin/_spinlock_debug_4.c @@ -16,58 +16,48 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/dce.h" -#include "libc/log/check.h" -#include "libc/runtime/runtime.h" -#include "libc/testlib/testlib.h" +#include "libc/intrin/kprintf.h" +#include "libc/intrin/lockcmpxchgp.h" +#include "libc/intrin/spinlock.h" +#include "libc/log/log.h" +#include "libc/nexgen32e/rdtsc.h" +#include "libc/runtime/internal.h" +#include "libc/time/clockstonanos.internal.h" -void SetUp(void) { - if (getenv("_SUBPROCESS")) { - if (!__argv[0]) { - exit(0); - } else { - exit(7); +privileged void _spinlock_debug_4(int *lock, const char *lockname, + const char *file, int line, + const char *func) { + unsigned i; + int me, owner; + uint64_t ts1, ts2; + me = gettid(); + owner = 0; + if (!_lockcmpxchgp(lock, &owner, me)) { + if (owner == me) { + kprintf("%s:%d: error: lock re-entry on %s in %s()\n", file, line, + lockname, func); + if (weaken(__die)) weaken(__die)(); + __restorewintty(); + _Exit(1); } - } else if (getenv("_WEIRDENV")) { - for (char **e = environ; *e; ++e) { - if (!strcmp(*e, "WEIRD")) { - exit(0); + i = 0; + ts1 = rdtsc(); + for (;;) { + owner = 0; + if (_lockcmpxchgp(lock, &owner, me)) break; + ts2 = rdtsc(); + if (ClocksToNanos(ts1, ts2) > 1000000000ul) { + ts1 = ts2; + kprintf("%s:%d: warning: slow lock on %s in %s()\n", file, line, + lockname, func); + } + if (++i & 7) { + __builtin_ia32_pause(); + } else { + sched_yield(); } } - exit(7); } } - -TEST(execve, testWeirdAnsiC89emptyArgv) { - char *prog; - int pid, ws; - if (IsWindows()) return; - if (IsOpenbsd()) return; - prog = GetProgramExecutableName(); - ASSERT_NE(-1, (pid = fork())); - if (!pid) { - execve(prog, (char *const[]){0}, (char *const[]){"_SUBPROCESS=1", 0}); - _Exit(127); - } - ASSERT_NE(-1, wait(&ws)); - EXPECT_TRUE(WIFEXITED(ws)); - EXPECT_EQ(0, WEXITSTATUS(ws)); -} - -TEST(execve, testWeirdEnvironmentVariable) { - char *prog; - int pid, ws; - if (IsWindows()) return; - if (IsOpenbsd()) return; - prog = GetProgramExecutableName(); - ASSERT_NE(-1, (pid = fork())); - if (!pid) { - execve(prog, (char *const[]){prog, 0}, - (char *const[]){"_WEIRDENV=1", "WEIRD", 0}); - _Exit(127); - } - ASSERT_NE(-1, wait(&ws)); - EXPECT_TRUE(WIFEXITED(ws)); - EXPECT_EQ(0, WEXITSTATUS(ws)); -} diff --git a/libc/intrin/_trylock_debug_4.c b/libc/intrin/_trylock_debug_4.c new file mode 100644 index 000000000..901548ce3 --- /dev/null +++ b/libc/intrin/_trylock_debug_4.c @@ -0,0 +1,42 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/weaken.h" +#include "libc/intrin/kprintf.h" +#include "libc/intrin/lockcmpxchgp.h" +#include "libc/intrin/spinlock.h" +#include "libc/log/log.h" +#include "libc/runtime/internal.h" +#include "libc/runtime/runtime.h" + +privileged int _trylock_debug_4(int *lock, const char *lockname, + const char *file, int line, const char *func) { + int owner = 0; + int me = gettid(); + if (_lockcmpxchgp(lock, &owner, me)) { + return 0; + } else if (owner != me) { + return owner; + } else { + kprintf("%s:%d: error: lock re-entry on %s in %s()\n", file, line, lockname, + func); + if (weaken(__die)) weaken(__die)(); + __restorewintty(); + _Exit(1); + } +} diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index c6145da37..cb789cc0c 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -21,15 +21,17 @@ #include "libc/bits/likely.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/asancodes.h" +#include "libc/intrin/cmpxchg.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/lockcmpxchg.h" #include "libc/intrin/nomultics.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/log/backtrace.internal.h" #include "libc/log/internal.h" #include "libc/log/libfatal.internal.h" @@ -57,9 +59,21 @@ STATIC_YOINK("_init_asan"); +#if IsModeDbg() +// MODE=dbg +// O(32mb) of morgue memory +// Θ(64) bytes of malloc overhead #define ASAN_MORGUE_ITEMS 512 -#define ASAN_MORGUE_THRESHOLD 65536 // morgue memory O(ITEMS*THRESHOLD) -#define ASAN_TRACE_ITEMS 16 // backtrace limit on malloc origin +#define ASAN_MORGUE_THRESHOLD 65536 +#define ASAN_TRACE_ITEMS 16 +#else +// MODE=asan +// O(32mb) of morgue memory +// Θ(32) bytes of malloc overhead +#define ASAN_MORGUE_ITEMS 512 +#define ASAN_MORGUE_THRESHOLD 65536 +#define ASAN_TRACE_ITEMS 4 +#endif /** * @fileoverview Cosmopolitan Address Sanitizer Runtime. @@ -126,7 +140,7 @@ struct AsanSourceLocation { }; struct AsanAccessInfo { - const uintptr_t addr; + const char *addr; const uintptr_t first_bad_addr; size_t size; bool iswrite; @@ -134,7 +148,7 @@ struct AsanAccessInfo { }; struct AsanGlobal { - const uintptr_t addr; + const char *addr; size_t size; size_t size_with_redzone; const void *name; @@ -154,7 +168,8 @@ struct ReportOriginHeap { int z; }; -bool __asan_noreentry; +static int __asan_noreentry; +_Alignas(64) static int __asan_lock; static struct AsanMorgue __asan_morgue; #define __asan_unreachable() \ @@ -184,7 +199,7 @@ static char *__asan_utf8cpy(char *p, unsigned c) { return p; } -static void *__asan_memset(void *p, char c, size_t n) { +static void __asan_memset(void *p, char c, size_t n) { char *b; size_t i; uint64_t x; @@ -192,29 +207,29 @@ static void *__asan_memset(void *p, char c, size_t n) { x = 0x0101010101010101ul * (c & 255); switch (n) { case 0: - return p; + break; case 1: __builtin_memcpy(b, &x, 1); - return p; + break; case 2: __builtin_memcpy(b, &x, 2); - return p; + break; case 3: __builtin_memcpy(b, &x, 2); __builtin_memcpy(b + 1, &x, 2); - return p; + break; case 4: __builtin_memcpy(b, &x, 4); - return p; + break; case 5: case 6: case 7: __builtin_memcpy(b, &x, 4); __builtin_memcpy(b + n - 4, &x, 4); - return p; + break; case 8: __builtin_memcpy(b, &x, 8); - return p; + break; case 9: case 10: case 11: @@ -225,7 +240,7 @@ static void *__asan_memset(void *p, char c, size_t n) { case 16: __builtin_memcpy(b, &x, 8); __builtin_memcpy(b + n - 8, &x, 8); - return p; + break; default: if (n <= 64) { i = 0; @@ -238,7 +253,7 @@ static void *__asan_memset(void *p, char c, size_t n) { } else { __repstosb(p, c, n); } - return p; + break; } } @@ -336,10 +351,10 @@ dontdiscard static __asan_die_f *__asan_die(void) { } } -void __asan_poison(long p, long n, signed char t) { +void __asan_poison(void *p, long n, signed char t) { signed char k, *s; - s = (signed char *)((p >> 3) + 0x7fff8000); - if ((k = p & 7)) { + s = (signed char *)(((intptr_t)p >> 3) + 0x7fff8000); + if ((k = (intptr_t)p & 7)) { if ((!*s && n >= 8 - k) || *s > k) *s = k; n -= MIN(8 - k, n); s += 1; @@ -351,10 +366,10 @@ void __asan_poison(long p, long n, signed char t) { } } -void __asan_unpoison(long p, long n) { +void __asan_unpoison(void *p, long n) { signed char k, *s; - k = p & 7; - s = (signed char *)((p >> 3) + 0x7fff8000); + k = (intptr_t)p & 7; + s = (signed char *)(((intptr_t)p >> 3) + 0x7fff8000); if (UNLIKELY(k)) { if (k + n < 8) { if (n > 0) *s = MAX(*s, k + n); @@ -721,7 +736,7 @@ static void __asan_report_memory_origin(const unsigned char *addr, int size, if (_base <= addr && addr < _end) { __asan_report_memory_origin_image((intptr_t)addr, size); } else if (IsAutoFrame((intptr_t)addr >> 16)) { - /* __asan_report_memory_origin_heap(addr, size); */ + __asan_report_memory_origin_heap(addr, size); } } @@ -734,9 +749,9 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, uint64_t x, y, z; char *p, *q, *base; struct MemoryIntervals *m; - ++g_ftrace; + --__ftrace; p = __fatalbuf; - kprintf("\n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p\n%s\n", + kprintf("\n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p\n", __asan_describe_access_poison(kind), size, message, addr, SHADOW(addr), __argv[0]); if (0 < size && size < 80) { @@ -756,19 +771,19 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, for (c = i = 0; i < 80; ++i) { if (!(t = __asan_check(base + i, 1).kind)) { if (c != 32) { - p = __stpcpy(p, "\e[32m"); + *p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '2', *p++ = 'm'; c = 32; } *p++ = '.'; } else { if (c != 31) { - p = __stpcpy(p, "\e[31m"); + *p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '1', *p++ = 'm'; c = 31; } p = __asan_utf8cpy(p, __asan_symbolize_access_poison(t)); } } - p = __stpcpy(p, "\e[39m"); + *p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '9', *p++ = 'm'; *p++ = '\n'; for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' '; for (; i + 8 <= 80; i += 8) { @@ -811,7 +826,7 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size, kprintf("%s", __fatalbuf); __asan_report_memory_origin(addr, size, kind); kprintf("\nthe crash was caused by\n"); - --g_ftrace; + ++__ftrace; return __asan_die(); } @@ -835,30 +850,27 @@ dontdiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size, } void *__asan_morgue_add(void *p) { + int i; void *r; - int i, j; - for (;;) { - i = __asan_morgue.i; - j = (i + 1) & (ARRAYLEN(__asan_morgue.p) - 1); - if (_lockcmpxchg(&__asan_morgue.i, i, j)) { - r = __asan_morgue.p[i]; - __asan_morgue.p[i] = p; - return r; - } - } + _spinlock_cooperative(&__asan_lock); + i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1); + r = __asan_morgue.p[i]; + __asan_morgue.p[i] = p; + _spunlock(&__asan_lock); + return r; } static void __asan_morgue_flush(void) { int i; void *p; + _spinlock_cooperative(&__asan_lock); for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) { - p = __asan_morgue.p[i]; - if (_lockcmpxchg(__asan_morgue.p + i, p, 0)) { - if (weaken(dlfree)) { - weaken(dlfree)(p); - } + if (__asan_morgue.p[i] && weaken(dlfree)) { + weaken(dlfree)(__asan_morgue.p[i]); } + __asan_morgue.p[i] = 0; } + _spunlock(&__asan_lock); } static size_t __asan_user_size(size_t n) { @@ -934,8 +946,8 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) { #define __asan_trace __asan_rawtrace -static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun, - struct AsanTrace *bt) { +void *__asan_allocate(size_t a, size_t n, int underrun, int overrun, + struct AsanTrace *bt) { char *p; size_t c; struct AsanExtra *e; @@ -943,9 +955,9 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun, if ((p = weaken(dlmemalign)(a, __asan_heap_size(n)))) { c = weaken(dlmalloc_usable_size)(p); e = (struct AsanExtra *)(p + c - sizeof(*e)); - __asan_unpoison((uintptr_t)p, n); - __asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */ - __asan_poison((uintptr_t)p + n, c - n, overrun); + __asan_unpoison(p, n); + __asan_poison(p - 16, 16, underrun); /* see dlmalloc design */ + __asan_poison(p + n, c - n, overrun); __asan_memset(p, 0xF9, n); __asan_write48(&e->size, n); __asan_memcpy(&e->bt, bt, sizeof(*bt)); @@ -1030,7 +1042,7 @@ static void __asan_deallocate(char *p, long kind) { struct AsanExtra *e; if ((e = __asan_get_extra(p, &c))) { if (__asan_read48(e->size, &n)) { - __asan_poison((uintptr_t)p, c, kind); + __asan_poison(p, c, kind); if (c <= ASAN_MORGUE_THRESHOLD) { p = __asan_morgue_add(p); } @@ -1084,11 +1096,11 @@ static void *__asan_realloc_impl(void *p, size_t n, if ((e = __asan_get_extra(p, &c))) { if (__asan_read48(e->size, &m)) { if (n <= m) { /* shrink */ - __asan_poison((uintptr_t)p + n, m - n, kAsanHeapOverrun); + __asan_poison((char *)p + n, m - n, kAsanHeapOverrun); __asan_write48(&e->size, n); return p; } else if (n <= c - sizeof(struct AsanExtra)) { /* small growth */ - __asan_unpoison((uintptr_t)p + m, n - m); + __asan_unpoison((char *)p + m, n - m); __asan_write48(&e->size, n); return p; } else { /* exponential growth */ @@ -1175,13 +1187,12 @@ void __asan_handle_no_return(void) { void __asan_register_globals(struct AsanGlobal g[], int n) { int i; - __asan_poison((intptr_t)g, sizeof(*g) * n, kAsanProtected); + __asan_poison(g, sizeof(*g) * n, kAsanProtected); for (i = 0; i < n; ++i) { __asan_poison(g[i].addr + g[i].size, g[i].size_with_redzone - g[i].size, kAsanGlobalRedzone); if (g[i].location) { - __asan_poison((intptr_t)g[i].location, sizeof(*g[i].location), - kAsanProtected); + __asan_poison(g[i].location, sizeof(*g[i].location), kAsanProtected); } } } @@ -1197,12 +1208,13 @@ void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) { struct AsanTrace tr; __asan_rawtrace(&tr, __builtin_frame_address(0)); kprintf( - "WARNING: ASAN error during %s bad %d byte %s at %x bt %x %x %x %x %x\n", - s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3], tr.p[4], tr.p[5]); + "WARNING: ASAN %s %s bad %d byte %s at %x bt %x %x %x\n", + __asan_noreentry == gettid() ? "error during" : "multi-threaded crash", + s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3]); } void __asan_report_load(uint8_t *addr, int size) { - if (_lockcmpxchg(&__asan_noreentry, false, true)) { + if (_lockcmpxchg(&__asan_noreentry, 0, gettid())) { if (!__vforked) { __asan_report_memory_fault(addr, size, "load")(); __asan_unreachable(); @@ -1215,7 +1227,7 @@ void __asan_report_load(uint8_t *addr, int size) { } void __asan_report_store(uint8_t *addr, int size) { - if (_lockcmpxchg(&__asan_noreentry, false, true)) { + if (_lockcmpxchg(&__asan_noreentry, 0, gettid())) { if (!__vforked) { __asan_report_memory_fault(addr, size, "store")(); __asan_unreachable(); @@ -1227,15 +1239,15 @@ void __asan_report_store(uint8_t *addr, int size) { } } -void __asan_poison_stack_memory(uintptr_t addr, size_t size) { +void __asan_poison_stack_memory(char *addr, size_t size) { __asan_poison(addr, size, kAsanStackFree); } -void __asan_unpoison_stack_memory(uintptr_t addr, size_t size) { +void __asan_unpoison_stack_memory(char *addr, size_t size) { __asan_unpoison(addr, size); } -void __asan_alloca_poison(uintptr_t addr, uintptr_t size) { +void __asan_alloca_poison(char *addr, uintptr_t size) { __asan_poison(addr - 32, 32, kAsanAllocaUnderrun); __asan_poison(addr + size, 32, kAsanAllocaOverrun); } @@ -1254,8 +1266,8 @@ void *__asan_get_current_fake_stack(void) { return 0; } -void __sanitizer_annotate_contiguous_container(long beg, long end, long old_mid, - long new_mid) { +void __sanitizer_annotate_contiguous_container(char *beg, char *end, + char *old_mid, char *new_mid) { // the c++ stl uses this // TODO(jart): make me faster __asan_unpoison(beg, new_mid - beg); @@ -1316,11 +1328,11 @@ void __asan_map_shadow(uintptr_t p, size_t n) { __repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16), kAsanUnmapped, size); } - __asan_unpoison((uintptr_t)p, n); + __asan_unpoison((char *)p, n); } static textstartup void __asan_shadow_string(char *s) { - __asan_map_shadow((uintptr_t)s, __strlen(s) + 1); + __asan_map_shadow((intptr_t)s, __strlen(s) + 1); } static textstartup void __asan_shadow_auxv(intptr_t *auxv) { @@ -1358,7 +1370,7 @@ static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m, static textstartup void __asan_shadow_existing_mappings(void) { __asan_shadow_mapping(&_mmi, 0); - __asan_map_shadow(GetStackAddr(0), GetStackSize()); + __asan_map_shadow((intptr_t)GetStackAddr(0), GetStackSize()); __asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow); } diff --git a/libc/intrin/asan.internal.h b/libc/intrin/asan.internal.h index 6bcbb2700..5dc92372f 100644 --- a/libc/intrin/asan.internal.h +++ b/libc/intrin/asan.internal.h @@ -16,10 +16,8 @@ struct AsanFault { const signed char *shadow; }; -extern bool __asan_noreentry; - -void __asan_unpoison(long, long); -void __asan_poison(long, long, signed char); +void __asan_unpoison(void *, long); +void __asan_poison(void *, long, signed char); void __asan_verify(const void *, size_t); void __asan_map_shadow(uintptr_t, size_t); bool __asan_is_valid(const void *, long) nosideeffect; diff --git a/libc/intrin/assertfail.greg.c b/libc/intrin/assertfail.greg.c index 0579ff244..7ee853936 100644 --- a/libc/intrin/assertfail.greg.c +++ b/libc/intrin/assertfail.greg.c @@ -33,8 +33,8 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file, int line) { int rc; static bool noreentry; - __strace = 0; - g_ftrace = 0; + --__strace; + --__ftrace; kprintf("%s:%d: assert(%s) failed\n", file, line, expr); if (_lockcmpxchg(&noreentry, false, true)) { if (weaken(__die)) { @@ -46,7 +46,6 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file, } else { rc = 24; } - if (weaken(__die)) weaken(__die)(); __restorewintty(); _Exit(rc); } diff --git a/libc/intrin/atomic_load.h b/libc/intrin/atomic_load.h deleted file mode 100644 index d5a292de9..000000000 --- a/libc/intrin/atomic_load.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_ -#define COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -intptr_t atomic_load(void *, size_t); - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define atomic_load(MEM) \ - ({ \ - autotype(MEM) Mem = (MEM); \ - typeof(*Mem) Reg; \ - asm("mov\t%1,%0" : "=r"(Reg) : "m"(*Mem)); \ - Reg; \ - }) -#else -#define atomic_load(MEM) atomic_load(MEM, sizeof(*(MEM))) -#endif /* GNUC && !ANSI && x86 */ - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_ */ diff --git a/libc/intrin/atomic_store.c b/libc/intrin/atomic_store.c deleted file mode 100644 index c4c32e6b7..000000000 --- a/libc/intrin/atomic_store.c +++ /dev/null @@ -1,54 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/atomic_store.h" - -/** - * Saves scalar to memory w/ one operation. - * - * This is guaranteed to happen in either one or zero operations, - * depending on whether or not it's possible for *(MEM) to be read - * afterwards. This macro only forbids compiler from using >1 ops. - * - * @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64} - * @param VAL is uint𝑘_t w/ better encoding for immediates (constexpr) - * @return VAL - * @note alignas(𝑘) on nexgen32e only needed for end of page gotcha - * @note alignas(𝑘) is implied if compiler knows type - * @note needed to defeat store tearing optimizations - * @see Intel Six-Thousand Page Manual Manual V.3A §8.2.3.1 - * @see atomic_load() - */ -intptr_t(atomic_store)(void *p, intptr_t x, size_t n) { - switch (n) { - case 1: - __builtin_memcpy(p, &x, 1); - return x; - case 2: - __builtin_memcpy(p, &x, 2); - return x; - case 4: - __builtin_memcpy(p, &x, 4); - return x; - case 8: - __builtin_memcpy(p, &x, 8); - return x; - default: - return 0; - } -} diff --git a/libc/intrin/atomic_store.h b/libc/intrin/atomic_store.h deleted file mode 100644 index 9a83c407c..000000000 --- a/libc/intrin/atomic_store.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_ -#define COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -intptr_t atomic_store(void *, intptr_t, size_t); - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define atomic_store(MEM, VAL) \ - ({ \ - autotype(VAL) Val = (VAL); \ - typeof(&Val) Mem = (MEM); \ - asm("mov%z1\t%1,%0" : "=m"(*Mem) : "r"(Val)); \ - Val; \ - }) -#else -#define atomic_store(MEM, VAL) \ - atomic_store(MEM, VAL, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAL)))) -#endif /* __GNUC__ && !__STRICT_ANSI__ */ - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_ */ diff --git a/libc/intrin/closehandle.greg.c b/libc/intrin/closehandle.c similarity index 97% rename from libc/intrin/closehandle.greg.c rename to libc/intrin/closehandle.c index dfd278caf..5d32fc810 100644 --- a/libc/intrin/closehandle.greg.c +++ b/libc/intrin/closehandle.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/log/log.h" #include "libc/nt/runtime.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/createdirectory.greg.c b/libc/intrin/createdirectory.c similarity index 98% rename from libc/intrin/createdirectory.greg.c rename to libc/intrin/createdirectory.c index f0a8efd10..1a3884279 100644 --- a/libc/intrin/createdirectory.greg.c +++ b/libc/intrin/createdirectory.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/files.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/createfile.greg.c b/libc/intrin/createfile.c similarity index 98% rename from libc/intrin/createfile.greg.c rename to libc/intrin/createfile.c index 6290f7381..31e3fef92 100644 --- a/libc/intrin/createfile.greg.c +++ b/libc/intrin/createfile.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/createfile.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/createfilemapping.greg.c b/libc/intrin/createfilemapping.c similarity index 98% rename from libc/intrin/createfilemapping.greg.c rename to libc/intrin/createfilemapping.c index a8a5ea4aa..7e149b5e8 100644 --- a/libc/intrin/createfilemapping.greg.c +++ b/libc/intrin/createfilemapping.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/memory.h" #include "libc/nt/struct/securityattributes.h" diff --git a/libc/intrin/createfilemappingnuma.greg.c b/libc/intrin/createfilemappingnuma.c similarity index 98% rename from libc/intrin/createfilemappingnuma.greg.c rename to libc/intrin/createfilemappingnuma.c index 7da20c4fc..33a51289e 100644 --- a/libc/intrin/createfilemappingnuma.greg.c +++ b/libc/intrin/createfilemappingnuma.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/memory.h" diff --git a/libc/intrin/createnamedpipe.greg.c b/libc/intrin/createnamedpipe.c similarity index 98% rename from libc/intrin/createnamedpipe.greg.c rename to libc/intrin/createnamedpipe.c index 7e70683e1..4c6d7a7ea 100644 --- a/libc/intrin/createnamedpipe.greg.c +++ b/libc/intrin/createnamedpipe.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/ipc.h" #include "libc/nt/struct/securityattributes.h" diff --git a/libc/intrin/createpipe.greg.c b/libc/intrin/createpipe.c similarity index 98% rename from libc/intrin/createpipe.greg.c rename to libc/intrin/createpipe.c index 4e295530a..a8bb75b2e 100644 --- a/libc/intrin/createpipe.greg.c +++ b/libc/intrin/createpipe.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/ipc.h" #include "libc/nt/struct/securityattributes.h" diff --git a/libc/intrin/createprocess.greg.c b/libc/intrin/createprocess.c similarity index 98% rename from libc/intrin/createprocess.greg.c rename to libc/intrin/createprocess.c index e18232d85..13a7b05c2 100644 --- a/libc/intrin/createprocess.greg.c +++ b/libc/intrin/createprocess.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/process.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/createsymboliclink.greg.c b/libc/intrin/createsymboliclink.c similarity index 98% rename from libc/intrin/createsymboliclink.greg.c rename to libc/intrin/createsymboliclink.c index ddbe879a0..18bc51c8b 100644 --- a/libc/intrin/createsymboliclink.greg.c +++ b/libc/intrin/createsymboliclink.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/files.h" diff --git a/libc/intrin/createthread.greg.c b/libc/intrin/createthread.c similarity index 98% rename from libc/intrin/createthread.greg.c rename to libc/intrin/createthread.c index 77992f157..d9ebf9650 100644 --- a/libc/intrin/createthread.greg.c +++ b/libc/intrin/createthread.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/struct/securityattributes.h" #include "libc/nt/thread.h" diff --git a/libc/intrin/cxaatexit.c b/libc/intrin/cxaatexit.c index a71602958..7fb83e8a0 100644 --- a/libc/intrin/cxaatexit.c +++ b/libc/intrin/cxaatexit.c @@ -19,6 +19,7 @@ #include "libc/assert.h" #include "libc/bits/weaken.h" #include "libc/calls/strace.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/bsr.h" @@ -28,6 +29,8 @@ STATIC_YOINK("__cxa_finalize"); +static int __cxa_lock; + /** * Adds global destructor. * @@ -47,6 +50,7 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) { unsigned i; struct CxaAtexitBlock *b, *b2; _Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), ""); + _spinlock(&__cxa_lock); b = __cxa_blocks.p; if (!b) b = __cxa_blocks.p = &__cxa_blocks.root; if (!~b->mask) { @@ -55,6 +59,7 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) { b2->next = b; __cxa_blocks.p = b = b2; } else { + _spunlock(&__cxa_lock); return enomem(); } } @@ -64,5 +69,6 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) { b->p[i].fp = fp; b->p[i].arg = arg; b->p[i].pred = pred; + _spunlock(&__cxa_lock); return 0; } diff --git a/libc/intrin/deletefile.greg.c b/libc/intrin/deletefile.c similarity index 97% rename from libc/intrin/deletefile.greg.c rename to libc/intrin/deletefile.c index bf30eb534..c9284a6de 100644 --- a/libc/intrin/deletefile.greg.c +++ b/libc/intrin/deletefile.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/describeflags.internal.h b/libc/intrin/describeflags.internal.h index 2c822ac05..e797abc9a 100644 --- a/libc/intrin/describeflags.internal.h +++ b/libc/intrin/describeflags.internal.h @@ -3,6 +3,7 @@ #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/sigaltstack.h" #include "libc/calls/struct/sigset.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/timespec.h" @@ -22,11 +23,13 @@ const char *DescribeMapFlags(int); const char *DescribeProtFlags(int); const char *DescribeRemapFlags(int); const char *DescribeRlimitName(int); +const char *DescribePersonalityFlags(int); const char *DescribeSeccompOperationFlags(int); const char *DescribePollFlags(char *, size_t, int); const char *DescribeStat(int, const struct stat *); const char *DescribeDirfd(char[hasatleast 12], int); const char *DescribeSigaction(char *, size_t, int, const struct sigaction *); +const char *DescribeSigaltstk(char *, size_t, int, const struct sigaltstack *); const char *DescribeSigset(char *, size_t, int, const sigset_t *); const char *DescribeRlimit(char *, size_t, int, const struct rlimit *); const char *DescribeTimespec(char *, size_t, int, const struct timespec *); diff --git a/libc/intrin/describeframe.c b/libc/intrin/describeframe.c index 1dc78593f..f252ff429 100644 --- a/libc/intrin/describeframe.c +++ b/libc/intrin/describeframe.c @@ -30,17 +30,17 @@ noasan const char *DescribeFrame(int x) { char *p; static char buf[32]; if (IsShadowFrame(x)) { - ksnprintf(buf, sizeof(buf), " /*shadow:%.12p*/", UNSHADOW(ADDR(x))); + ksnprintf(buf, sizeof(buf), " shadow=%.8x", FRAME(UNSHADOW(ADDR(x)))); return buf; - return " /*shadow*/ "; + return " shadow "; } else if (IsAutoFrame(x)) { - return " /*automap*/"; + return " automap"; } else if (IsFixedFrame(x)) { - return " /*fixed*/ "; + return " fixed "; } else if (IsArenaFrame(x)) { - return " /*arena*/ "; + return " arena "; } else if (IsStaticStackFrame(x)) { - return " /*stack*/ "; + return " stack "; } else { return ""; } diff --git a/libc/intrin/describemapflags.greg.c b/libc/intrin/describemapflags.greg.c index f30c85fe9..b0fdefd50 100644 --- a/libc/intrin/describemapflags.greg.c +++ b/libc/intrin/describemapflags.greg.c @@ -26,8 +26,8 @@ const char *DescribeMapFlags(int x) { _Alignas(char) static char mapflags[256]; const struct DescribeFlags kMapFlags[] = { {MAP_STACK, "STACK"}, // order matters - {MAP_ANONYMOUS, "ANONYMOUS"}, // {MAP_PRIVATE, "PRIVATE"}, // + {MAP_ANONYMOUS, "ANONYMOUS"}, // {MAP_SHARED, "SHARED"}, // {MAP_FIXED, "FIXED"}, // {MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, // diff --git a/libc/intrin/describentsecurityattributes.greg.c b/libc/intrin/describentsecurityattributes.greg.c index 192fb72f0..141483677 100644 --- a/libc/intrin/describentsecurityattributes.greg.c +++ b/libc/intrin/describentsecurityattributes.greg.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/struct/securityattributes.h" diff --git a/libc/intrin/describepersonalityflags.c b/libc/intrin/describepersonalityflags.c new file mode 100644 index 000000000..5e09fde70 --- /dev/null +++ b/libc/intrin/describepersonalityflags.c @@ -0,0 +1,43 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/describeflags.internal.h" +#include "libc/macros.internal.h" +#include "libc/nt/enum/accessmask.h" +#include "libc/nt/enum/filesharemode.h" +#include "libc/sysv/consts/personality.h" + +static const struct DescribeFlags kPersonalityFlags[] = { + {ADDR_COMPAT_LAYOUT, "ADDR_COMPAT_LAYOUT"}, // + {READ_IMPLIES_EXEC, "READ_IMPLIES_EXEC"}, // + {ADDR_LIMIT_3GB, "ADDR_LIMIT_3GB"}, // + {FDPIC_FUNCPTRS, "FDPIC_FUNCPTRS"}, // + {STICKY_TIMEOUTS, "STICKY_TIMEOUTS"}, // + {MMAP_PAGE_ZERO, "MMAP_PAGE_ZERO"}, // + {ADDR_LIMIT_32BIT, "ADDR_LIMIT_32BIT"}, // + {WHOLE_SECONDS, "WHOLE_SECONDS"}, // + {ADDR_NO_RANDOMIZE, "ADDR_NO_RANDOMIZE"}, // + {SHORT_INODE, "SHORT_INODE"}, // + {UNAME26, "UNAME26"}, // +}; + +const char *DescribePersonalityFlags(int x) { + _Alignas(char) static char personalityflags[128]; + return DescribeFlags(personalityflags, sizeof(personalityflags), + kPersonalityFlags, ARRAYLEN(kPersonalityFlags), "", x); +} diff --git a/libc/intrin/deviceiocontrol.greg.c b/libc/intrin/deviceiocontrol.greg.c index 903137913..456f8026f 100644 --- a/libc/intrin/deviceiocontrol.greg.c +++ b/libc/intrin/deviceiocontrol.greg.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/exit1.greg.c b/libc/intrin/exit1.greg.c index 90e43e5f1..9f340725c 100644 --- a/libc/intrin/exit1.greg.c +++ b/libc/intrin/exit1.greg.c @@ -19,7 +19,6 @@ #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/setjmp.internal.h" -#include "libc/intrin/winthread.internal.h" #include "libc/nt/thread.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/nr.h" @@ -34,14 +33,13 @@ */ privileged wontreturn void _Exit1(int rc) { struct WinThread *wt; - /* STRACE("_Exit1(%d)", rc); */ + STRACE("_Exit1(%d)", rc); if (!IsWindows() && !IsMetal()) { - register long r10 asm("r10") = 0; - asm volatile("syscall" + asm volatile("xor\t%%r10d,%%r10d\n\t" + "syscall" : /* no outputs */ - : "a"(__NR_exit), "D"(IsLinux() ? rc : 0), "S"(0), "d"(0), - "r"(r10) - : "rcx", "r11", "memory"); + : "a"(__NR_exit), "D"(IsLinux() ? rc : 0), "S"(0), "d"(0) + : "rcx", "r10", "r11", "memory"); } else if (IsWindows()) { ExitThread(rc); } diff --git a/libc/intrin/findclose.greg.c b/libc/intrin/findclose.c similarity index 97% rename from libc/intrin/findclose.greg.c rename to libc/intrin/findclose.c index 17fe27fe7..652d4f9cd 100644 --- a/libc/intrin/findclose.greg.c +++ b/libc/intrin/findclose.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/findfirstfile.greg.c b/libc/intrin/findfirstfile.c similarity index 98% rename from libc/intrin/findfirstfile.greg.c rename to libc/intrin/findfirstfile.c index 76936932d..02a431208 100644 --- a/libc/intrin/findfirstfile.greg.c +++ b/libc/intrin/findfirstfile.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/files.h" #include "libc/nt/memory.h" diff --git a/libc/intrin/findnextfile.greg.c b/libc/intrin/findnextfile.c similarity index 98% rename from libc/intrin/findnextfile.greg.c rename to libc/intrin/findnextfile.c index 750ea2138..5f3f0b08b 100644 --- a/libc/intrin/findnextfile.greg.c +++ b/libc/intrin/findnextfile.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/errors.h" #include "libc/nt/files.h" diff --git a/libc/intrin/flushfilebuffers.greg.c b/libc/intrin/flushfilebuffers.c similarity index 98% rename from libc/intrin/flushfilebuffers.greg.c rename to libc/intrin/flushfilebuffers.c index e6b4c90e4..918f5d321 100644 --- a/libc/intrin/flushfilebuffers.greg.c +++ b/libc/intrin/flushfilebuffers.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" __msabi extern typeof(FlushFileBuffers) *const __imp_FlushFileBuffers; diff --git a/libc/intrin/flushviewoffile.greg.c b/libc/intrin/flushviewoffile.c similarity index 98% rename from libc/intrin/flushviewoffile.greg.c rename to libc/intrin/flushviewoffile.c index e8ad6082c..9912b3534 100644 --- a/libc/intrin/flushviewoffile.greg.c +++ b/libc/intrin/flushviewoffile.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/memory.h" __msabi extern typeof(FlushViewOfFile) *const __imp_FlushViewOfFile; diff --git a/libc/intrin/ftrace.c b/libc/intrin/ftrace.c index 58f88f986..202fe746c 100644 --- a/libc/intrin/ftrace.c +++ b/libc/intrin/ftrace.c @@ -18,4 +18,25 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/runtime.h" -int g_ftrace; +/** + * Function tracing enabled state. + * + * After ftrace_install() has been called, the logging of C function + * calls may be controlled by changing this variable. If `__ftrace` is + * greater than zero, functions are logged. Otherwise, they aren't. + * + * By convention, functions wishing to disable function tracing for a + * short time period should say: + * + * void foo() { + * --__ftrace; + * bar(); + * ++__ftrace; + * } + * + * This way you still have some flexibility to force function tracing, + * by setting `__ftrace` to a higher number like `2` or `200`. Even + * though under normal circumstances, `__ftrace` should only be either + * zero or one. + */ +_Atomic(int) __ftrace; diff --git a/libc/intrin/g_fds.c b/libc/intrin/g_fds.c index d071e00b0..9f575dcd6 100644 --- a/libc/intrin/g_fds.c +++ b/libc/intrin/g_fds.c @@ -25,7 +25,7 @@ STATIC_YOINK("_init_g_fds"); struct Fds g_fds; -_Alignas(64) char __fds_lock; +_Alignas(64) int __fds_lock; textstartup void InitializeFileDescriptors(void) { struct Fds *fds; diff --git a/libc/intrin/generateconsolectrlevent.greg.c b/libc/intrin/generateconsolectrlevent.c similarity index 98% rename from libc/intrin/generateconsolectrlevent.greg.c rename to libc/intrin/generateconsolectrlevent.c index 4617973d2..31cfbf60f 100644 --- a/libc/intrin/generateconsolectrlevent.greg.c +++ b/libc/intrin/generateconsolectrlevent.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/console.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/getexitcodeprocess.greg.c b/libc/intrin/getexitcodeprocess.c similarity index 97% rename from libc/intrin/getexitcodeprocess.greg.c rename to libc/intrin/getexitcodeprocess.c index 9fd02ea1e..8a783e3a7 100644 --- a/libc/intrin/getexitcodeprocess.greg.c +++ b/libc/intrin/getexitcodeprocess.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/accounting.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/getfileattributes.greg.c b/libc/intrin/getfileattributes.c similarity index 98% rename from libc/intrin/getfileattributes.greg.c rename to libc/intrin/getfileattributes.c index c7dcc4c00..943ce0f9e 100644 --- a/libc/intrin/getfileattributes.greg.c +++ b/libc/intrin/getfileattributes.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/files.h" diff --git a/libc/intrin/getmagnumstr.greg.c b/libc/intrin/getmagnumstr.greg.c index 20834e936..7bcbbc542 100644 --- a/libc/intrin/getmagnumstr.greg.c +++ b/libc/intrin/getmagnumstr.greg.c @@ -18,7 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/magnumstrs.internal.h" -char *GetMagnumStr(const struct MagnumStr *ms, int x) { +privileged char *GetMagnumStr(const struct MagnumStr *ms, int x) { int i; for (i = 0; ms[i].x != MAGNUM_TERMINATOR; ++i) { if (x == MAGNUM_NUMBER(ms, i)) { diff --git a/libc/intrin/getpid.c b/libc/intrin/getpid.c index 0d8113aed..a0d0c032d 100644 --- a/libc/intrin/getpid.c +++ b/libc/intrin/getpid.c @@ -17,12 +17,23 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/runtime/internal.h" /** * Returns process id. + * + * This function does not need to issue a system call. The PID is + * tracked by a global variable which is updated atfork(). The only + * exception is when the process is vfork()'d in which case a system + * call shall be issued. + * + * On Linux, and only Linux, the process id is guaranteed to be the same + * as gettid() for the main thread. + * * @asyncsignalsafe + * @threadsafe * @vforksafe */ int getpid(void) { diff --git a/libc/intrin/gettid.greg.c b/libc/intrin/gettid.greg.c index 28c5cc548..9e3cc2802 100644 --- a/libc/intrin/gettid.greg.c +++ b/libc/intrin/gettid.greg.c @@ -18,20 +18,52 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/dce.h" -#include "libc/intrin/tls.h" +#include "libc/nexgen32e/threaded.h" #include "libc/nt/thread.h" +#include "libc/nt/thunk/msabi.h" +#include "libc/runtime/internal.h" + +__msabi extern typeof(GetCurrentThreadId) *const __imp_GetCurrentThreadId; /** * Returns current thread id. + * + * On Linux, and Linux only, this is guaranteed to be equal to getpid() + * if this is the main thread. On NetBSD, gettid() for the main thread + * is always 1. + * + * This function issues a system call. That stops being the case as soon + * as __install_tls() is called. That'll happen automatically, when you + * call clone() and provide the TLS parameter. We assume that when a TLS + * block exists, then + * + * *(int *)(__get_tls() + 0x38) + * + * will contain the thread id. Therefore when issuing clone() calls, the + * `CLONE_CHILD_SETTID` and `CLONE_CHILD_CLEARTID` flags should use that + * index as its `ctid` memory. + * + * gettid (single threaded) l: 126𝑐 41𝑛𝑠 + * gettid (tls enabled) l: 2𝑐 1𝑛𝑠 + * + * The TLS convention is important for reentrant lock performance. + * + * @return thread id greater than zero or -1 w/ errno * @asyncsignalsafe + * @threadsafe */ privileged int gettid(void) { int rc; int64_t wut; struct WinThread *wt; + if (__tls_enabled) { + rc = *(int *)(__get_tls() + 0x38); + return rc; + } + if (IsWindows()) { - return GetCurrentThreadId(); + return __imp_GetCurrentThreadId(); } if (IsLinux()) { @@ -76,5 +108,5 @@ privileged int gettid(void) { return wut; // narrowing intentional } - return getpid(); + return __pid; } diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index 50463291d..6bf9df84f 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -46,6 +46,8 @@ $(LIBC_INTRIN_A_OBJS): \ OVERRIDE_CFLAGS += \ -foptimize-sibling-calls +# we can't use asan and ubsan because: +# this is asan and ubsan o/$(MODE)/libc/intrin/asan.o \ o/$(MODE)/libc/intrin/ubsan.o: \ OVERRIDE_CFLAGS += \ @@ -58,68 +60,93 @@ o/$(MODE)/libc/intrin/asan.o: \ -finline \ -finline-functions +# we can't use compiler magic because: +# kprintf() is mission critical to error reporting +o/$(MODE)/libc/intrin/getmagnumstr.greg.o \ +o/$(MODE)/libc/intrin/strerrno.greg.o \ +o/$(MODE)/libc/intrin/strerrdoc.greg.o \ +o/$(MODE)/libc/intrin/strerror_wr.greg.o \ o/$(MODE)/libc/intrin/kprintf.greg.o: \ OVERRIDE_CFLAGS += \ -fpie \ + -fwrapv \ + -x-no-pg \ + -mno-fentry \ -ffreestanding \ - $(NO_MAGIC) + -fno-sanitize=all \ + -fno-stack-protector + +# we can't use compiler magic because: +# spinlocks are called very early in initialization +# e.g. __cxa_atexit() +o/$(MODE)/libc/intrin/gettid.greg.o \ +o/$(MODE)/libc/intrin/_trylock_debug_4.o \ +o/$(MODE)/libc/intrin/_spinlock_debug_4.o: \ + OVERRIDE_CFLAGS += \ + -fwrapv \ + -x-no-pg \ + -mno-fentry \ + -ffreestanding \ + -fno-sanitize=all \ + -fno-stack-protector o/$(MODE)/libc/intrin/tls.greg.o \ o/$(MODE)/libc/intrin/exit.greg.o \ o/$(MODE)/libc/intrin/exit1.greg.o \ -o/$(MODE)/libc/intrin/gettid.greg.o \ o/$(MODE)/libc/intrin/getenv.greg.o \ -o/$(MODE)/libc/intrin/createfile.greg.o \ o/$(MODE)/libc/intrin/assertfail.greg.o \ -o/$(MODE)/libc/intrin/reopenfile.greg.o \ -o/$(MODE)/libc/intrin/deletefile.greg.o \ -o/$(MODE)/libc/intrin/createpipe.greg.o \ -o/$(MODE)/libc/intrin/closehandle.greg.o \ o/$(MODE)/libc/intrin/describeiov.greg.o \ -o/$(MODE)/libc/intrin/openprocess.greg.o \ -o/$(MODE)/libc/intrin/createthread.greg.o \ o/$(MODE)/libc/intrin/describestat.greg.o \ -o/$(MODE)/libc/intrin/findnextfile.greg.o \ -o/$(MODE)/libc/intrin/createprocess.greg.o \ -o/$(MODE)/libc/intrin/findfirstfile.greg.o \ o/$(MODE)/libc/intrin/describeflags.greg.o \ o/$(MODE)/libc/intrin/describerlimit.greg.o \ -o/$(MODE)/libc/intrin/removedirectory.greg.o \ -o/$(MODE)/libc/intrin/createnamedpipe.greg.o \ -o/$(MODE)/libc/intrin/unmapviewoffile.greg.o \ -o/$(MODE)/libc/intrin/flushviewoffile.greg.o \ o/$(MODE)/libc/intrin/deviceiocontrol.greg.o \ -o/$(MODE)/libc/intrin/createdirectory.greg.o \ -o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \ -o/$(MODE)/libc/intrin/terminateprocess.greg.o \ o/$(MODE)/libc/intrin/describemapflags.greg.o \ o/$(MODE)/libc/intrin/describetimespec.greg.o \ -o/$(MODE)/libc/intrin/getfileattributes.greg.o \ -o/$(MODE)/libc/intrin/getexitcodeprocess.greg.o \ -o/$(MODE)/libc/intrin/waitforsingleobject.greg.o \ -o/$(MODE)/libc/intrin/setcurrentdirectory.greg.o \ -o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \ -o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \ -o/$(MODE)/libc/intrin/waitformultipleobjects.greg.o \ -o/$(MODE)/libc/intrin/generateconsolectrlevent.greg.o \ +o/$(MODE)/libc/intrin/createfile.o \ +o/$(MODE)/libc/intrin/reopenfile.o \ +o/$(MODE)/libc/intrin/deletefile.o \ +o/$(MODE)/libc/intrin/createpipe.o \ +o/$(MODE)/libc/intrin/closehandle.o \ +o/$(MODE)/libc/intrin/openprocess.o \ +o/$(MODE)/libc/intrin/createthread.o \ +o/$(MODE)/libc/intrin/findclose.o \ +o/$(MODE)/libc/intrin/findnextfile.o \ +o/$(MODE)/libc/intrin/createprocess.o \ +o/$(MODE)/libc/intrin/findfirstfile.o \ +o/$(MODE)/libc/intrin/removedirectory.o \ +o/$(MODE)/libc/intrin/createsymboliclink.o \ +o/$(MODE)/libc/intrin/createnamedpipe.o \ +o/$(MODE)/libc/intrin/unmapviewoffile.o \ +o/$(MODE)/libc/intrin/virtualprotect.o \ +o/$(MODE)/libc/intrin/flushviewoffile.o \ +o/$(MODE)/libc/intrin/createdirectory.o \ +o/$(MODE)/libc/intrin/flushfilebuffers.o \ +o/$(MODE)/libc/intrin/terminateprocess.o \ +o/$(MODE)/libc/intrin/getfileattributes.o \ +o/$(MODE)/libc/intrin/getexitcodeprocess.o \ +o/$(MODE)/libc/intrin/waitforsingleobject.o \ +o/$(MODE)/libc/intrin/setcurrentdirectory.o \ +o/$(MODE)/libc/intrin/mapviewoffileex.o \ +o/$(MODE)/libc/intrin/movefileex.o \ +o/$(MODE)/libc/intrin/mapviewoffileexnuma.o \ +o/$(MODE)/libc/intrin/createfilemapping.o \ +o/$(MODE)/libc/intrin/createfilemappingnuma.o \ +o/$(MODE)/libc/intrin/waitformultipleobjects.o \ +o/$(MODE)/libc/intrin/generateconsolectrlevent.o \ o/$(MODE)/libc/intrin/kstarttsc.o \ o/$(MODE)/libc/intrin/nomultics.o \ o/$(MODE)/libc/intrin/ntconsolemode.o: \ OVERRIDE_CFLAGS += \ -Os \ + -fwrapv \ -ffreestanding \ - $(NO_MAGIC) + -fno-stack-protector \ + -fno-sanitize=all o/$(MODE)/libc/intrin/describeopenflags.greg.o: \ OVERRIDE_CPPFLAGS += \ -DSTACK_FRAME_UNLIMITED -o/$(MODE)/libc/intrin/asan.o \ -o/$(MODE)/libc/intrin/ubsan.o: \ - OVERRIDE_CFLAGS += \ - -fno-sanitize=all \ - -fno-stack-protector - o//libc/intrin/memmove.o: \ OVERRIDE_CFLAGS += \ -fno-toplevel-reorder diff --git a/libc/intrin/kdos2errno.S b/libc/intrin/kdos2errno.S index f09390e7f..3bab83afd 100644 --- a/libc/intrin/kdos2errno.S +++ b/libc/intrin/kdos2errno.S @@ -27,7 +27,7 @@ .long \systemv - kDos2Errno .endm - .section .rodata + .section .rodata,"a",@progbits .underrun kDos2Errno: // .e kNtErrorInvalidFunction,ENOSYS # in consts.sh diff --git a/libc/fmt/kerrnodocs.S b/libc/intrin/kerrnodocs.S similarity index 100% rename from libc/fmt/kerrnodocs.S rename to libc/intrin/kerrnodocs.S diff --git a/libc/fmt/kerrnonames.S b/libc/intrin/kerrnonames.S similarity index 100% rename from libc/fmt/kerrnonames.S rename to libc/intrin/kerrnonames.S diff --git a/libc/intrin/kopenflags.S b/libc/intrin/kopenflags.S index a0749a5af..e00ebf792 100644 --- a/libc/intrin/kopenflags.S +++ b/libc/intrin/kopenflags.S @@ -40,6 +40,7 @@ kOpenFlags: .e O_TRUNC,"TRUNC" // .e O_CLOEXEC,"CLOEXEC" // .e O_NONBLOCK,"NONBLOCK" // + .e O_DIRECTORY,"DIRECTORY" // .e O_DIRECT,"DIRECT" // no-op on xnu/openbsd .e O_APPEND,"APPEND" // weird on nt .e O_TMPFILE,"TMPFILE" // linux, windows diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 90f8177c5..82f3395f2 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -17,11 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #define ShouldUseMsabiAttribute() 1 +#include "libc/bits/bits.h" #include "libc/bits/likely.h" #include "libc/bits/safemacros.internal.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/divmod10.internal.h" @@ -31,11 +32,11 @@ #include "libc/intrin/lockcmpxchg.h" #include "libc/intrin/nomultics.internal.h" #include "libc/intrin/spinlock.h" -#include "libc/intrin/threaded.internal.h" #include "libc/limits.h" #include "libc/log/internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" +#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/uart.internal.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" @@ -52,6 +53,8 @@ #include "libc/sysv/consts/prot.h" #include "libc/time/clockstonanos.internal.h" +extern hidden struct SymbolTable *__symtab; + struct Timestamps { unsigned long long birth; unsigned long long start; @@ -262,6 +265,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, continue; case '#': + case '`': hash = '0'; continue; @@ -514,13 +518,19 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, } case 't': { + // %t will print the &symbol associated with an address. this + // requires that some other code linked GetSymbolTable() and + // called it beforehand to ensure the symbol table is loaded. + // if the symbol table isn't linked or available, then this + // routine will display &hexaddr so objdump -dS foo.com.dbg + // can be manually consulted to look up the faulting code. int idx; x = va_arg(va, intptr_t); - if (weaken(__get_symbol) && + if (weaken(__symtab) && *weaken(__symtab) && (idx = weaken(__get_symbol)(0, x)) != -1) { if (p + 1 <= e) *p++ = '&'; - s = weaken(GetSymbolTable)()->name_base + - weaken(GetSymbolTable)()->names[idx]; + s = (*weaken(__symtab))->name_base + + (*weaken(__symtab))->names[idx]; goto FormatString; } base = 4; @@ -698,9 +708,14 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, if (p < e) *p = hash; ++p; } - for (; cols > i; --cols) { - if (p < e) { + while (cols > i) { + if (p + 8 < e && cols - i > 8) { + WRITE64LE(p, 0x2020202020202020); + cols -= 8; + p += 8; + } else if (p < e) { *p++ = ' '; + --cols; } else { p = kadvance(p, e, cols - i); break; @@ -842,7 +857,6 @@ privileged void kvprintf(const char *fmt, va_list v) { * * Specifiers: * - * - `P` pid * - `c` char * - `o` octal * - `b` binary @@ -858,6 +872,7 @@ privileged void kvprintf(const char *fmt, va_list v) { * - `X` uppercase * - `T` timestamp * - `x` hexadecimal + * - `P` pid (or tid if threaded) * * Types: * diff --git a/libc/intrin/lockcmpxchgp.h b/libc/intrin/lockcmpxchgp.h new file mode 100644 index 000000000..fdf12d3ab --- /dev/null +++ b/libc/intrin/lockcmpxchgp.h @@ -0,0 +1,24 @@ +#ifndef COSMOPOLITAN_LIBC_INTRIN_LOCKCMPXCHGP_H_ +#define COSMOPOLITAN_LIBC_INTRIN_LOCKCMPXCHGP_H_ +#include "libc/bits/asmflag.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__) +#define _lockcmpxchgp(IN_OUT_IFTHING, IN_OUT_ISEQUALTOME, IN_REPLACEITWITHME) \ + ({ \ + bool DidIt; \ + autotype(IN_OUT_IFTHING) IfThing = (IN_OUT_IFTHING); \ + typeof(IfThing) IsEqualToMe = (IN_OUT_ISEQUALTOME); \ + typeof(*IfThing) ReplaceItWithMe = (IN_REPLACEITWITHME); \ + asm volatile(ZFLAG_ASM("lock cmpxchg\t%3,%1") \ + : ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(*IsEqualToMe) \ + : "r"(ReplaceItWithMe) \ + : "cc"); \ + DidIt; \ + }) +#endif /* GNUC && !ANSI && x86 */ + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_INTRIN_LOCKCMPXCHGP_H_ */ diff --git a/libc/intrin/mapviewoffileex.greg.c b/libc/intrin/mapviewoffileex.c similarity index 98% rename from libc/intrin/mapviewoffileex.greg.c rename to libc/intrin/mapviewoffileex.c index 778e56497..3542063d1 100644 --- a/libc/intrin/mapviewoffileex.greg.c +++ b/libc/intrin/mapviewoffileex.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/enum/filemapflags.h" #include "libc/nt/memory.h" diff --git a/libc/intrin/mapviewoffileexnuma.greg.c b/libc/intrin/mapviewoffileexnuma.c similarity index 98% rename from libc/intrin/mapviewoffileexnuma.greg.c rename to libc/intrin/mapviewoffileexnuma.c index dbbe9e3e5..9ec6faae3 100644 --- a/libc/intrin/mapviewoffileexnuma.greg.c +++ b/libc/intrin/mapviewoffileexnuma.c @@ -17,8 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/enum/filemapflags.h" diff --git a/libc/intrin/movefileex.greg.c b/libc/intrin/movefileex.c similarity index 98% rename from libc/intrin/movefileex.greg.c rename to libc/intrin/movefileex.c index 8f497ab8c..5eb10ab26 100644 --- a/libc/intrin/movefileex.greg.c +++ b/libc/intrin/movefileex.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/files.h" #include "libc/nt/memory.h" diff --git a/libc/intrin/ntgetversion.c b/libc/intrin/ntgetversion.c index 57c7ea551..d458b68b2 100644 --- a/libc/intrin/ntgetversion.c +++ b/libc/intrin/ntgetversion.c @@ -22,9 +22,9 @@ /** * Returns New Technology version, e.g. * - * if (IsWindows() && NtGetVersion() >=k NtVersionWindows10) {...} - * * This can only be called on Windows. + * + * @see IsAtLeastWindows10() */ textwindows noasan int NtGetVersion(void) { return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion; diff --git a/libc/intrin/once.h b/libc/intrin/once.h index 52eb74f2d..8aa755ad9 100644 --- a/libc/intrin/once.h +++ b/libc/intrin/once.h @@ -2,20 +2,20 @@ #define COSMOPOLITAN_LIBC_INTRIN_ONCE_H_ #include "libc/intrin/spinlock.h" -#define _once(x) \ - ({ \ - typeof(x) oncerc; \ - static bool once; \ - static typeof(oncerc) onceresult; \ - _Alignas(64) static char oncelock; \ - _spinlock(&oncelock); \ - if (once) { \ - oncerc = onceresult; \ - } else { \ - oncerc = onceresult = x; \ - } \ - _spunlock(&oncelock); \ - oncerc; \ +#define _once(x) \ + ({ \ + typeof(x) oncerc; \ + static bool once; \ + static typeof(oncerc) onceresult; \ + _Alignas(64) static int oncelock; \ + _spinlock(&oncelock); \ + if (once) { \ + oncerc = onceresult; \ + } else { \ + oncerc = onceresult = x; \ + } \ + _spunlock(&oncelock); \ + oncerc; \ }) #endif /* COSMOPOLITAN_LIBC_INTRIN_ONCE_H_ */ diff --git a/libc/intrin/openprocess.greg.c b/libc/intrin/openprocess.c similarity index 98% rename from libc/intrin/openprocess.greg.c rename to libc/intrin/openprocess.c index 897d4f7c9..44f570c19 100644 --- a/libc/intrin/openprocess.greg.c +++ b/libc/intrin/openprocess.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/memory.h" #include "libc/nt/process.h" diff --git a/libc/intrin/prot2nt.greg.c b/libc/intrin/prot2nt.greg.c index 4547a57ee..80b7a78a3 100644 --- a/libc/intrin/prot2nt.greg.c +++ b/libc/intrin/prot2nt.greg.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/nt/enum/pageflags.h" #include "libc/runtime/directmap.internal.h" #include "libc/sysv/consts/prot.h" diff --git a/libc/intrin/releasefd.c b/libc/intrin/releasefd.c index 3b9410d36..48124c3cb 100644 --- a/libc/intrin/releasefd.c +++ b/libc/intrin/releasefd.c @@ -17,14 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" void __releasefd(int fd) { _spinlock(&__fds_lock); - if (0 <= fd && fd < g_fds.n) { - g_fds.p[fd].kind = 0; - g_fds.f = MIN(fd, g_fds.f); - } + __releasefd_unlocked(fd); _spunlock(&__fds_lock); } diff --git a/libc/calls/getfdhandleactual.greg.c b/libc/intrin/releasefd_unlocked.c similarity index 90% rename from libc/calls/getfdhandleactual.greg.c rename to libc/intrin/releasefd_unlocked.c index b0f797b12..6be6460b8 100644 --- a/libc/calls/getfdhandleactual.greg.c +++ b/libc/intrin/releasefd_unlocked.c @@ -17,12 +17,11 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" -#include "libc/sock/ntstdin.internal.h" +#include "libc/macros.internal.h" -int64_t __getfdhandleactual(int fd) { - if (g_fds.p[fd].worker) { - return g_fds.p[fd].worker->reader; - } else { - return g_fds.p[fd].handle; +void __releasefd_unlocked(int fd) { + if (0 <= fd && fd < g_fds.n) { + g_fds.p[fd].kind = 0; + g_fds.f = MIN(fd, g_fds.f); } } diff --git a/libc/intrin/removedirectory.greg.c b/libc/intrin/removedirectory.c similarity index 97% rename from libc/intrin/removedirectory.greg.c rename to libc/intrin/removedirectory.c index 6f6035c54..6d1709fe8 100644 --- a/libc/intrin/removedirectory.greg.c +++ b/libc/intrin/removedirectory.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/reopenfile.greg.c b/libc/intrin/reopenfile.c similarity index 98% rename from libc/intrin/reopenfile.greg.c rename to libc/intrin/reopenfile.c index b20292ae6..2aef55ebd 100644 --- a/libc/intrin/reopenfile.greg.c +++ b/libc/intrin/reopenfile.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/nt/files.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/sched_yield.S b/libc/intrin/sched_yield.S new file mode 100644 index 000000000..c0a7d80bd --- /dev/null +++ b/libc/intrin/sched_yield.S @@ -0,0 +1,69 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" +#include "libc/sysv/consts/nr.h" +#include "libc/macros.internal.h" +.privileged + +// Asks kernel to let other threads be scheduled. +// +// @return 0 on success, or -1 w/ errno +sched_yield: + +#if SupportsWindows() +// Windows Support +// +// A value of zero, together with the bAlertable parameter set to +// FALSE, causes the thread to relinquish the remainder of its time +// slice to any other thread that is ready to run, if there are no +// pending user APCs on the calling thread. If there are no other +// threads ready to run and no user APCs are queued, the function +// returns immediately, and the thread continues execution. +// ──Quoth MSDN + testb IsWindows() + jz 1f + push %rbp + mov %rsp,%rbp + xor %ecx,%ecx + xor %edx,%edx + ntcall __imp_SleepEx + xor %eax,%eax + pop %rbp + ret +#endif + +#if SupportsSystemv() +// UNIX Support +1: mov __NR_sched_yield,%eax +#if SupportsBsd() && SupportsLinux() + clc +#endif + syscall +#if SupportsBsd() + jc systemfive_errno +#endif +#if SupportsLinux() + cmp $-4095,%rax + jae systemfive_error +#endif +#endif + +2: ret + .endfn sched_yield,globl + .previous diff --git a/libc/intrin/setcurrentdirectory.greg.c b/libc/intrin/setcurrentdirectory.c similarity index 97% rename from libc/intrin/setcurrentdirectory.greg.c rename to libc/intrin/setcurrentdirectory.c index 28f0f9516..9045f7277 100644 --- a/libc/intrin/setcurrentdirectory.greg.c +++ b/libc/intrin/setcurrentdirectory.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/files.h" #include "libc/nt/memory.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/spinlock.h b/libc/intrin/spinlock.h index e66e1aec2..b1df648dc 100644 --- a/libc/intrin/spinlock.h +++ b/libc/intrin/spinlock.h @@ -1,65 +1,83 @@ #ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ #define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ -#include "libc/bits/weaken.h" +#include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/intrin/kprintf.h" -#include "libc/log/backtrace.internal.h" -#include "libc/log/log.h" +#include "libc/intrin/lockcmpxchg.h" +#include "libc/intrin/lockcmpxchgp.h" +/*───────────────────────────────────────────────────────────────────────────│─╗ +│ cosmopolitan § spinlocks ─╬─│┼ +╚────────────────────────────────────────────────────────────────────────────│─╝ + privileged unsophisticated locking subroutines */ -#if defined(_SPINLOCK_DEBUG) -#define _spinlock(lock) _spinlock_debug(lock) -#elif defined(TINY) -#define _spinlock(lock) _spinlock_tiny(lock) -#else -#define _spinlock(lock) _spinlock_optimistic(lock) +#if IsModeDbg() && !defined(_SPINLOCK_DEBUG) +#define _SPINLOCK_DEBUG #endif -#define _spunlock(lock) __atomic_clear(lock, __ATOMIC_RELAXED) +#if defined(_SPINLOCK_DEBUG) +#define _spinlock(lock) _spinlock_ndebug(lock) +#define _spinlock_ndebug(lock) _spinlock_cooperative(lock) +#define _trylock(lock) _trylock_debug(lock) +#define _seizelock(lock) _seizelock_impl(lock, gettid()) +#elif defined(TINY) +#define _spinlock(lock) _spinlock_tiny(lock) +#define _spinlock_ndebug(lock) _spinlock_tiny(lock) +#define _trylock(lock) _trylock_inline(lock) +#define _seizelock(lock) _seizelock_impl(lock, 1) +#else +#define _spinlock(lock) _spinlock_cooperative(lock) +#define _spinlock_ndebug(lock) _spinlock_cooperative(lock) +#define _trylock(lock) _trylock_inline(lock) +#define _seizelock(lock) _seizelock_impl(lock, 1) +#endif -#define _trylock(lock) __atomic_test_and_set(lock, __ATOMIC_SEQ_CST) +#define _trylock_inline(lock) __atomic_test_and_set(lock, __ATOMIC_SEQ_CST) -#define _seizelock(lock) \ - do { \ - typeof(*(lock)) x = 1; \ - __atomic_store(lock, &x, __ATOMIC_SEQ_CST); \ +#define _trylock_debug(lock) \ + _trylock_debug_4(lock, #lock, __FILE__, __LINE__, __FUNCTION__) + +#define _spinlock_debug(lock) \ + _spinlock_debug_4(lock, #lock, __FILE__, __LINE__, __FUNCTION__) + +#define _spunlock(lock) \ + do { \ + autotype(lock) __lock = (lock); \ + typeof(*__lock) __x = 0; \ + __atomic_store(__lock, &__x, __ATOMIC_RELAXED); \ } while (0) -#define _spinlock_tiny(lock) \ - do { \ - while (_trylock(lock)) { \ - __builtin_ia32_pause(); \ - } \ +#define _seizelock_impl(lock, value) \ + do { \ + autotype(lock) __lock = (lock); \ + typeof(*__lock) __x = (value); \ + __atomic_store(__lock, &__x, __ATOMIC_RELEASE); \ } while (0) -#define _spinlock_optimistic(lock) \ - do { \ - for (;;) { \ - typeof(*(lock)) x; \ - __atomic_load(lock, &x, __ATOMIC_RELAXED); \ - if (!x && !_trylock(lock)) { \ - break; \ - } else { \ - __builtin_ia32_pause(); \ - } \ - } \ +#define _spinlock_tiny(lock) \ + do { \ + autotype(lock) __lock = (lock); \ + while (_trylock_inline(__lock)) { \ + __builtin_ia32_pause(); \ + } \ } while (0) -#define _spinlock_debug(lock) \ - do { \ - typeof(*(lock)) me, owner; \ - me = gettid(); \ - if (_trylock(lock)) { \ - __atomic_load(lock, &owner, __ATOMIC_RELAXED); \ - if (owner == me) { \ - kprintf("%s:%d: warning: possible spinlock re-entry in %s()\n", \ - __FILE__, __LINE__, __FUNCTION__); \ - if (weaken(ShowBacktrace)) { \ - weaken(ShowBacktrace)(2, 0); \ - } \ - } \ - _spinlock_optimistic(lock); \ - } \ - *lock = me; \ +#define _spinlock_cooperative(lock) \ + do { \ + autotype(lock) __lock = (lock); \ + typeof(*__lock) __x; \ + unsigned __tries = 0; \ + for (;;) { \ + __atomic_load(__lock, &__x, __ATOMIC_RELAXED); \ + if (!__x && !_trylock_inline(__lock)) { \ + break; \ + } else if (++__tries & 7) { \ + __builtin_ia32_pause(); \ + } else { \ + sched_yield(); \ + } \ + } \ } while (0) +int _trylock_debug_4(int *, const char *, const char *, int, const char *); +void _spinlock_debug_4(int *, const char *, const char *, int, const char *); + #endif /* COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ */ diff --git a/libc/intrin/stracef.greg.c b/libc/intrin/stracef.greg.c index ab5fbc4fe..6ca880dbf 100644 --- a/libc/intrin/stracef.greg.c +++ b/libc/intrin/stracef.greg.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/strace.internal.h" #include "libc/intrin/kprintf.h" +#include "libc/runtime/runtime.h" privileged void __stracef(const char *fmt, ...) { va_list v; diff --git a/libc/fmt/strerdoc.greg.c b/libc/intrin/strerdoc.greg.c similarity index 98% rename from libc/fmt/strerdoc.greg.c rename to libc/intrin/strerdoc.greg.c index b8e89b384..07022eca7 100644 --- a/libc/fmt/strerdoc.greg.c +++ b/libc/intrin/strerdoc.greg.c @@ -23,7 +23,7 @@ * Converts errno value to descriptive sentence. * @return non-null rodata string or null if not found */ -char *strerdoc(int x) { +privileged char *strerdoc(int x) { if (x) { return GetMagnumStr(kErrnoDocs, x); } else { diff --git a/libc/fmt/strerrno.greg.c b/libc/intrin/strerrno.greg.c similarity index 98% rename from libc/fmt/strerrno.greg.c rename to libc/intrin/strerrno.greg.c index 145727831..3c9e1a037 100644 --- a/libc/fmt/strerrno.greg.c +++ b/libc/intrin/strerrno.greg.c @@ -23,7 +23,7 @@ * Converts errno value to symbolic name. * @return non-null rodata string or null if not found */ -char *strerrno(int x) { +privileged char *strerrno(int x) { if (x) { return GetMagnumStr(kErrnoNames, x); } else { diff --git a/libc/fmt/strerror_wr.greg.c b/libc/intrin/strerror_wr.greg.c similarity index 97% rename from libc/fmt/strerror_wr.greg.c rename to libc/intrin/strerror_wr.greg.c index 8fad73863..7832eb360 100644 --- a/libc/fmt/strerror_wr.greg.c +++ b/libc/intrin/strerror_wr.greg.c @@ -31,7 +31,7 @@ * @param err is error number or zero if unknown * @return 0 on success, or error code */ -int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) { +privileged int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) { /* kprintf() weakly depends on this function */ int c, n; char16_t winmsg[256]; diff --git a/libc/intrin/terminateprocess.greg.c b/libc/intrin/terminateprocess.c similarity index 97% rename from libc/intrin/terminateprocess.greg.c rename to libc/intrin/terminateprocess.c index 5f308f7cf..c658f1a34 100644 --- a/libc/intrin/terminateprocess.greg.c +++ b/libc/intrin/terminateprocess.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/console.h" #include "libc/nt/runtime.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/threaded.internal.h b/libc/intrin/threaded.internal.h deleted file mode 100644 index 7b31c0b8c..000000000 --- a/libc/intrin/threaded.internal.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_INTRIN_THREADED_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_INTRIN_THREADED_INTERNAL_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern bool __threaded; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_INTRIN_THREADED_INTERNAL_H_ */ diff --git a/libc/intrin/tls.greg.c b/libc/intrin/tls.greg.c index 2dec7159a..3dc87cab7 100644 --- a/libc/intrin/tls.greg.c +++ b/libc/intrin/tls.greg.c @@ -17,73 +17,84 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/calls/calls.h" #include "libc/dce.h" -#include "libc/intrin/tls.h" +#include "libc/errno.h" +#include "libc/nexgen32e/threaded.h" +#include "libc/nt/thread.h" #include "libc/nt/thunk/msabi.h" +#include "libc/sysv/consts/nrlinux.h" -__msabi extern typeof(TlsFree) *const __imp_TlsFree; -__msabi extern typeof(TlsAlloc) *const __imp_TlsAlloc; -__msabi extern typeof(TlsGetValue) *const __imp_TlsGetValue; -__msabi extern typeof(TlsSetValue) *const __imp_TlsSetValue; +#define __NR_sysarch 0x000000a5 +#define __NR___set_tcb 0x00000149 +#define __NR__lwp_setprivate 0x0000013d +#define __NR_thread_fast_set_cthread_self 0x03000003 /** - * Assigns thread-local storage slot. + * Initializes thread information block. * - * This function may for instance be called at startup and the result - * can be assigned to a global static variable; from then on, all the - * threads in your application may pass that value to TlsGetValue, to - * retrieve their thread-local values. + * Here's the layout your c library assumes: * - * @return index on success, or -1u w/ errno - * @threadsafe - */ -uint32_t TlsAlloc(void) { - return __imp_TlsAlloc(); -} - -/** - * Releases thread-local storage slot. - * @threadsafe - */ -bool32 TlsFree(uint32_t dwTlsIndex) { - return __imp_TlsFree(dwTlsIndex); -} - -/** - * Sets value to thread-local storage slot. + * offset size description + * 0x0000 0x08 linear address pointer + * 0x0008 0x08 jmp_buf *exiter + * 0x0010 0x04 exit code + * 0x0030 0x08 linear address pointer + * 0x0038 0x04 tid + * 0x003c 0x04 errno * - * @param dwTlsIndex is something returned by TlsAlloc() - * @return true if successful, otherwise false - * @threadsafe */ -bool32 TlsSetValue(uint32_t dwTlsIndex, void *lpTlsValue) { - assert(IsWindows()); - if (dwTlsIndex < 64) { - asm("mov\t%1,%%gs:%0" - : "=m"(*((long *)0x1480 + dwTlsIndex)) - : "r"(lpTlsValue)); - return true; - } else { - return __imp_TlsSetValue(dwTlsIndex, lpTlsValue); +privileged void *__initialize_tls(char tib[64]) { + if (tib) { + *(intptr_t *)tib = (intptr_t)tib; + *(intptr_t *)(tib + 0x08) = 0; + *(int *)(tib + 0x10) = -1; // exit code + *(intptr_t *)(tib + 0x30) = (intptr_t)tib; + *(int *)(tib + 0x38) = -1; // tid + *(int *)(tib + 0x3c) = 0; } + return tib; } /** - * Retrieves value from thread-local storage slot. - * - * @param dwTlsIndex is something returned by TlsAlloc() - * @return true if successful, otherwise false - * @threadsafe + * Installs thread information block on main process. */ -void *TlsGetValue(uint32_t dwTlsIndex) { - void *lpTlsValue; - assert(IsWindows()); - if (dwTlsIndex < 64) { - asm("mov\t%%gs:%1,%0" - : "=r"(lpTlsValue) - : "m"(*((long *)0x1480 + dwTlsIndex))); - return lpTlsValue; +privileged void __install_tls(char tib[64]) { + int ax, dx; + assert(tib); + assert(!__tls_enabled); + assert(*(int *)(tib + 0x38) != -1); + if (IsWindows()) { + if (!__tls_index) { + __tls_index = TlsAlloc(); + } + asm("mov\t%1,%%gs:%0" : "=m"(*((long *)0x1480 + __tls_index)) : "r"(tib)); + } else if (IsFreebsd()) { + asm volatile("syscall" + : "=a"(ax) + : "0"(__NR_sysarch), "D"(129), "S"(tib) + : "rcx", "r11", "memory", "cc"); + } else if (IsXnu()) { + asm volatile("syscall" + : "=a"(ax) + : "0"(__NR_thread_fast_set_cthread_self), + "D"((intptr_t)tib - 0x30) + : "rcx", "r11", "memory", "cc"); + } else if (IsOpenbsd()) { + asm volatile("syscall" + : "=a"(ax) + : "0"(__NR___set_tcb), "D"(tib) + : "rcx", "r11", "memory", "cc"); + } else if (IsNetbsd()) { + asm volatile("syscall" + : "=a"(ax), "=d"(dx) + : "0"(__NR__lwp_setprivate), "D"(tib) + : "rcx", "r11", "memory", "cc"); } else { - return __imp_TlsGetValue(dwTlsIndex); + asm volatile("syscall" + : "=a"(ax) + : "0"(__NR_linux_arch_prctl), "D"(ARCH_SET_FS), "S"(tib) + : "rcx", "r11", "memory"); } + __tls_enabled = true; } diff --git a/libc/intrin/tls.h b/libc/intrin/tls.h deleted file mode 100644 index 8f539900d..000000000 --- a/libc/intrin/tls.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_INTRIN_TLS_H_ -#define COSMOPOLITAN_LIBC_INTRIN_TLS_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -uint32_t TlsAlloc(void); -bool32 TlsFree(uint32_t); -bool32 TlsSetValue(uint32_t, void *); -void *TlsGetValue(uint32_t); - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_INTRIN_TLS_H_ */ diff --git a/libc/intrin/unmapviewoffile.greg.c b/libc/intrin/unmapviewoffile.c similarity index 97% rename from libc/intrin/unmapviewoffile.greg.c rename to libc/intrin/unmapviewoffile.c index aa7684fa0..455db63d3 100644 --- a/libc/intrin/unmapviewoffile.greg.c +++ b/libc/intrin/unmapviewoffile.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/memory.h" __msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile; diff --git a/libc/intrin/vforked.c b/libc/intrin/vforked.c index 4cb33868a..a93441dd4 100644 --- a/libc/intrin/vforked.c +++ b/libc/intrin/vforked.c @@ -16,6 +16,5 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" int __vforked; diff --git a/libc/intrin/virtualprotect.greg.c b/libc/intrin/virtualprotect.c similarity index 89% rename from libc/intrin/virtualprotect.greg.c rename to libc/intrin/virtualprotect.c index 07fb6f747..d43cf2ab3 100644 --- a/libc/intrin/virtualprotect.greg.c +++ b/libc/intrin/virtualprotect.c @@ -16,14 +16,19 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/intrin/describeflags.internal.h" #include "libc/log/libfatal.internal.h" #include "libc/nt/memory.h" __msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; +static const char *DescribeVpFlags(uint32_t *x) { + if (!x) return "n/a"; + return DescribeNtPageFlags(*x); +} + /** * Protects memory on the New Technology. * @note this wrapper takes care of ABI, STRACE(), and __winerr() @@ -34,13 +39,9 @@ textwindows bool32 VirtualProtect(void *lpAddress, uint64_t dwSize, bool32 bOk; char oldbuf[64]; bOk = __imp_VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); - if (bOk) { - __stpcpy(oldbuf, DescribeNtPageFlags(*lpflOldProtect)); - } else { - __winerr(); - __stpcpy(oldbuf, "n/a"); - } + if (!bOk) __winerr(); NTTRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize, - DescribeNtPageFlags(flNewProtect), oldbuf, bOk); + DescribeNtPageFlags(flNewProtect), + DescribeVpFlags(bOk ? lpflOldProtect : 0), bOk); return bOk; } diff --git a/libc/intrin/waitformultipleobjects.greg.c b/libc/intrin/waitformultipleobjects.c similarity index 98% rename from libc/intrin/waitformultipleobjects.greg.c rename to libc/intrin/waitformultipleobjects.c index 2b6aa0be0..6a7ae4938 100644 --- a/libc/intrin/waitformultipleobjects.greg.c +++ b/libc/intrin/waitformultipleobjects.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/synchronization.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/waitforsingleobject.greg.c b/libc/intrin/waitforsingleobject.c similarity index 97% rename from libc/intrin/waitforsingleobject.greg.c rename to libc/intrin/waitforsingleobject.c index d345ef17b..bde8762ef 100644 --- a/libc/intrin/waitforsingleobject.greg.c +++ b/libc/intrin/waitforsingleobject.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/nt/synchronization.h" #include "libc/nt/thunk/msabi.h" diff --git a/libc/intrin/winthread.internal.h b/libc/intrin/winthread.internal.h deleted file mode 100644 index 0ea54dbd1..000000000 --- a/libc/intrin/winthread.internal.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_RUNTIME_WINTHREAD_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_RUNTIME_WINTHREAD_INTERNAL_H_ -#include "libc/intrin/tls.h" -#include "libc/runtime/runtime.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -struct WinThread { - uint32_t tid; - int flags; - int *ctid; - int (*func)(void *); - void *arg; -}; - -extern int __winthread; - -static inline struct WinThread *GetWinThread(void) { - return TlsGetValue(__winthread); -} - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_RUNTIME_WINTHREAD_INTERNAL_H_ */ diff --git a/libc/isystem/stdatomic.h b/libc/isystem/stdatomic.h new file mode 100644 index 000000000..319a98beb --- /dev/null +++ b/libc/isystem/stdatomic.h @@ -0,0 +1,4 @@ +#ifndef COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_ +#define COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_ +#include "libc/bits/atomic.h" +#endif /* COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_ */ diff --git a/libc/log/backtrace2.greg.c b/libc/log/backtrace2.greg.c index 611d05688..d6646c18b 100644 --- a/libc/log/backtrace2.greg.c +++ b/libc/log/backtrace2.greg.c @@ -23,6 +23,7 @@ #include "libc/calls/calls.h" #include "libc/calls/sigbits.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/conv.h" @@ -74,15 +75,23 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { return -1; } - /* - * DWARF is a weak standard. Platforms that use LLVM or old GNU - * usually can't be counted upon to print backtraces correctly. - */ + // DWARF is a weak standard. Platforms that use LLVM or old GNU + // usually can't be counted upon to print backtraces correctly. if (!IsLinux() && !IsWindows()) { ShowHint("won't print addr2line backtrace because probably llvm"); return -1; } + if (IsWindows()) { + // TODO: We need a way to *not* pass //?/C:/... paths to mingw + return -1; + } + + if (IsLinux() && !__is_linux_2_6_23()) { + // we need the `addr2line -a` option + return -1; + } + i = 0; j = 0; argv[i++] = "addr2line"; @@ -174,12 +183,12 @@ static int PrintBacktrace(int fd, const struct StackFrame *bp) { void ShowBacktrace(int fd, const struct StackFrame *bp) { #ifdef __FNO_OMIT_FRAME_POINTER__ /* asan runtime depends on this function */ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); + --__ftrace; + --__strace; if (!bp) bp = __builtin_frame_address(0); PrintBacktrace(fd, bp); - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); + ++__strace; + ++__ftrace; #else (fprintf)(stderr, "ShowBacktrace() needs these flags to show C backtrace:\n" "\t-D__FNO_OMIT_FRAME_POINTER__\n" diff --git a/libc/log/checkfail.c b/libc/log/checkfail.c index d98055e7e..b6efa27a1 100644 --- a/libc/log/checkfail.c +++ b/libc/log/checkfail.c @@ -45,8 +45,8 @@ relegated void __check_fail(const char *suffix, const char *opstr, size_t i; va_list va; char hostname[32]; - __strace = 0; - g_ftrace = 0; + --__strace; + --__ftrace; e = errno; __start_fatal(file, line); __stpcpy(hostname, "unknown"); @@ -68,7 +68,7 @@ relegated void __check_fail(const char *suffix, const char *opstr, } kprintf("%s\n", RESET); if (!IsTiny() && e == ENOMEM) { - PrintMemoryIntervals(2, &_mmi); + __print_maps(); } __die(); unreachable; diff --git a/libc/log/internal.h b/libc/log/internal.h index 14a644ca8..625da7514 100644 --- a/libc/log/internal.h +++ b/libc/log/internal.h @@ -10,11 +10,11 @@ COSMOPOLITAN_C_START_ extern hidden bool __nocolor; extern hidden int kCrashSigs[7]; extern hidden bool g_isrunningundermake; -extern hidden struct sigaction g_oldcrashacts[7]; void __start_fatal(const char *, int) hidden; void __oncrash(int, struct siginfo *, struct ucontext *) relegated; void __restore_tty(void); +void RestoreDefaultCrashSignalHandlers(void); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/log/leaks.c b/libc/log/leaks.c index 0f61dda6a..16c65ceee 100644 --- a/libc/log/leaks.c +++ b/libc/log/leaks.c @@ -108,7 +108,7 @@ noasan void CheckForMemoryLeaks(void) { } malloc_inspect_all(OnMemory, 0); kprintf("\n"); - PrintMemoryIntervals(2, &_mmi); + __print_maps(); /* PrintSystemMappings(2); */ /* PrintGarbage(); */ __restorewintty(); diff --git a/libc/log/libfatal.internal.h b/libc/log/libfatal.internal.h index eb723f5e6..6e5585e03 100644 --- a/libc/log/libfatal.internal.h +++ b/libc/log/libfatal.internal.h @@ -6,7 +6,6 @@ #include "libc/nexgen32e/bsr.h" #include "libc/nt/process.h" #include "libc/nt/runtime.h" -#include "libc/runtime/runtime.h" #include "libc/sysv/consts/nr.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ diff --git a/libc/log/log.h b/libc/log/log.h index 1c9c8b93b..c026b5982 100644 --- a/libc/log/log.h +++ b/libc/log/log.h @@ -7,6 +7,7 @@ #include "libc/calls/struct/winsize.h" #include "libc/errno.h" #include "libc/nexgen32e/stackframe.h" +#include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" /*───────────────────────────────────────────────────────────────────────────│─╗ @@ -78,24 +79,25 @@ extern unsigned __log_level; /* log level for runtime check */ // log a message with the specified log level (not checking if LOGGABLE) #define LOGF(LEVEL, FMT, ...) \ do { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } while (0) // die with an error message without backtrace and debugger invocation #define DIEF(FMT, ...) \ do { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ if (weaken(__die)) weaken(__die)(); \ - exit(1); \ + __restorewintty(); \ + _Exit(1); \ unreachable; \ } while (0) #define FATALF(FMT, ...) \ do { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ unreachable; \ } while (0) @@ -103,78 +105,78 @@ extern unsigned __log_level; /* log level for runtime check */ #define ERRORF(FMT, ...) \ do { \ if (LOGGABLE(kLogError)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define WARNF(FMT, ...) \ do { \ if (LOGGABLE(kLogWarn)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define INFOF(FMT, ...) \ do { \ if (LOGGABLE(kLogInfo)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define VERBOSEF(FMT, ...) \ do { \ if (LOGGABLE(kLogVerbose)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define DEBUGF(FMT, ...) \ do { \ if (UNLIKELY(LOGGABLE(kLogDebug))) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define NOISEF(FMT, ...) \ do { \ if (UNLIKELY(LOGGABLE(kLogNoise))) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define FLOGF(F, FMT, ...) \ do { \ if (LOGGABLE(kLogInfo)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define FWARNF(F, FMT, ...) \ do { \ if (LOGGABLE(kLogWarn)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define FFATALF(F, FMT, ...) \ do { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ unreachable; \ } while (0) @@ -182,18 +184,18 @@ extern unsigned __log_level; /* log level for runtime check */ #define FDEBUGF(F, FMT, ...) \ do { \ if (UNLIKELY(LOGGABLE(kLogDebug))) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) #define FNOISEF(F, FMT, ...) \ do { \ if (UNLIKELY(LOGGABLE(kLogNoise))) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ } \ } while (0) @@ -206,25 +208,25 @@ extern unsigned __log_level; /* log level for runtime check */ int e = errno; \ autotype(FORM) Ax = (FORM); \ if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ + --__ftrace; \ __logerrno(__FILE__, __LINE__, #FORM); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ + ++__ftrace; \ errno = e; \ } \ Ax; \ }) -#define LOGIFNULL(FORM) \ - ({ \ - int e = errno; \ - autotype(FORM) Ax = (FORM); \ - if (Ax == NULL && LOGGABLE(kLogWarn)) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ - __logerrno(__FILE__, __LINE__, #FORM); \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ - errno = e; \ - } \ - Ax; \ +#define LOGIFNULL(FORM) \ + ({ \ + int e = errno; \ + autotype(FORM) Ax = (FORM); \ + if (Ax == NULL && LOGGABLE(kLogWarn)) { \ + --__ftrace; \ + __logerrno(__FILE__, __LINE__, #FORM); \ + ++__ftrace; \ + errno = e; \ + } \ + Ax; \ }) /*───────────────────────────────────────────────────────────────────────────│─╗ diff --git a/libc/log/log.mk b/libc/log/log.mk index 593dd3982..36930a76f 100644 --- a/libc/log/log.mk +++ b/libc/log/log.mk @@ -75,7 +75,6 @@ o/$(MODE)/libc/log/backtrace3.o \ o/$(MODE)/libc/log/checkaligned.o \ o/$(MODE)/libc/log/checkfail.o \ o/$(MODE)/libc/log/checkfail_ndebug.o \ -o/$(MODE)/libc/log/getsymboltable.o \ o/$(MODE)/libc/log/restoretty.o \ o/$(MODE)/libc/log/oncrash.o \ o/$(MODE)/libc/log/onkill.o \ diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index b517e2ead..b83fbc8bf 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -18,8 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/sigbits.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigaction.h" #include "libc/errno.h" @@ -35,6 +35,7 @@ #include "libc/nexgen32e/stackframe.h" #include "libc/runtime/internal.h" #include "libc/runtime/pc.internal.h" +#include "libc/runtime/runtime.h" /** * @fileoverview Abnormal termination handling & GUI debugging. @@ -57,7 +58,6 @@ static const char kCpuFlags[12] forcealign(1) = "CVPRAKZSTIDO"; static const char kFpuExceptions[6] forcealign(1) = "IDZOUP"; int kCrashSigs[7]; -struct sigaction g_oldcrashacts[7]; relegated static void ShowFunctionCalls(ucontext_t *ctx) { struct StackFrame *bp; @@ -206,8 +206,9 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si, " %m\n" " %s %s %s %s\n", !__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "", sig, - (ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) && - ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE)) + (ctx && + (ctx->uc_mcontext.rsp >= (intptr_t)GetStaticStackAddr(0) && + ctx->uc_mcontext.rsp <= (intptr_t)GetStaticStackAddr(0) + PAGESIZE)) ? "Stack Overflow" : GetSiCodeName(sig, si->si_code), host, getpid(), gettid(), program_invocation_name, names.sysname, @@ -219,7 +220,7 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si, ShowSseRegisters(ctx); } kprintf("\n"); - PrintMemoryIntervals(2, &_mmi); + __print_maps(); /* PrintSystemMappings(2); */ if (__argv) { for (i = 0; i < __argc; ++i) { @@ -231,16 +232,6 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si, kprintf("\n"); } -relegated static void RestoreDefaultCrashSignalHandlers(void) { - size_t i; - sigset_t ss; - sigemptyset(&ss); - sigprocmask(SIG_SETMASK, &ss, NULL); - for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { - if (kCrashSigs[i]) sigaction(kCrashSigs[i], &g_oldcrashacts[i], NULL); - } -} - static wontreturn relegated noinstrument void __minicrash(int sig, struct siginfo *si, ucontext_t *ctx, @@ -277,8 +268,9 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si, intptr_t rip; int gdbpid, err; static bool noreentry, notpossible; - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); + STRACE("__oncrash rip %x", ctx->uc_mcontext.rip); + --__ftrace; + --__strace; if (_lockcmpxchg(&noreentry, false, true)) { if (!__vforked) { rip = ctx ? ctx->uc_mcontext.rip : 0; @@ -316,6 +308,6 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si, } noreentry = false; ItsATrap: - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); + ++__strace; + ++__ftrace; } diff --git a/libc/log/restoretty.greg.c b/libc/log/restoretty.greg.c index 3175a7b3c..2b43b90d7 100644 --- a/libc/log/restoretty.greg.c +++ b/libc/log/restoretty.greg.c @@ -17,9 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/metatermios.internal.h" #include "libc/calls/struct/termios.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" #include "libc/dce.h" #include "libc/errno.h" diff --git a/libc/log/showcrashreports.c b/libc/log/showcrashreports.c index 66edf6490..b7fec5f62 100644 --- a/libc/log/showcrashreports.c +++ b/libc/log/showcrashreports.c @@ -16,13 +16,17 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" #include "libc/calls/sigbits.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaltstack.h" #include "libc/log/internal.h" #include "libc/log/log.h" #include "libc/macros.internal.h" +#include "libc/runtime/stack.h" #include "libc/runtime/symbols.internal.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/ss.h" @@ -32,6 +36,43 @@ STATIC_YOINK("malloc_inspect_all"); /* for asan memory origin */ STATIC_YOINK("__get_symbol_by_addr"); /* for asan memory origin */ extern const unsigned char __oncrash_thunks[8][11]; +static struct sigaltstack g_oldsigaltstack; +static struct sigaction g_oldcrashacts[7]; + +static void InstallCrashHandlers(int extraflags) { + size_t i; + struct sigaction sa; + bzero(&sa, sizeof(sa)); + sa.sa_flags = SA_SIGINFO | SA_NODEFER | extraflags; + sigfillset(&sa.sa_mask); + for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { + sigdelset(&sa.sa_mask, kCrashSigs[i]); + } + for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { + if (kCrashSigs[i]) { + sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i]; + sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]); + } + } +} + +relegated void RestoreDefaultCrashSignalHandlers(void) { + size_t i; + sigset_t ss; + sigemptyset(&ss); + sigprocmask(SIG_SETMASK, &ss, NULL); + for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { + if (kCrashSigs[i]) { + sigaction(kCrashSigs[i], &g_oldcrashacts[i], NULL); + } + } +} + +static void FreeSigAltStack(void *p) { + InstallCrashHandlers(0); + sigaltstack(&g_oldsigaltstack, 0); + munmap(p, GetStackSize()); +} /** * Installs crash signal handlers. @@ -51,8 +92,7 @@ extern const unsigned char __oncrash_thunks[8][11]; * @see callexitontermination() */ void ShowCrashReports(void) { - size_t i; - struct sigaction sa; + char *sp; struct sigaltstack ss; /* : showcrashreports.c, oncrashthunks.S, oncrash.c */ kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */ @@ -63,22 +103,24 @@ void ShowCrashReports(void) { kCrashSigs[5] = SIGABRT; /* abort() called */ kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */ /* : showcrashreports.c, oncrashthunks.S, oncrash.c */ - bzero(&sa, sizeof(sa)); - ss.ss_flags = 0; - ss.ss_size = SIGSTKSZ; - ss.ss_sp = malloc(SIGSTKSZ); - __cxa_atexit(free, ss.ss_sp, 0); - sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; - sigfillset(&sa.sa_mask); - for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { - sigdelset(&sa.sa_mask, kCrashSigs[i]); - } - if (!IsWindows()) sigaltstack(&ss, 0); - for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { - if (kCrashSigs[i]) { - sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i]; - sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]); + if (!IsWindows()) { + bzero(&ss, sizeof(ss)); + ss.ss_flags = 0; + ss.ss_size = GetStackSize(); + // FreeBSD sigaltstack() will EFAULT if we use MAP_STACK here + // OpenBSD sigaltstack() auto-applies MAP_STACK to the memory + if ((sp = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { + ss.ss_sp = sp; + if (!sigaltstack(&ss, &g_oldsigaltstack)) { + __cxa_atexit(FreeSigAltStack, ss.ss_sp, 0); + } else { + munmap(ss.ss_sp, GetStackSize()); + } } + InstallCrashHandlers(SA_ONSTACK); + } else { + InstallCrashHandlers(0); } GetSymbolTable(); } diff --git a/libc/log/vflogf.c b/libc/log/vflogf.c index 42766b264..c67a7d8ff 100644 --- a/libc/log/vflogf.c +++ b/libc/log/vflogf.c @@ -41,24 +41,25 @@ #define kNontrivialSize (8 * 1000 * 1000) static struct timespec vflogf_ts; -_Alignas(64) static char vflogf_lock; /** * Takes corrective action if logging is on the fritz. */ -void vflogf_onfail(FILE *f) { +static void vflogf_onfail(FILE *f) { errno_t err; int64_t size; if (IsTiny()) return; - err = ferror(f); - if (fileno(f) != -1 && (err == ENOSPC || err == EDQUOT || err == EFBIG) && - ((size = getfiledescriptorsize(fileno(f))) == -1 || + err = ferror_unlocked(f); + if (fileno_unlocked(f) != -1 && + (err == ENOSPC || err == EDQUOT || err == EFBIG) && + ((size = getfiledescriptorsize(fileno_unlocked(f))) == -1 || size > kNontrivialSize)) { - ftruncate(fileno(f), 0); - fseek(f, SEEK_SET, 0); + ftruncate(fileno_unlocked(f), 0); + fseeko_unlocked(f, SEEK_SET, 0); f->beg = f->end = 0; - clearerr(f); - (fprintf)(f, "performed emergency log truncation: %s\n", strerror(err)); + clearerr_unlocked(f); + (fprintf_unlocked)(f, "performed emergency log truncation: %s\n", + strerror(err)); } } @@ -88,8 +89,8 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f, int64_t secs, nsec, dots; if (!f) f = __log_file; if (!f) return; - _spinlock(&vflogf_lock); - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); + flockfile(f); + --__strace; t2 = nowl(); secs = t2; @@ -105,16 +106,17 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f, bufmode = f->bufmode; if (bufmode == _IOLBF) f->bufmode = _IOFBF; - if ((fprintf)(f, "%r%c%s%06ld:%s:%d:%.*s:%d] ", "FEWIVDNT"[level & 7], buf32, - rem1000000int64(div1000int64(dots)), file, line, - strchrnul(prog, '.') - prog, prog, getpid()) <= 0) { + if ((fprintf_unlocked)(f, "%r%c%s%06ld:%s:%d:%.*s:%d] ", + "FEWIVDNT"[level & 7], buf32, + rem1000000int64(div1000int64(dots)), file, line, + strchrnul(prog, '.') - prog, prog, getpid()) <= 0) { vflogf_onfail(f); } - (vfprintf)(f, fmt, va); - fprintf(f, "\n"); + (vfprintf_unlocked)(f, fmt, va); + fputc_unlocked('\n', f); if (bufmode == _IOLBF) { f->bufmode = _IOLBF; - fflush(f); + fflush_unlocked(f); } if (level == kLogFatal) { @@ -122,11 +124,10 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f, strcpy(buf32, "unknown"); gethostname(buf32, sizeof(buf32)); (dprintf)(STDERR_FILENO, "fatality %s pid %d\n", buf32, getpid()); - _spunlock(&vflogf_lock); __die(); unreachable; } - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); - _spunlock(&vflogf_lock); + ++__strace; + funlockfile(f); } diff --git a/libc/macros.internal.inc b/libc/macros.internal.inc index f4e0de543..15772f719 100644 --- a/libc/macros.internal.inc +++ b/libc/macros.internal.inc @@ -124,6 +124,15 @@ .section .privileged,"ax",@progbits .endm +// Loads address of errno into %rcx +.macro .errno + call __errno_location +// cs +// cs +// cs +// mov $__errno,%eax +.endm + // Post-Initialization Read-Only (PIRO) BSS section. // @param ss is an optional string, for control image locality .macro .piro ss diff --git a/libc/mem/aligned_alloc.c b/libc/mem/aligned_alloc.c index fc2133098..6c734f313 100644 --- a/libc/mem/aligned_alloc.c +++ b/libc/mem/aligned_alloc.c @@ -27,6 +27,7 @@ * @return memory address, or NULL w/ errno * @throw EINVAL if !IS2POW(a) * @see pvalloc() + * @threadsafe */ void *aligned_alloc(size_t a, size_t n) { if (IS2POW(a)) { diff --git a/libc/mem/asprintf.c b/libc/mem/asprintf.c index 5d20342d0..7e76a84d0 100644 --- a/libc/mem/asprintf.c +++ b/libc/mem/asprintf.c @@ -26,6 +26,7 @@ * portability, since that's guaranteed to work with all libraries * @return bytes written (excluding NUL) or -1 w/ errno * @see xasprintf() for a better API + * @threadsafe */ int(asprintf)(char **strp, const char *fmt, ...) { int res; diff --git a/libc/mem/calloc.S b/libc/mem/calloc.S index 8f89690ef..0486dfac1 100644 --- a/libc/mem/calloc.S +++ b/libc/mem/calloc.S @@ -26,5 +26,6 @@ // @return rax is memory address, or NULL w/ errno // @note overreliance on memalign is a sure way to fragment space // @see dlcalloc() +// @threadsafe calloc: jmp *hook_calloc(%rip) .endfn calloc,globl diff --git a/libc/mem/free.S b/libc/mem/free.S index 0190fe07c..35a7cc937 100644 --- a/libc/mem/free.S +++ b/libc/mem/free.S @@ -28,5 +28,6 @@ // // @param rdi is allocation address, which may be NULL // @see dlfree() +// @threadsafe free: jmp *hook_free(%rip) .endfn free,globl diff --git a/libc/mem/get_current_dir_name.c b/libc/mem/get_current_dir_name.c index 403bffb0c..0f68b0e53 100644 --- a/libc/mem/get_current_dir_name.c +++ b/libc/mem/get_current_dir_name.c @@ -28,6 +28,7 @@ * that'll be returned. * * @return pointer that must be free()'d, or NULL w/ errno + * @threadsafe */ dontdiscard char *get_current_dir_name(void) { const char *p; diff --git a/libc/mem/malloc.S b/libc/mem/malloc.S index 3e7388c66..1afda752c 100644 --- a/libc/mem/malloc.S +++ b/libc/mem/malloc.S @@ -33,5 +33,6 @@ // // @param rdi is number of bytes needed, coerced to 1+ // @return new memory, or NULL w/ errno +// @threadsafe malloc: jmp *hook_malloc(%rip) .endfn malloc,globl diff --git a/libc/mem/malloc_usable_size.S b/libc/mem/malloc_usable_size.S index 0242a7708..161f050fd 100644 --- a/libc/mem/malloc_usable_size.S +++ b/libc/mem/malloc_usable_size.S @@ -35,6 +35,7 @@ // @param rdi is address of allocation // @return rax is total number of bytes // @see dlmalloc_usable_size() +// @threadsafe malloc_usable_size: jmp *hook_malloc_usable_size(%rip) .endfn malloc_usable_size,globl diff --git a/libc/mem/memalign.S b/libc/mem/memalign.S index 9c75364f6..9a8e762ee 100644 --- a/libc/mem/memalign.S +++ b/libc/mem/memalign.S @@ -30,6 +30,7 @@ // @param rsi is number of bytes needed, coerced to 1+ // @return rax is memory address, or NULL w/ errno // @see valloc(), pvalloc() +// @threadsafe memalign: jmp *hook_memalign(%rip) .endfn memalign,globl diff --git a/libc/mem/pledge.c b/libc/mem/pledge.c index 929519fd7..18da884d9 100644 --- a/libc/mem/pledge.c +++ b/libc/mem/pledge.c @@ -17,9 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/filter.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" @@ -238,20 +238,20 @@ static const struct Pledges { const size_t len; } kPledgeLinux[] = { {"default", PLEDGELEN(kPledgeLinuxDefault)}, // - {"stdio", PLEDGELEN(kPledgeLinuxStdio)}, // - {"rpath", PLEDGELEN(kPledgeLinuxRpath)}, // - {"wpath", PLEDGELEN(kPledgeLinuxWpath)}, // - {"cpath", PLEDGELEN(kPledgeLinuxCpath)}, // - {"dpath", PLEDGELEN(kPledgeLinuxDpath)}, // + {"stdio", PLEDGELEN(kPledgeLinuxStdio)}, // + {"rpath", PLEDGELEN(kPledgeLinuxRpath)}, // + {"wpath", PLEDGELEN(kPledgeLinuxWpath)}, // + {"cpath", PLEDGELEN(kPledgeLinuxCpath)}, // + {"dpath", PLEDGELEN(kPledgeLinuxDpath)}, // {"tmppath", PLEDGELEN(kPledgeLinuxTmppath)}, // - {"inet", PLEDGELEN(kPledgeLinuxInet)}, // - {"fattr", PLEDGELEN(kPledgeLinuxFattr)}, // - {"unix", PLEDGELEN(kPledgeLinuxUnix)}, // - {"dns", PLEDGELEN(kPledgeLinuxDns)}, // - {"proc", PLEDGELEN(kPledgeLinuxProc)}, // - {"exec", PLEDGELEN(kPledgeLinuxExec)}, // - {"id", PLEDGELEN(kPledgeLinuxId)}, // - {0}, // + {"inet", PLEDGELEN(kPledgeLinuxInet)}, // + {"fattr", PLEDGELEN(kPledgeLinuxFattr)}, // + {"unix", PLEDGELEN(kPledgeLinuxUnix)}, // + {"dns", PLEDGELEN(kPledgeLinuxDns)}, // + {"proc", PLEDGELEN(kPledgeLinuxProc)}, // + {"exec", PLEDGELEN(kPledgeLinuxExec)}, // + {"id", PLEDGELEN(kPledgeLinuxId)}, // + {0}, // }; static const struct sock_filter kFilterStart[] = { @@ -290,7 +290,8 @@ static bool AppendPledge(struct Filter *f, const uint16_t *p, size_t len) { return true; } -static const uint16_t *FindPledge(const struct Pledges *p, const char *name, size_t *len) { +static const uint16_t *FindPledge(const struct Pledges *p, const char *name, + size_t *len) { int i; for (i = 0; p[i].name; ++i) { if (!strcasecmp(name, p[i].name)) { diff --git a/libc/mem/posix_memalign.c b/libc/mem/posix_memalign.c index a4c173773..3b384ba21 100644 --- a/libc/mem/posix_memalign.c +++ b/libc/mem/posix_memalign.c @@ -35,6 +35,7 @@ * @param bytes is number of bytes to allocate * @return return 0 or EINVAL or ENOMEM w/o setting errno * @see memalign() + * @threadsafe */ int posix_memalign(void **pp, size_t alignment, size_t bytes) { int e; diff --git a/libc/mem/putenv.c b/libc/mem/putenv.c index 27ff77240..be407b1b9 100644 --- a/libc/mem/putenv.c +++ b/libc/mem/putenv.c @@ -105,10 +105,14 @@ Fail: return einval(); } +static void UnsetenvFree(void *p) { + free(p); +} + /* weakly called by unsetenv() when removing a pointer */ void __freeenv(void *p) { if (once) { - __cxa_atexit(free, p, 0); + __cxa_atexit(UnsetenvFree, p, 0); } } diff --git a/libc/mem/pvalloc.c b/libc/mem/pvalloc.c index 1c59640ad..2fb40aea2 100644 --- a/libc/mem/pvalloc.c +++ b/libc/mem/pvalloc.c @@ -25,6 +25,7 @@ * @param n number of bytes needed * @return memory address, or NULL w/ errno * @see valloc() + * @threadsafe */ void *pvalloc(size_t n) { return memalign(PAGESIZE, ROUNDUP(n, PAGESIZE)); diff --git a/libc/mem/realloc.S b/libc/mem/realloc.S index 01f398c1e..b89010ff8 100644 --- a/libc/mem/realloc.S +++ b/libc/mem/realloc.S @@ -53,6 +53,7 @@ // @note realloc(p=0, n=0) → malloc(32) // @note realloc(p≠0, n=0) → free(p) // @see dlrealloc() +// @threadsafe realloc: jmp *hook_realloc(%rip) .endfn realloc,globl diff --git a/libc/mem/realloc_in_place.S b/libc/mem/realloc_in_place.S index 5ad041b76..674393545 100644 --- a/libc/mem/realloc_in_place.S +++ b/libc/mem/realloc_in_place.S @@ -32,6 +32,7 @@ // @param rsi (newsize) is number of bytes needed // @return rax is result, or NULL w/ errno // @see dlrealloc_in_place() +// @threadsafe realloc_in_place: jmp *hook_realloc_in_place(%rip) .endfn realloc_in_place,globl diff --git a/libc/mem/reallocarray.c b/libc/mem/reallocarray.c index 0c1c5750b..c6f2bc548 100644 --- a/libc/mem/reallocarray.c +++ b/libc/mem/reallocarray.c @@ -26,6 +26,7 @@ * @param ptr may be NULL for malloc() behavior * @param nmemb may be 0 for free() behavior; shrinking is promised too * @return new address or NULL w/ errno and ptr is NOT free()'d + * @threadsafe */ void *reallocarray(void *ptr, size_t nmemb, size_t itemsize) { size_t n; diff --git a/libc/mem/strdup.c b/libc/mem/strdup.c index f3fe00ce3..17cb55afb 100644 --- a/libc/mem/strdup.c +++ b/libc/mem/strdup.c @@ -25,6 +25,7 @@ * @param s is a NUL-terminated byte string * @return new string or NULL w/ errno * @error ENOMEM + * @threadsafe */ char *strdup(const char *s) { size_t len = strlen(s); diff --git a/libc/mem/strndup.c b/libc/mem/strndup.c index a4facf3b4..382b57da1 100644 --- a/libc/mem/strndup.c +++ b/libc/mem/strndup.c @@ -26,6 +26,7 @@ * @param n if less than strlen(s) will truncate the string * @return new string or NULL w/ errno * @error ENOMEM + * @threadsafe */ char *strndup(const char *s, size_t n) { char *s2; diff --git a/libc/mem/valloc.c b/libc/mem/valloc.c index 39467eaeb..3f8e0fc77 100644 --- a/libc/mem/valloc.c +++ b/libc/mem/valloc.c @@ -24,6 +24,7 @@ * @param n number of bytes needed * @return memory address, or NULL w/ errno * @see pvalloc() + * @threadsafe */ void *valloc(size_t n) { return memalign(PAGESIZE, n); diff --git a/libc/mem/vasprintf.c b/libc/mem/vasprintf.c index 26ad2fe6c..b002c8a34 100644 --- a/libc/mem/vasprintf.c +++ b/libc/mem/vasprintf.c @@ -23,6 +23,7 @@ /** * Formats string w/ dynamic memory allocation. * @see xasprintf() for a better API + * @threadsafe */ int(vasprintf)(char **strp, const char *fmt, va_list va) { va_list vb; diff --git a/libc/mem/wcsdup.c b/libc/mem/wcsdup.c index c143f7a3c..97e5a8751 100644 --- a/libc/mem/wcsdup.c +++ b/libc/mem/wcsdup.c @@ -21,6 +21,7 @@ /** * Allocates copy of wide string. + * @threadsafe */ wchar_t *wcsdup(const wchar_t *s) { size_t len = wcslen(s); diff --git a/libc/nexgen32e/checkstackalign.S b/libc/nexgen32e/checkstackalign.S new file mode 100644 index 000000000..e944f1b38 --- /dev/null +++ b/libc/nexgen32e/checkstackalign.S @@ -0,0 +1,38 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + +// Checks that stack is 16-byte aligned. +// +// This function crashes if called with a misaligned stack. +CheckStackIsAligned: + push %rbp + mov %rsp,%rbp + +/ allocate sixteen bytes + push %rax + push %rax + +/ put a value in it + xorps %xmm0,%xmm0 + movaps %xmm0,-16(%rbp) + + leave + ret + .endfn CheckStackIsAligned,globl diff --git a/libc/nexgen32e/gc.S b/libc/nexgen32e/gc.S index 08c03c60b..d93859808 100644 --- a/libc/nexgen32e/gc.S +++ b/libc/nexgen32e/gc.S @@ -22,6 +22,8 @@ #define INITIAL_CAPACITY 4 + nop + // Invokes deferred function calls. // // This offers behavior similar to std::unique_ptr. Functions @@ -32,8 +34,6 @@ // // @param rax,rdx,xmm0,xmm1,st0,st1 is return value // @see test/libc/runtime/gc_test.c - nop # backtrace workaround -// __gc: decq __garbage(%rip) mov __garbage(%rip),%r8 mov __garbage+16(%rip),%r9 @@ -43,17 +43,16 @@ __gc: decq __garbage(%rip) mov 8(%r8),%r9 mov 16(%r8),%rdi push 24(%r8) -// push %rbp mov %rsp,%rbp - sub $16,%rsp - push %rax - push %rdx - movdqa %xmm0,-16(%rbp) + sub $32,%rsp + mov %rax,-8(%rbp) + mov %rdx,-16(%rbp) + movdqa %xmm0,-32(%rbp) call *%r9 - movdqa -16(%rbp),%xmm0 - pop %rdx - pop %rax + movdqa -32(%rbp),%xmm0 + mov -16(%rbp),%rdx + mov -8(%rbp),%rax leave ret 9: hlt diff --git a/libc/nexgen32e/nexgen32e.h b/libc/nexgen32e/nexgen32e.h index 56557bba0..c2d45ee3f 100644 --- a/libc/nexgen32e/nexgen32e.h +++ b/libc/nexgen32e/nexgen32e.h @@ -7,6 +7,7 @@ extern long kHalfCache3; void imapxlatab(void *); void insertionsort(int32_t *, size_t); +void CheckStackIsAligned(void); int64_t div10int64(int64_t) libcesque pureconst; int64_t div100int64(int64_t) libcesque pureconst; diff --git a/libc/nexgen32e/nexgen32e.mk b/libc/nexgen32e/nexgen32e.mk index d00fbdd9a..a887887ce 100644 --- a/libc/nexgen32e/nexgen32e.mk +++ b/libc/nexgen32e/nexgen32e.mk @@ -42,7 +42,7 @@ $(LIBC_NEXGEN32E_A).pkg: \ $(LIBC_NEXGEN32E_A_OBJS) \ $(foreach x,$(LIBC_NEXGEN32E_A_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/libc/nexgen32e/errno.o: \ +o/$(MODE)/libc/nexgen32e/threaded.o: \ OVERRIDE_CFLAGS += \ $(NO_MAGIC) \ -fno-sanitize=all diff --git a/libc/nexgen32e/nt2sysv.S b/libc/nexgen32e/nt2sysv.S index ef5939d5b..34ae867d9 100644 --- a/libc/nexgen32e/nt2sysv.S +++ b/libc/nexgen32e/nt2sysv.S @@ -32,6 +32,8 @@ __nt2sysv: push %rbp mov %rsp,%rbp +// TODO(jart): We should probably find some way to use our own +// stack when Windows delivers signals ;_; .profilable sub $0x100,%rsp push %rbx diff --git a/libc/intrin/threaded.c b/libc/nexgen32e/threaded.c similarity index 95% rename from libc/intrin/threaded.c rename to libc/nexgen32e/threaded.c index c8589830b..7db3d662b 100644 --- a/libc/intrin/threaded.c +++ b/libc/nexgen32e/threaded.c @@ -16,6 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/threaded.internal.h" +#include "libc/nexgen32e/threaded.h" bool __threaded; +bool __tls_enabled; +unsigned __tls_index; diff --git a/libc/nexgen32e/threaded.h b/libc/nexgen32e/threaded.h new file mode 100644 index 000000000..868aab33e --- /dev/null +++ b/libc/nexgen32e/threaded.h @@ -0,0 +1,39 @@ +#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ +#define COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ +#include "libc/dce.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +extern bool __threaded; +extern bool __tls_enabled; +extern unsigned __tls_index; + +void *__initialize_tls(char[64]); +void __install_tls(char[64]); + +#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__) +/** + * Returns address of thread information block. + * + * This function must not be called until TLS is initialized. + * + * @see __install_tls() + * @see clone() + */ +static noasan inline char *__get_tls(void) { + char *tib, *lin = (char *)0x30; + if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd()) { + asm("mov\t%%fs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory"); + } else { + asm("mov\t%%gs:(%1),%0" : "=a"(tib) : "r"(lin) : "memory"); + if (IsWindows()) { + tib = *(char **)(tib + 0x1480 + __tls_index * 8); + } + } + return tib; +} +#endif /* GNU x86-64 */ + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_THREADED_H_ */ diff --git a/libc/nt/enum/th32cs.h b/libc/nt/enum/th32cs.h new file mode 100644 index 000000000..9c870ecf0 --- /dev/null +++ b/libc/nt/enum/th32cs.h @@ -0,0 +1,11 @@ +#ifndef COSMOPOLITAN_LIBC_NT_ENUM_TH32CS_H_ +#define COSMOPOLITAN_LIBC_NT_ENUM_TH32CS_H_ + +#define kNtTh32csInherit 0x80000000 +#define kNtTh32csSnapheaplist 0x00000001 +#define kNtTh32csSnapmodule 0x00000008 +#define kNtTh32csSnapmodule32 0x00000010 +#define kNtTh32csSnapprocess 0x00000002 +#define kNtTh32csSnapthread 0x00000004 + +#endif /* COSMOPOLITAN_LIBC_NT_ENUM_TH32CS_H_ */ diff --git a/libc/nt/enum/version.h b/libc/nt/enum/version.h index c6f67f1fc..48a45834f 100644 --- a/libc/nt/enum/version.h +++ b/libc/nt/enum/version.h @@ -4,17 +4,18 @@ /** * Known versions of the New Technology executive. + * @see IsAtLeastWindows10() * @see NtGetVersion() */ -#define kNtVersionWindows10 0x0a00 -#define kNtVersionWindows81 0x0603 -#define kNtVersionWindows8 0x0602 -#define kNtVersionWindows7 0x0601 +#define kNtVersionWindows10 0x0a00 +#define kNtVersionWindows81 0x0603 +#define kNtVersionWindows8 0x0602 +#define kNtVersionWindows7 0x0601 #define kNtVersionWindowsVista 0x0600 /* intended baseline */ -#define kNtVersionWindowsXp64 0x0502 /* end of the road */ -#define kNtVersionWindowsXp 0x0501 /* snowball's chance */ -#define kNtVersionWindows2000 0x0500 /* the golden age */ -#define kNtVersionFuture 0x0b00 +#define kNtVersionWindowsXp64 0x0502 /* end of the road */ +#define kNtVersionWindowsXp 0x0501 /* snowball's chance */ +#define kNtVersionWindows2000 0x0500 /* the golden age */ +#define kNtVersionFuture 0x0b00 #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_NT_ENUM_VERSION_H_ */ diff --git a/libc/nt/kernel32/CreateToolhelp32Snapshot.s b/libc/nt/kernel32/CreateToolhelp32Snapshot.s index 54982f143..aea3d4177 100644 --- a/libc/nt/kernel32/CreateToolhelp32Snapshot.s +++ b/libc/nt/kernel32/CreateToolhelp32Snapshot.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" -.imp kernel32,__imp_CreateToolhelp32Snapshot,CreateToolhelp32Snapshot,250 +.imp kernel32,__imp_CreateToolhelp32Snapshot,CreateToolhelp32Snapshot,0 + + .text.windows +CreateToolhelp32Snapshot: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_CreateToolhelp32Snapshot(%rip),%rax + jmp __sysv2nt + .endfn CreateToolhelp32Snapshot,globl + .previous diff --git a/libc/nt/kernel32/Process32FirstW.s b/libc/nt/kernel32/Process32FirstW.s index b8408bce5..d65af4e3f 100644 --- a/libc/nt/kernel32/Process32FirstW.s +++ b/libc/nt/kernel32/Process32FirstW.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" -.imp kernel32,__imp_Process32FirstW,Process32FirstW,1065 +.imp kernel32,__imp_Process32FirstW,Process32FirstW,0 + + .text.windows +Process32First: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_Process32FirstW(%rip),%rax + jmp __sysv2nt + .endfn Process32First,globl + .previous diff --git a/libc/nt/kernel32/Process32NextW.s b/libc/nt/kernel32/Process32NextW.s index aa49537b1..9ae46191c 100644 --- a/libc/nt/kernel32/Process32NextW.s +++ b/libc/nt/kernel32/Process32NextW.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" -.imp kernel32,__imp_Process32NextW,Process32NextW,1067 +.imp kernel32,__imp_Process32NextW,Process32NextW,0 + + .text.windows +Process32Next: + push %rbp + mov %rsp,%rbp + .profilable + mov __imp_Process32NextW(%rip),%rax + jmp __sysv2nt + .endfn Process32Next,globl + .previous diff --git a/libc/nt/kernel32/TlsAlloc.s b/libc/nt/kernel32/TlsAlloc.s index e39628b00..9a8311965 100644 --- a/libc/nt/kernel32/TlsAlloc.s +++ b/libc/nt/kernel32/TlsAlloc.s @@ -2,7 +2,7 @@ .imp kernel32,__imp_TlsAlloc,TlsAlloc,0 .text.windows -__TlsAlloc: +TlsAlloc: push %rbp mov %rsp,%rbp .profilable @@ -10,5 +10,5 @@ __TlsAlloc: call *__imp_TlsAlloc(%rip) leave ret - .endfn __TlsAlloc,globl + .endfn TlsAlloc,globl .previous diff --git a/libc/nt/kernel32/TlsFree.s b/libc/nt/kernel32/TlsFree.s index 8a66707ad..580308a34 100644 --- a/libc/nt/kernel32/TlsFree.s +++ b/libc/nt/kernel32/TlsFree.s @@ -2,7 +2,7 @@ .imp kernel32,__imp_TlsFree,TlsFree,0 .text.windows -__TlsFree: +TlsFree: push %rbp mov %rsp,%rbp .profilable @@ -11,5 +11,5 @@ __TlsFree: call *__imp_TlsFree(%rip) leave ret - .endfn __TlsFree,globl + .endfn TlsFree,globl .previous diff --git a/libc/nt/kernel32/TlsGetValue.s b/libc/nt/kernel32/TlsGetValue.s index 371ed9084..b4c5fb727 100644 --- a/libc/nt/kernel32/TlsGetValue.s +++ b/libc/nt/kernel32/TlsGetValue.s @@ -2,7 +2,7 @@ .imp kernel32,__imp_TlsGetValue,TlsGetValue,0 .text.windows -__TlsGetValue: +TlsGetValue: push %rbp mov %rsp,%rbp .profilable @@ -11,5 +11,5 @@ __TlsGetValue: call *__imp_TlsGetValue(%rip) leave ret - .endfn __TlsGetValue,globl + .endfn TlsGetValue,globl .previous diff --git a/libc/nt/kernel32/TlsSetValue.s b/libc/nt/kernel32/TlsSetValue.s index 77d63bf4b..c53d538c5 100644 --- a/libc/nt/kernel32/TlsSetValue.s +++ b/libc/nt/kernel32/TlsSetValue.s @@ -2,11 +2,11 @@ .imp kernel32,__imp_TlsSetValue,TlsSetValue,0 .text.windows -__TlsSetValue: +TlsSetValue: push %rbp mov %rsp,%rbp .profilable mov __imp_TlsSetValue(%rip),%rax jmp __sysv2nt - .endfn __TlsSetValue,globl + .endfn TlsSetValue,globl .previous diff --git a/libc/nt/master.sh b/libc/nt/master.sh index caefb97e5..a46644acf 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -208,7 +208,7 @@ imp 'CreateThreadpoolWait' CreateThreadpoolWait kernel32 0 imp 'CreateThreadpoolWork' CreateThreadpoolWork kernel32 0 imp 'CreateTimerQueue' CreateTimerQueue kernel32 0 imp 'CreateTimerQueueTimer' CreateTimerQueueTimer kernel32 0 -imp 'CreateToolhelp32Snapshot' CreateToolhelp32Snapshot kernel32 250 +imp 'CreateToolhelp32Snapshot' CreateToolhelp32Snapshot kernel32 0 2 imp 'CreateUmsCompletionList' CreateUmsCompletionList kernel32 251 imp 'CreateUmsThreadContext' CreateUmsThreadContext kernel32 252 imp 'CreateWaitableTimer' CreateWaitableTimerW kernel32 0 3 @@ -302,8 +302,8 @@ imp 'EnumerateLocalComputerNamesA' EnumerateLocalComputerNamesA kernel32 3 imp 'EraseTape' EraseTape kernel32 352 imp 'EscapeCommFunction' EscapeCommFunction kernel32 0 imp 'ExecuteUmsThread' ExecuteUmsThread kernel32 354 -imp 'ExitThread' ExitThread kernel32 0 1 imp 'ExitProcess' ExitProcess kernel32 0 1 # a.k.a. RtlExitUserProcess +imp 'ExitThread' ExitThread kernel32 0 1 imp 'ExitVDM' ExitVDM kernel32 357 imp 'ExpandEnvironmentStrings' ExpandEnvironmentStringsW kernel32 0 imp 'ExpandEnvironmentStringsA' ExpandEnvironmentStringsA kernel32 0 @@ -934,8 +934,8 @@ imp 'PowerSetRequest' PowerSetRequest kernel32 1059 imp 'PrefetchVirtualMemory' PrefetchVirtualMemory kernel32 0 4 imp 'PrepareTape' PrepareTape kernel32 1061 imp 'PrivMoveFileIdentity' PrivMoveFileIdentityW kernel32 1063 -imp 'Process32First' Process32FirstW kernel32 1065 -imp 'Process32Next' Process32NextW kernel32 1067 +imp 'Process32First' Process32FirstW kernel32 0 2 +imp 'Process32Next' Process32NextW kernel32 0 2 imp 'ProcessIdToSessionId' ProcessIdToSessionId kernel32 0 imp 'PssCaptureSnapshot' PssCaptureSnapshot kernel32 0 imp 'PssDuplicateSnapshot' PssDuplicateSnapshot kernel32 0 @@ -1225,6 +1225,10 @@ imp 'TermsrvSetValueKey' TermsrvSetValueKey kernel32 1441 imp 'TermsrvSyncUserIniFileExt' TermsrvSyncUserIniFileExt kernel32 1442 imp 'Thread32First' Thread32First kernel32 1443 imp 'Thread32Next' Thread32Next kernel32 1444 +imp 'TlsAlloc' TlsAlloc kernel32 0 0 +imp 'TlsFree' TlsFree kernel32 0 1 +imp 'TlsGetValue' TlsGetValue kernel32 0 1 +imp 'TlsSetValue' TlsSetValue kernel32 0 2 imp 'Toolhelp32ReadProcessMemory' Toolhelp32ReadProcessMemory kernel32 1449 imp 'TransactNamedPipe' TransactNamedPipe kernel32 0 7 imp 'TransmitCommChar' TransmitCommChar kernel32 0 @@ -1364,10 +1368,6 @@ imp '__ReOpenFile' ReOpenFile kernel32 0 4 # TODO(jart): 6.2 and highe imp '__RemoveDirectory' RemoveDirectoryW kernel32 0 1 imp '__SetCurrentDirectory' SetCurrentDirectoryW kernel32 0 1 imp '__TerminateProcess' TerminateProcess kernel32 0 2 -imp '__TlsAlloc' TlsAlloc kernel32 0 0 -imp '__TlsFree' TlsFree kernel32 0 1 -imp '__TlsGetValue' TlsGetValue kernel32 0 1 -imp '__TlsSetValue' TlsSetValue kernel32 0 2 imp '__UnmapViewOfFile' UnmapViewOfFile kernel32 0 1 imp '__VirtualProtect' VirtualProtect kernel32 0 4 imp '__WaitForMultipleObjects' WaitForMultipleObjects kernel32 0 4 diff --git a/libc/nt/process.h b/libc/nt/process.h index 480e1b851..38745121e 100644 --- a/libc/nt/process.h +++ b/libc/nt/process.h @@ -1,6 +1,7 @@ #ifndef COSMOPOLITAN_LIBC_NT_PROCESS_H_ #define COSMOPOLITAN_LIBC_NT_PROCESS_H_ #include "libc/nt/startupinfo.h" +#include "libc/nt/struct/processentry32.h" #include "libc/nt/struct/processinformation.h" #include "libc/nt/struct/processmemorycounters.h" #include "libc/nt/struct/securityattributes.h" @@ -73,6 +74,10 @@ bool32 GetProcessMemoryInfo( int64_t hProcess, struct NtProcessMemoryCountersEx *out_ppsmemCounters, uint32_t cb); +int64_t CreateToolhelp32Snapshot(uint32_t dwFlags, uint32_t th32ProcessID); +bool32 Process32First(int64_t hSnapshot, struct NtProcessEntry32 *in_out_lppe); +bool32 Process32Next(int64_t hSnapshot, struct NtProcessEntry32 *out_lppe); + #if ShouldUseMsabiAttribute() #include "libc/nt/thunk/process.inc" #endif /* ShouldUseMsabiAttribute() */ diff --git a/libc/nt/struct/processentry32.h b/libc/nt/struct/processentry32.h new file mode 100644 index 000000000..e6b481573 --- /dev/null +++ b/libc/nt/struct/processentry32.h @@ -0,0 +1,19 @@ +#ifndef COSMOPOLITAN_LIBC_NT_STRUCT_PROCESSENTRY32_H_ +#define COSMOPOLITAN_LIBC_NT_STRUCT_PROCESSENTRY32_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) + +struct NtProcessEntry32 { + uint32_t dwSize; + uint32_t cntUsage; /* unused */ + uint32_t th32ProcessID; + uint64_t th32DefaultHeapID; /* unused */ + uint32_t th32ModuleID; /* unused */ + uint32_t cntThreads; + uint32_t th32ParentProcessID; + int32_t cPriClassBase; + uint32_t dwFlags; /* unused */ + char16_t szExeFile[260]; +}; + +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_NT_STRUCT_PROCESSENTRY32_H_ */ diff --git a/libc/nt/thread.h b/libc/nt/thread.h index d5a8c3548..72f836b2c 100644 --- a/libc/nt/thread.h +++ b/libc/nt/thread.h @@ -57,6 +57,11 @@ bool32 CancelSynchronousIo(int64_t hThread); bool32 CancelIo(int64_t hFile); bool32 CancelIoEx(int64_t hFile, struct NtOverlapped *opt_lpOverlapped); +uint32_t TlsAlloc(void); +bool32 TlsFree(uint32_t); +bool32 TlsSetValue(uint32_t, void *); +void *TlsGetValue(uint32_t); + #if ShouldUseMsabiAttribute() #include "libc/nt/thunk/thread.inc" #endif /* ShouldUseMsabiAttribute() */ diff --git a/libc/nt/version.h b/libc/nt/version.h index f7ade11de..c7da8aab0 100644 --- a/libc/nt/version.h +++ b/libc/nt/version.h @@ -8,16 +8,14 @@ bool IsAtLeastWindows10(void) pureconst; bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation); #if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__) -#define IsAtLeastWindows10() \ - ({ \ - long ReG; \ - bool NoTbelow; \ - asm("mov\t%%gs:96,%1\r\n" \ - "cmpb\t%2,280(%1)" \ - : "=@ccnb"(NoTbelow), "=l"(ReG) \ - : "i"(10)); \ - NoTbelow; \ - }) +#define IsAtLeastWindows10() (GetNtMajorVersion() >= 10) +static pureconst inline unsigned char GetNtMajorVersion(void) { + uintptr_t _x; + asm("mov\t%%gs:96,%q0\r\n" + "mov\t280(%q0),%b0" + : "=q"(_x)); + return _x; +} #endif COSMOPOLITAN_C_END_ diff --git a/libc/rand/getrandom.c b/libc/rand/getrandom.c index 866dd671e..5b9f234b6 100644 --- a/libc/rand/getrandom.c +++ b/libc/rand/getrandom.c @@ -18,8 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/nexgen32e/kcpuids.h" diff --git a/libc/rand/rand64.c b/libc/rand/rand64.c index 6d24f19ee..940a64a19 100644 --- a/libc/rand/rand64.c +++ b/libc/rand/rand64.c @@ -31,7 +31,7 @@ static int thepid; static uint128_t thepool; -_Alignas(64) static char rand64_lock; +_Alignas(64) static int rand64_lock; /** * Returns nondeterministic random data. @@ -47,7 +47,6 @@ _Alignas(64) static char rand64_lock; * @note this function is not intended for cryptography * @note this function passes bigcrush and practrand * @note this function takes at minimum 15 cycles - * @asyncsignalsafe * @threadsafe * @vforksafe */ diff --git a/libc/runtime/arch_prctl.c b/libc/runtime/arch_prctl.c index c5602feb4..2c958c5fb 100644 --- a/libc/runtime/arch_prctl.c +++ b/libc/runtime/arch_prctl.c @@ -19,6 +19,7 @@ #include "libc/bits/asmflag.h" #include "libc/bits/bits.h" #include "libc/calls/calls.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/nexgen32e/msr.h" #include "libc/nexgen32e/x86feature.h" @@ -57,8 +58,6 @@ "d"((uint32_t)(val_ >> 32))); \ } while (0) -int sys_arch_prctl(int, int64_t) hidden; - static inline int arch_prctl_fsgsbase(int code, int64_t addr) { switch (code) { case ARCH_SET_GS: diff --git a/libc/runtime/arememoryintervalsok.c b/libc/runtime/arememoryintervalsok.c index 1a4969a14..5b7d4fe9c 100644 --- a/libc/runtime/arememoryintervalsok.c +++ b/libc/runtime/arememoryintervalsok.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/strace.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/memtrack.internal.h" noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { @@ -27,6 +28,12 @@ noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { STRACE("AreMemoryIntervalsOk() y should be >= x!"); return false; } + if (!(mm->p[i].size <= + (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE + FRAMESIZE && + mm->p[i].size > (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE)) { + STRACE("AreMemoryIntervalsOk() size is wrong!"); + return false; + } if (i) { if (mm->p[i].h != -1 || mm->p[i - 1].h != -1) { if (mm->p[i].x <= mm->p[i - 1].y) { diff --git a/libc/runtime/clone-linux.S b/libc/runtime/clone-linux.S new file mode 100644 index 000000000..131e60592 --- /dev/null +++ b/libc/runtime/clone-linux.S @@ -0,0 +1,55 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + +// Invokes clone() system call on GNU/Systemd. +// +// @param rdi is flags +// @param rsi is top of stack +// @param rdx is ptid +// @param rcx is ctid +// @param r8 is tls +// @param r9 is func +// @param 8(rsp) is arg +// @return tid of child on success, or -1 w/ errno +sys_clone_linux: + push %rbp + mov %rsp,%rbp + .profilable + push %rbx + mov %rcx,%r10 + mov 16(%rbp),%rbx + mov $56,%eax # __NR_clone + syscall + test %rax,%rax + jz 2f + cmp $-4095,%rax + jae 1f +0: pop %rbx + pop %rbp + ret +1: call systemfive_error + jmp 0b +2: xor %ebp,%ebp # child thread + mov %rbx,%rdi # arg + call *%r9 # func(arg) + xchg %eax,%edi # func(arg) → exitcode + mov $60,%eax # __NR_exit(exitcode) + syscall + .endfn sys_clone_linux,globl,hidden diff --git a/libc/runtime/clone.c b/libc/runtime/clone.c index c6295f4e8..35b45eac4 100644 --- a/libc/runtime/clone.c +++ b/libc/runtime/clone.c @@ -18,22 +18,20 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/ucontext-netbsd.internal.h" +#include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" -#include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" -#include "libc/intrin/threaded.internal.h" -#include "libc/intrin/tls.h" -#include "libc/intrin/winthread.internal.h" +#include "libc/nexgen32e/threaded.h" #include "libc/nt/runtime.h" #include "libc/nt/thread.h" #include "libc/nt/thunk/msabi.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/nr.h" +#include "libc/sysv/consts/nrlinux.h" #include "libc/sysv/errfuns.h" #include "libc/thread/freebsd.internal.h" #include "libc/thread/xnu.internal.h" @@ -44,106 +42,147 @@ STATIC_YOINK("gettid"); // for kprintf() #define __NR_clone_linux 56 #define __NR__lwp_create 309 #define __NR_getcontext_netbsd 307 -#define __NR__lwp_setprivate 317 #define __NR_bsdthread_create 0x02000168 #define __NR_thread_fast_set_cthread_self 0x03000003 #define PTHREAD_START_CUSTOM_XNU 0x01000000 #define LWP_DETACHED 0x00000040 #define LWP_SUSPENDED 0x00000080 -uint32_t WinThreadThunk(void *warg); -asm(".section\t.text.windows,\"ax\",@progbits\n\t" - ".local\tWinThreadThunk\n" - "WinThreadThunk:\n\t" - "xor\t%ebp,%ebp\n\t" - "mov\t%rcx,%rdi\n\t" - "mov\t%rcx,%rsp\n\t" - "jmp\tWinThreadMain\n\t" - ".size\tWinThreadThunk,.-WinThreadThunk\n\t" - ".previous"); -__attribute__((__used__, __no_reorder__)) +__msabi extern typeof(TlsSetValue) *const __imp_TlsSetValue; +__msabi extern typeof(ExitThread) *const __imp_ExitThread; -static textwindows wontreturn void -WinThreadMain(struct WinThread *wt) { +struct CloneArgs { + union { + int tid; + uint32_t utid; + int64_t tid64; + }; + union { + int lock; + void *pstack; + }; + int *ctid; + int *ztid; + char *tls; + int (*func)(void *); + void *arg; +}; + +struct __tfork { + void *tf_tcb; + int32_t *tf_tid; + void *tf_stack; +}; + +static char tibdefault[64]; + +//////////////////////////////////////////////////////////////////////////////// +// THE NEW TECHNOLOGY + +int WinThreadLaunch(void *arg, int (*func)(void *), intptr_t rsp); + +// we can't log this function because: +// 1. windows owns the backtrace pointer right now +// 2. ftrace unwinds rbp to determine depth +// we can't use address sanitizer because: +// 1. __asan_handle_no_return wipes stack +// 2. windows owns the stack memory right now +// we need win32 raw imports because: +// 1. generated thunks are function logged +noasan noinstrument static textwindows wontreturn void WinThreadEntry( + int rdi, int rsi, int rdx, struct CloneArgs *wt) { int rc; - if (wt->flags & CLONE_CHILD_SETTID) { - *wt->ctid = wt->tid; + if (wt->tls) { + asm("mov\t%1,%%gs:%0" + : "=m"(*((long *)0x1480 + __tls_index)) + : "r"(wt->tls)); } - // TlsSetValue(__winthread, wt); - rc = wt->func(wt->arg); - if (wt->flags & CLONE_CHILD_CLEARTID) { - *wt->ctid = 0; - } - _Exit1(rc); + *wt->ctid = wt->tid; + rc = WinThreadLaunch(wt->arg, wt->func, (intptr_t)wt & -16); + // we can now clear ctid directly since we're no longer using our own + // stack memory, which can now be safely free'd by the parent thread. + *wt->ztid = 0; + // since we didn't indirect this function through NT2SYSV() it's not + // safe to simply return, and as such, we just call ExitThread(). + __imp_ExitThread(rc); + unreachable; } static textwindows int CloneWindows(int (*func)(void *), char *stk, size_t stksz, int flags, void *arg, - int *ptid, void *tls, size_t tlssz, - int *ctid) { + void *tls, size_t tlssz, int *ctid) { int64_t h; - struct WinThread *wt; - wt = (struct WinThread *)(((intptr_t)(stk + stksz) - - sizeof(struct WinThread)) & - -alignof(struct WinThread)); - wt->flags = flags; - wt->ctid = ctid; + struct CloneArgs *wt; + wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) - + sizeof(struct CloneArgs)) & + -alignof(struct CloneArgs)); + wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid; + wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid; wt->func = func; wt->arg = arg; - if ((h = CreateThread(0, 0, WinThreadThunk, wt, 0, &wt->tid))) { + wt->tls = flags & CLONE_SETTLS ? tls : 0; + if ((h = CreateThread(0, 0, (void *)WinThreadEntry, wt, 0, &wt->utid))) { CloseHandle(h); - if (flags & CLONE_PARENT_SETTID) { - *ptid = wt->tid; - } return wt->tid; } else { - __releasefd(wt->tid); return -1; } } +//////////////////////////////////////////////////////////////////////////////// +// XNU'S NOT UNIX + void XnuThreadThunk(void *pthread, int machport, void *(*func)(void *), - void *arg, intptr_t *stack, unsigned flags); + void *arg, intptr_t *stack, unsigned xnuflags); asm(".local\tXnuThreadThunk\n" "XnuThreadThunk:\n\t" "xor\t%ebp,%ebp\n\t" "mov\t%r8,%rsp\n\t" + "and\t$-16,%rsp\n\t" + "push\t%rax\n\t" "jmp\tXnuThreadMain\n\t" ".size\tXnuThreadThunk,.-XnuThreadThunk"); __attribute__((__used__, __no_reorder__)) static wontreturn void XnuThreadMain(void *pthread, int tid, int (*func)(void *arg), void *arg, - intptr_t *sp, unsigned flags) { - int rc; - sp[1] = tid; - _spunlock(sp); - if (sp[4] & CLONE_SETTLS) { + struct CloneArgs *wt, unsigned xnuflags) { + int ax; + wt->tid = tid; + _spunlock(&wt->lock); + if (wt->tls) { // XNU uses the same 0x30 offset as the WIN32 TIB x64. They told the // Go team at Google that they Apply stands by our ability to use it // https://github.com/golang/go/issues/23617#issuecomment-376662373 asm volatile("syscall" - : "=a"(rc) - : "0"(__NR_thread_fast_set_cthread_self), "D"(sp[3] - 0x30) + : "=a"(ax) + : "0"(__NR_thread_fast_set_cthread_self), "D"(wt->tls - 0x30) : "rcx", "r11", "memory", "cc"); } - if (sp[4] & CLONE_CHILD_SETTID) { - *(int *)sp[2] = tid; - } - rc = func(arg); - if (sp[4] & CLONE_CHILD_CLEARTID) { - *(int *)sp[2] = 0; - } - _Exit1(rc); + *wt->ctid = tid; + func(arg); + // we no longer use the stack after this point + // %rax = int bsdthread_terminate(%rdi = void *stackaddr, + // %rsi = size_t freesize, + // %rdx = uint32_t port, + // %r10 = uint32_t sem); + asm volatile("movl\t$0,%0\n\t" // *wt->ztid = 0 + "xor\t%%r10d,%%r10d\n\t" // sem = 0 + "syscall\n\t" // _Exit1() + "ud2" + : "=m"(*wt->ztid) + : "a"(0x2000000 | 361), "D"(0), "S"(0), "d"(0) + : "rcx", "r10", "r11", "memory"); + unreachable; } static int CloneXnu(int (*fn)(void *), char *stk, size_t stksz, int flags, - void *arg, int *ptid, void *tls, size_t tlssz, int *ctid) { + void *arg, void *tls, size_t tlssz, int *ctid) { int rc; bool failed; - intptr_t *sp; static bool once; static int broken; + struct CloneArgs *wt; if (!once) { if (bsdthread_register(XnuThreadThunk, 0, 0, 0, 0, 0, 0) == -1) { broken = errno; @@ -154,92 +193,76 @@ static int CloneXnu(int (*fn)(void *), char *stk, size_t stksz, int flags, errno = broken; return -1; } - sp = (intptr_t *)(stk + stksz); - *--sp = 0; // 5 padding - *--sp = flags; // 4 clone() flags - *--sp = (intptr_t)tls; // 3 thread local storage - *--sp = (intptr_t)ctid; // 2 child tid api - *--sp = 0; // 1 receives tid - *--sp = 0; // 0 lock - _seizelock(sp); // TODO: How can we get the tid without locking? - if ((rc = bsdthread_create(fn, arg, sp, 0, PTHREAD_START_CUSTOM_XNU)) != -1) { - _spinlock(sp); - if (flags & CLONE_PARENT_SETTID) { - *ptid = sp[1]; - } - rc = sp[1]; + wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) - + sizeof(struct CloneArgs)) & + -alignof(struct CloneArgs)); + wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid; + wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid; + wt->tls = flags & CLONE_SETTLS ? tls : 0; + _seizelock(&wt->lock); // TODO: How can we get the tid without locking? + if ((rc = bsdthread_create(fn, arg, wt, 0, PTHREAD_START_CUSTOM_XNU)) != -1) { + _spinlock(&wt->lock); + rc = wt->tid; } return rc; } -void FreebsdThreadThunk(void *sp) wontreturn; -asm(".local\tFreebsdThreadThunk\n" - "FreebsdThreadThunk:\n\t" - "xor\t%ebp,%ebp\n\t" - "mov\t%rdi,%rsp\n\t" - "jmp\tFreebsdThreadMain\n\t" - ".size\tFreebsdThreadThunk,.-FreebsdThreadThunk"); -__attribute__((__used__, __no_reorder__)) +//////////////////////////////////////////////////////////////////////////////// +// FREE BESIYATA DISHMAYA -static wontreturn void -FreebsdThreadMain(intptr_t *sp) { - int rc; - if (sp[3] & CLONE_CHILD_SETTID) { - *(int *)sp[2] = sp[4]; - } - rc = ((int (*)(intptr_t))sp[0])(sp[1]); - if (sp[3] & CLONE_CHILD_CLEARTID) { - *(int *)sp[2] = 0; - } - _Exit1(rc); +static wontreturn void FreebsdThreadMain(void *p) { + struct CloneArgs *wt = p; + *wt->ctid = wt->tid; + wt->func(wt->arg); + // we no longer use the stack after this point + // void thr_exit(%rdi = long *state); + asm volatile("movl\t$0,%0\n\t" // *wt->ztid = 0 + "syscall" // _Exit1() + : "=m"(*wt->ztid) + : "a"(431), "D"(0) + : "rcx", "r11", "memory"); + unreachable; } static int CloneFreebsd(int (*func)(void *), char *stk, size_t stksz, int flags, - void *arg, int *ptid, void *tls, size_t tlssz, - int *ctid) { + void *arg, void *tls, size_t tlssz, int *ctid) { int ax; bool failed; int64_t tid; - intptr_t *sp; - sp = (intptr_t *)(stk + stksz); - *--sp = 0; // 5 [padding] - *--sp = 0; // 4 [child_tid] - *--sp = flags; // 3 - *--sp = (intptr_t)ctid; // 2 - *--sp = (intptr_t)arg; // 1 - *--sp = (intptr_t)func; // 0 + struct CloneArgs *wt; + wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) - + sizeof(struct CloneArgs)) & + -alignof(struct CloneArgs)); + wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid; + wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid; + wt->tls = tls; + wt->func = func; + wt->arg = arg; struct thr_param params = { - .start_func = FreebsdThreadThunk, - .arg = sp, + .start_func = FreebsdThreadMain, + .arg = wt, .stack_base = stk, - .stack_size = stksz, + .stack_size = (((intptr_t)wt - (intptr_t)stk) & -16) - 8, .tls_base = flags & CLONE_SETTLS ? tls : 0, .tls_size = flags & CLONE_SETTLS ? tlssz : 0, - .child_tid = sp + 4, + .child_tid = &wt->tid64, .parent_tid = &tid, }; asm volatile(CFLAG_ASM("syscall") : CFLAG_CONSTRAINT(failed), "=a"(ax) : "1"(__NR_thr_new), "D"(¶ms), "S"(sizeof(params)) : "rcx", "rdx", "r8", "r9", "r10", "r11", "memory"); - if (!failed) { - if (flags & CLONE_PARENT_SETTID) { - *ptid = tid; - } - return tid; - } else { + if (failed) { errno = ax; - return -1; + tid = -1; } + return tid; } -struct __tfork { - void *tf_tcb; - int32_t *tf_tid; - void *tf_stack; -}; +//////////////////////////////////////////////////////////////////////////////// +// OPEN BESIYATA DISHMAYA -int __tfork(struct __tfork *params, size_t psize, intptr_t *stack); +int __tfork(struct __tfork *params, size_t psize, struct CloneArgs *wt); asm(".section\t.privileged,\"ax\",@progbits\n\t" ".local\t__tfork\n" "__tfork:\n\t" @@ -256,62 +279,76 @@ asm(".section\t.privileged,\"ax\",@progbits\n\t" "xor\t%ebp,%ebp\n\t" "mov\t%r8,%rsp\n\t" "mov\t%r8,%rdi\n\t" + "and\t$-16,%rsp\n\t" + "push\t%rax\n\t" "jmp\tOpenbsdThreadMain\n\t" ".size\t__tfork,.-__tfork\n\t" ".previous"); __attribute__((__used__, __no_reorder__)) static privileged wontreturn void -OpenbsdThreadMain(intptr_t *sp) { - int rc; - rc = ((int (*)(intptr_t))sp[0])(sp[1]); - if (sp[3] & CLONE_CHILD_CLEARTID) { - *(int *)sp[2] = 0; - } - _Exit1(rc); +OpenbsdThreadMain(struct CloneArgs *wt) { + wt->func(wt->arg); + // we no longer use the stack after this point. however openbsd + // validates the rsp register too so a race condition can still + // happen if the parent tries to free the stack. we'll solve it + // by simply changing rsp back to the old value before exiting! + // although ideally there should be a better solution. + // + // void __threxit(%rdi = int32_t *notdead); + asm volatile("mov\t%3,%%rsp\n\t" + "movl\t$0,%0\n\t" // *wt->ztid = 0 + "syscall" // _Exit1() + : "=m"(*wt->ztid) + : "a"(302), "D"(0), "r"(wt->pstack) + : "rcx", "r11", "memory"); + unreachable; } static int CloneOpenbsd(int (*func)(void *), char *stk, size_t stksz, int flags, - void *arg, int *ptid, void *tls, size_t tlssz, - int *ctid) { + void *arg, void *tls, size_t tlssz, int *ctid) { int tid; - intptr_t *sp; + struct CloneArgs *wt; struct __tfork params; - sp = (intptr_t *)(stk + stksz); - *--sp = flags; // 3 - *--sp = (intptr_t)ctid; // 2 - *--sp = (intptr_t)arg; // 1 - *--sp = (intptr_t)func; // 0 - params.tf_stack = sp; + wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) - + sizeof(struct CloneArgs)) & + -alignof(struct CloneArgs)); + wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid; + wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid; + wt->pstack = __builtin_frame_address(0); + wt->func = func; + wt->arg = arg; + params.tf_stack = wt; params.tf_tcb = flags & CLONE_SETTLS ? tls : 0; params.tf_tid = flags & CLONE_CHILD_SETTID ? ctid : 0; - if ((tid = __tfork(¶ms, sizeof(params), sp)) > 0) { - if (flags & CLONE_PARENT_SETTID) { - *ptid = tid; - } - } else { + if ((tid = __tfork(¶ms, sizeof(params), wt)) < 0) { errno = -tid; tid = -1; } return tid; } +//////////////////////////////////////////////////////////////////////////////// +// NET BESIYATA DISHMAYA + static wontreturn void NetbsdThreadMain(void *arg, int (*func)(void *arg), - int *tid, int *ctid, int flags) { - int rc; - if (flags & CLONE_CHILD_SETTID) { - *ctid = *tid; - } - rc = func(arg); - if (flags & CLONE_CHILD_CLEARTID) { - *ctid = 0; - } - _Exit1(rc); + int *tid, int *ctid, int *ztid) { + int ax, dx; + *ctid = *tid; + func(arg); + // we no longer use the stack after this point + // %eax = int __lwp_exit(void); + asm volatile("movl\t$0,%2\n\t" // *wt->ztid = 0 + "syscall\n\t" // _Exit1() + "ud2" + : "=a"(ax), "=d"(dx), "=m"(*ztid) + : "0"(310) + : "rcx", "r11", "memory"); + unreachable; } static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags, - void *arg, int *ptid, void *tls, size_t tlssz, - int *ctid) { + void *arg, void *tls, size_t tlssz, int *ctid) { // NetBSD has its own clone() and it works, but it's technically a // second-class API, intended to help Linux folks migrate to this! // We put it on the thread's stack, to avoid locking this function @@ -321,8 +358,10 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags, intptr_t dx, sp; static bool once; static int broken; - struct ucontext_netbsd *ctx; + struct ucontext_netbsd ctx; static struct ucontext_netbsd netbsd_clone_template; + + // memoize arbitrary valid processor state structure if (!once) { asm volatile(CFLAG_ASM("syscall") : CFLAG_CONSTRAINT(failed), "=a"(ax) @@ -339,36 +378,36 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags, } sp = (intptr_t)(stk + stksz); sp -= sizeof(int); + sp = sp & -alignof(int); tid = (int *)sp; - sp -= sizeof(*ctx); - sp = sp & -alignof(*ctx); - ctx = (struct ucontext_netbsd *)sp; - memcpy(ctx, &netbsd_clone_template, sizeof(*ctx)); - ctx->uc_link = 0; - ctx->uc_mcontext.rbp = 0; - ctx->uc_mcontext.rsp = sp; - ctx->uc_mcontext.rip = (intptr_t)NetbsdThreadMain; - ctx->uc_mcontext.rdi = (intptr_t)arg; - ctx->uc_mcontext.rsi = (intptr_t)func; - ctx->uc_mcontext.rdx = (intptr_t)tid; - ctx->uc_mcontext.rcx = (intptr_t)ctid; - ctx->uc_mcontext.r8 = flags; - ctx->uc_flags |= _UC_STACK; - ctx->uc_stack.ss_sp = stk; - ctx->uc_stack.ss_size = stksz; - ctx->uc_stack.ss_flags = 0; + sp = sp & -16; + sp -= 8; + // pass parameters in process state + memcpy(&ctx, &netbsd_clone_template, sizeof(ctx)); + ctx.uc_link = 0; + ctx.uc_mcontext.rbp = 0; + ctx.uc_mcontext.rsp = sp; + ctx.uc_mcontext.rip = (intptr_t)NetbsdThreadMain; + ctx.uc_mcontext.rdi = (intptr_t)arg; + ctx.uc_mcontext.rsi = (intptr_t)func; + ctx.uc_mcontext.rdx = (intptr_t)tid; + ctx.uc_mcontext.rcx = (intptr_t)(flags & CLONE_CHILD_SETTID ? ctid : tid); + ctx.uc_mcontext.r8 = (intptr_t)(flags & CLONE_CHILD_CLEARTID ? ctid : tid); + ctx.uc_flags |= _UC_STACK; + ctx.uc_stack.ss_sp = stk; + ctx.uc_stack.ss_size = stksz; + ctx.uc_stack.ss_flags = 0; if (flags & CLONE_SETTLS) { - ctx->uc_flags |= _UC_TLSBASE; - ctx->uc_mcontext._mc_tlsbase = (intptr_t)tls; + ctx.uc_flags |= _UC_TLSBASE; + ctx.uc_mcontext._mc_tlsbase = (intptr_t)tls; } + + // perform the system call asm volatile(CFLAG_ASM("syscall") : CFLAG_CONSTRAINT(failed), "=a"(ax), "=d"(dx) - : "1"(__NR__lwp_create), "D"(ctx), "S"(LWP_DETACHED), "2"(tid) + : "1"(__NR__lwp_create), "D"(&ctx), "S"(LWP_DETACHED), "2"(tid) : "rcx", "r11", "memory"); if (!failed) { - if (flags & CLONE_PARENT_SETTID) { - *ptid = *tid; - } return *tid; } else { errno = ax; @@ -376,95 +415,119 @@ static int CloneNetbsd(int (*func)(void *), char *stk, size_t stksz, int flags, } } -static int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags, - void *arg, int *ptid, void *tls, size_t tlssz, - int *ctid) { - int ax; - bool failed; - intptr_t *stack; - register int *r8 asm("r8") = tls; - register int (*r9)(void *) asm("r9") = func; - register int *r10 asm("r10") = ctid; - stack = (intptr_t *)(stk + stksz); - *--stack = (long)arg; // push 1 - asm volatile("syscall" - : "=a"(ax) - : "0"(__NR_clone_linux), "D"(flags), "S"(stack), "d"(ptid), - "r"(r10), "r"(r8), "r"(r9) - : "rcx", "r11", "memory"); - if (ax > -4096u) { - errno = -ax; - return -1; - } - if (ax) return ax; - asm volatile("xor\t%%ebp,%%ebp\n\t" - "pop\t%%rdi\n\t" // pop 1 - "call\t*%0\n\t" - "xchg\t%%eax,%%edi\n\t" - "jmp\t_Exit1" - : /* no outputs */ - : "r"(r9) - : "memory"); - unreachable; -} +//////////////////////////////////////////////////////////////////////////////// +// GNU/SYSTEMD + +int sys_clone_linux(int flags, char *stk, int *ptid, int *ctid, void *tls, + int (*func)(void *), void *arg); + +//////////////////////////////////////////////////////////////////////////////// +// COSMOPOLITAN /** * Creates thread. * * Threads are created in a detached manner. They currently can't be - * synchronized using wait() and posix signals. Threads created by this + * synchronized using wait() or posix signals. Threads created by this * function should be synchronized using shared memory operations. * * Any memory that's required by this system call wrapper is allocated - * to the top of your stack. This is normally about 64 bytes, although - * on NetBSD it's currently 800. + * to the top of your stack. This shouldn't be more than 128 bytes. + * + * Your function is called from within the stack you specify. A return + * address is pushed onto your stack, that causes returning to jump to + * _Exit1() which terminates the thread. Even though the callback says + * it supports a return code, that'll only work on Linux and Windows. + * + * The `tls` parameter is for thread-local storage. If you specify this + * then clone() will implicitly rewire libc (e.g. errno) to use TLS: + * + * static char tib[64]; + * __initialize_tls(tib); + * __install_tls(tib); + * + * If you want a main process TLS size that's larger call it manually. + * Once you've done the above and/or started creating your own threads + * you'll be able to access your `tls` thread information block, using + * + * char *p = __get_tls(); + * printf("errno is %d\n", *(int *)(p + 0x3c)); * * This function follows the same ABI convention as the Linux userspace * libraries, with a few small changes. The varargs has been removed to * help prevent broken code, and the stack size and tls size parameters * are introduced for compatibility with FreeBSD. * + * To keep this system call lightweight, only the thread creation use + * case is polyfilled across platforms. For example, if you want fork + * that works on OpenBSD for example, don't do it with clone(SIGCHLD) + * and please just call fork(). Even if you do that on Linux, it will + * effectively work around libc features like atfork(), so that means + * other calls like getpid() may return incorrect values. + * * @param func is your callback function * @param stk points to the bottom of a caller allocated stack, which - * must be null when fork() and vfork() equivalent flags are used - * and furthermore this must be mmap()'d using MAP_STACK in order - * to work on OpenBSD - * @param stksz is the size of that stack in bytes which must be zero - * if the fork() or vfork() equivalent flags are used it's highly - * recommended that this value be GetStackSize(), or else kprintf - * and other runtime services providing memory safety can't do as - * good and quick of a job; this value must be 4096-aligned, plus - * it must be at minimum 4096 bytes in size - * @param flags usually has one of - * - `SIGCHLD` will delegate to fork() - * - `CLONE_VFORK|CLONE_VM|SIGCHLD` means vfork() + * must be allocated via mmap() using the MAP_STACK flag, or else + * you won't get optimal performance and it won't work on OpenBSD + * @param stksz is the size of that stack in bytes, we recommend that + * that this be set to GetStackSize() or else memory safety tools + * like kprintf() can't do as good and quick of a job; this value + * must be 16-aligned plus it must be at least 4192 bytes in size + * and it's advised to have the bottom-most page, be a guard page + * @param flags should have: * - `CLONE_THREAD|CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND` - * as part high bytes, and the low order byte may optionally contain - * a signal e.g. SIGCHLD, to enable parent notification on terminate - * although the signal isn't supported on non-Linux and non-NetBSD - * at the moment; 'flags' may optionally bitwise or the following: - * - `CLONE_PARENT_SETTID` is needed for `ctid` should be set - * - `CLONE_CHILD_SETTID` is needed for `ptid` should be set - * - `CLONE_SETTLS` is needed to set `%fs` segment to `tls` + * and you may optionally bitwise or any of the following: + * - `CLONE_CHILD_SETTID` is needed too if you use `ctid` which + * is part of the memory the child owns and it'll be set right + * before the callback function is invoked + * - `CLONE_CHILD_CLEARTID` causes `*ctid = 0` upon termination + * which can be used to implement join so that the parent may + * safely free the stack memory that the child is using + * - `CLONE_PARENT_SETTID` is needed too if you use `ptid` and this + * is guaranteed to happen before clone() returns + * - `CLONE_SETTLS` is needed too if you set `tls`. You may get this + * value from the thread by calling __get_tls(). There are a few + * layout expectations imposed by your C library. Those are all + * documented by __initialize_tls() which initializes the parts of + * the first 64 bytes of tls memory that libc cares about. Also + * note that if you decide to use tls once then you must use it + * for everything, since this flag also flips a runtime state that + * enables it for the main thread and functions such as + * __errno_location() will begin assuming they can safely access + * the tls segment register. * @param arg will be passed to your callback - * @param ptid lets the parent receive the child thread id; - * this parameter is ignored if `CLONE_PARENT_SETTID` is not set * @param tls may be used to set the thread local storage segment; * this parameter is ignored if `CLONE_SETTLS` is not set - * @param tlssz is the size of tls in bytes - * @param ctid lets the child receive its thread id; - * this parameter is ignored if `CLONE_CHILD_SETTID` is not set - * @return tid on success and 0 to the child, otherwise -1 w/ errno + * @param tlssz is the size of tls in bytes which must be at least 64 + * @param ctid lets the child receive its thread id without having to + * call gettid() and is ignored if `CLONE_CHILD_SETTID` isn't set + * @return tid of child on success, or -1 w/ errno * @threadsafe */ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg, int *ptid, void *tls, size_t tlssz, int *ctid) { int rc; + struct CloneArgs *wt; - // let kprintf() switch from pids to tids - __threaded = true; + // transition program to threaded state + if ((flags & CLONE_SETTLS) && !__tls_enabled) { + if (~flags & CLONE_THREAD) { + STRACE("clone() tls w/o thread"); + return einval(); + } + if (__threaded) { + STRACE("clone() tls/non-tls mixed order"); + return einval(); + } + __initialize_tls(tibdefault); + *(int *)((char *)tibdefault + 0x38) = gettid(); + *(int *)((char *)tibdefault + 0x3c) = __errno; + __install_tls(tibdefault); + __threaded = true; + } else if (flags & CLONE_THREAD) { + __threaded = true; + } - // verify memory is kosher if (IsAsan() && ((stksz > PAGESIZE && !__asan_is_valid((char *)stk + PAGESIZE, stksz - PAGESIZE)) || @@ -475,61 +538,40 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg, ((flags & CLONE_CHILD_SETTID) && !__asan_is_valid(ctid, sizeof(*ctid))))) { rc = efault(); - } - - // delegate to bona fide clone() - else if (IsLinux()) { - rc = CloneLinux(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid); - } - - // polyfill fork() and vfork() use cases on platforms without clone() - else if ((SupportsWindows() || SupportsBsd()) && - flags == (CLONE_VFORK | CLONE_VM | SIGCHLD)) { - if (IsTiny()) { - rc = einval(); - } else if (!arg && !stksz) { - return vfork(); // don't log clone() - } else { - rc = einval(); - } - } else if ((SupportsWindows() || SupportsBsd()) && flags == SIGCHLD) { - if (IsTiny()) { - rc = eopnotsupp(); - } else if (!arg && !stksz) { - return fork(); // don't log clone() - } else { - rc = einval(); - } - } - - // we now assume we're creating a thread - // these platforms can't do signals the way linux does - else if (!IsTiny() && ((stksz < PAGESIZE || (stksz & (PAGESIZE - 1))) || - (flags & ~(CLONE_SETTLS | CLONE_PARENT_SETTID | - CLONE_CHILD_SETTID)) != - (CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | - CLONE_SIGHAND))) { + } else if (!IsTiny() && + (((flags & CLONE_VM) && (stksz < PAGESIZE || (stksz & 15))) || + ((flags & CLONE_SETTLS) && (tlssz < 64 || (tlssz & 7))))) { + rc = einval(); + } else if (IsLinux()) { + rc = + sys_clone_linux(flags, (char *)stk + stksz, ptid, ctid, tls, func, arg); + } else if (!IsTiny() && + (flags & ~(CLONE_SETTLS | CLONE_PARENT_SETTID | + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) != + (CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND)) { + STRACE("clone flag unsupported on this platform"); rc = einval(); } else if (IsXnu()) { - rc = CloneXnu(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid); + rc = CloneXnu(func, stk, stksz, flags, arg, tls, tlssz, ctid); } else if (IsFreebsd()) { - rc = CloneFreebsd(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid); + rc = CloneFreebsd(func, stk, stksz, flags, arg, tls, tlssz, ctid); } else if (IsNetbsd()) { - rc = CloneNetbsd(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid); + rc = CloneNetbsd(func, stk, stksz, flags, arg, tls, tlssz, ctid); } else if (IsOpenbsd()) { - rc = CloneOpenbsd(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid); - } - - // These platforms can't do segment registers like linux does - else if (flags & CLONE_SETTLS) { - rc = einval(); + rc = CloneOpenbsd(func, stk, stksz, flags, arg, tls, tlssz, ctid); } else if (IsWindows()) { - rc = CloneWindows(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid); + rc = CloneWindows(func, stk, stksz, flags, arg, tls, tlssz, ctid); } else { rc = enosys(); } + if (rc != -1 && (flags & CLONE_PARENT_SETTID)) { + *ptid = rc; + } + STRACE("clone(%p, %p, %'zu, %#x, %p, %p, %p, %'zu, %p) → %d% m", func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid, rc); + return rc; } diff --git a/libc/runtime/cosmo.S b/libc/runtime/cosmo.S index c14c2a1c3..97f228013 100644 --- a/libc/runtime/cosmo.S +++ b/libc/runtime/cosmo.S @@ -135,6 +135,16 @@ cosmo: push %rbp .init.end 306,_init_ftrace #endif +#if IsAsan() + .init.start 306,_init_symbols + push %rdi + push %rsi + call __init_symbols + pop %rsi + pop %rdi + .init.end 306,_init_symbols +#endif + #if IsModeDbg() #ifdef SYSDEBUG .init.start 307,_init_printargs diff --git a/libc/runtime/finddebugbinary.c b/libc/runtime/finddebugbinary.c index aee215169..e902aaa54 100644 --- a/libc/runtime/finddebugbinary.c +++ b/libc/runtime/finddebugbinary.c @@ -35,23 +35,24 @@ const char *FindDebugBinary(void) { char *p; size_t n; if (!once) { - if (!(res = getenv("COMDBG"))) { - p = GetProgramExecutableName(); - n = strlen(p); - if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) { - res = p; - } else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") && - n + 4 < ARRAYLEN(buf)) { - mempcpy(mempcpy(buf, p, n), ".dbg", 5); - if (fileexists(buf)) { - res = buf; - } - } else if (n + 8 < ARRAYLEN(buf)) { - mempcpy(mempcpy(buf, p, n), ".com.dbg", 9); - if (fileexists(buf)) { - res = buf; - } + p = GetProgramExecutableName(); + n = strlen(p); + if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) { + res = p; + } else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") && + n + 4 < ARRAYLEN(buf)) { + mempcpy(mempcpy(buf, p, n), ".dbg", 5); + if (fileexists(buf)) { + res = buf; } + } else if (n + 8 < ARRAYLEN(buf)) { + mempcpy(mempcpy(buf, p, n), ".com.dbg", 9); + if (fileexists(buf)) { + res = buf; + } + } + if (!res) { + res = getenv("COMDBG"); } once = true; } diff --git a/libc/runtime/fork-nt.c b/libc/runtime/fork-nt.c index e737f6f3e..7ef8b4ac0 100644 --- a/libc/runtime/fork-nt.c +++ b/libc/runtime/fork-nt.c @@ -19,7 +19,9 @@ #include "libc/bits/weaken.h" #include "libc/calls/internal.h" #include "libc/calls/ntspawn.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/fmt/itoa.h" #include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" @@ -45,7 +47,6 @@ #include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" -#include "libc/sock/ntstdin.internal.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" @@ -222,7 +223,6 @@ textwindows void WinMainForked(void) { // rewrap the stdin named pipe hack // since the handles closed on fork - if (weaken(ForkNtStdinWorker)) weaken(ForkNtStdinWorker)(); struct Fds *fds = VEIL("r", &g_fds); fds->p[0].handle = fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle); fds->p[1].handle = fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle); diff --git a/libc/runtime/fork.c b/libc/runtime/fork.c index ae9d242f3..252f5a1a3 100644 --- a/libc/runtime/fork.c +++ b/libc/runtime/fork.c @@ -19,8 +19,10 @@ #include "libc/bits/bits.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/nt/process.h" #include "libc/runtime/internal.h" diff --git a/libc/runtime/ftrace-hook.S b/libc/runtime/ftrace-hook.S index a679c52b1..b4d7f2885 100644 --- a/libc/runtime/ftrace-hook.S +++ b/libc/runtime/ftrace-hook.S @@ -20,7 +20,7 @@ .privileged ftrace_hook: - cmp $0,g_ftrace(%rip) + cmp $0,__ftrace(%rip) jg 1f ret 1: push %rbp diff --git a/libc/runtime/ftraceinit.greg.c b/libc/runtime/ftraceinit.greg.c index 48bbc05aa..cb212bda1 100644 --- a/libc/runtime/ftraceinit.greg.c +++ b/libc/runtime/ftraceinit.greg.c @@ -35,7 +35,7 @@ textstartup int ftrace_init(void) { if (__intercept_flag(&__argc, __argv, "--ftrace")) { ftrace_install(); - ++g_ftrace; + ++__ftrace; } return __argc; } diff --git a/libc/runtime/ftracer.c b/libc/runtime/ftracer.c index 6f79f9b15..e4f16be5e 100644 --- a/libc/runtime/ftracer.c +++ b/libc/runtime/ftracer.c @@ -16,24 +16,16 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/safemacros.internal.h" +#include "libc/calls/calls.h" +#include "libc/fmt/itoa.h" #include "libc/intrin/cmpxchg.h" #include "libc/intrin/kprintf.h" -#include "libc/log/libfatal.internal.h" +#include "libc/intrin/lockcmpxchgp.h" #include "libc/macros.internal.h" -#include "libc/nexgen32e/rdtsc.h" -#include "libc/nexgen32e/rdtscp.h" #include "libc/nexgen32e/stackframe.h" -#include "libc/nexgen32e/x86feature.h" -#include "libc/runtime/memtrack.internal.h" -#include "libc/runtime/runtime.h" +#include "libc/nexgen32e/threaded.h" +#include "libc/runtime/stack.h" #include "libc/runtime/symbols.internal.h" -#include "libc/stdio/stdio.h" -#include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/o.h" -#include "libc/time/clockstonanos.internal.h" - -#pragma weak stderr #define MAX_NESTING 512 @@ -47,13 +39,15 @@ void ftrace_hook(void); -bool ftrace_enabled; -static int g_skew; -static int64_t g_lastaddr; -static uint64_t g_laststamp; +_Alignas(64) int ftrace_lock; -static privileged noinstrument noasan noubsan int GetNestingLevelImpl( - struct StackFrame *frame) { +static struct Ftrace { + int skew; + int stackdigs; + int64_t lastaddr; +} g_ftrace; + +static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) { int nesting = -2; while (frame) { ++nesting; @@ -62,15 +56,49 @@ static privileged noinstrument noasan noubsan int GetNestingLevelImpl( return MAX(0, nesting); } -static privileged noinstrument noasan noubsan int GetNestingLevel( - struct StackFrame *frame) { +static privileged inline int GetNestingLevel(struct StackFrame *frame) { int nesting; nesting = GetNestingLevelImpl(frame); - if (nesting < g_skew) g_skew = nesting; - nesting -= g_skew; + if (nesting < g_ftrace.skew) g_ftrace.skew = nesting; + nesting -= g_ftrace.skew; return MIN(MAX_NESTING, nesting); } +static privileged inline void ReleaseFtraceLock(void) { + int zero = 0; + __atomic_store(&ftrace_lock, &zero, __ATOMIC_RELAXED); +} + +static privileged inline bool AcquireFtraceLock(void) { + int me, owner; + unsigned tries; + if (!__threaded) { + return _cmpxchg(&ftrace_lock, 0, -1); + } else { + for (tries = 0, me = gettid();;) { + owner = 0; + if (_lockcmpxchgp(&ftrace_lock, &owner, me)) { + return true; + } + if (owner == -1) { + // avoid things getting weird after first clone() call transition + return false; + } + if (owner == me) { + // we ignore re-entry into ftrace. while the code and build config + // is written to make re-entry highly unlikely, it's impossible to + // guarantee. there's also the possibility of asynchronous signals + return false; + } + if (++tries & 7) { + __builtin_ia32_pause(); + } else { + sched_yield(); + } + } + } +} + /** * Prints name of function being called. * @@ -78,35 +106,30 @@ static privileged noinstrument noasan noubsan int GetNestingLevel( * prologues of other functions. We assume those functions behave * according to the System Five NexGen32e ABI. */ -privileged noinstrument noasan noubsan void ftracer(void) { - /* asan runtime depends on this function */ - uint64_t stamp; - static bool noreentry; +privileged void ftracer(void) { + long stackuse; struct StackFrame *frame; - if (!_cmpxchg(&noreentry, 0, 1)) return; - if (ftrace_enabled) { - stamp = rdtsc(); + if (AcquireFtraceLock()) { frame = __builtin_frame_address(0); frame = frame->next; - if (frame->addr != g_lastaddr) { - kprintf("+ %*s%t %d\r\n", GetNestingLevel(frame) * 2, "", frame->addr, - ClocksToNanos(stamp, g_laststamp)); - g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc(); - g_lastaddr = frame->addr; + if (frame->addr != g_ftrace.lastaddr) { + stackuse = (intptr_t)GetStackAddr(0) + GetStackSize() - (intptr_t)frame; + kprintf("%rFUN %5P %'13T %'*ld %*s%t\n", g_ftrace.stackdigs, stackuse, + GetNestingLevel(frame) * 2, "", frame->addr); + g_ftrace.lastaddr = frame->addr; } + ReleaseFtraceLock(); } - noreentry = 0; } textstartup int ftrace_install(void) { if (GetSymbolTable()) { - g_lastaddr = -1; - g_laststamp = kStartTsc; - g_skew = GetNestingLevelImpl(__builtin_frame_address(0)); - ftrace_enabled = 1; + g_ftrace.lastaddr = -1; + g_ftrace.stackdigs = LengthInt64Thousands(GetStackSize()); + g_ftrace.skew = GetNestingLevelImpl(__builtin_frame_address(0)); return __hook(ftrace_hook, GetSymbolTable()); } else { - kprintf("error: --ftrace failed to open symbol table\r\n"); + kprintf("error: --ftrace failed to open symbol table\n"); return -1; } } diff --git a/libc/runtime/getdosenviron.c b/libc/runtime/getdosenviron.c index 58f3e3bf1..c9dd991b2 100644 --- a/libc/runtime/getdosenviron.c +++ b/libc/runtime/getdosenviron.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/str/tpenc.h" @@ -23,6 +24,19 @@ #define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c)) +forceinline int IsAlpha(int c) { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); +} + +forceinline char *MemChr(const char *s, unsigned char c, unsigned long n) { + for (; n; --n, ++s) { + if ((*s & 255) == c) { + return s; + } + } + return 0; +} + static textwindows noasan noinstrument axdx_t Recode16to8(char *dst, size_t dstsize, const char16_t *src) { @@ -45,13 +59,51 @@ static textwindows noasan noinstrument axdx_t Recode16to8(char *dst, } w = tpenc(x); do { - if (r.ax + 1 >= dstsize) break; - dst[r.ax++] = w; + if (r.ax + 1 < dstsize) { + dst[r.ax++] = w; + } else { + break; + } } while ((w >>= 8)); } + if (r.ax < dstsize) { + dst[r.ax] = 0; + } return r; } +textwindows noinstrument noasan void FixPath(char *path) { + char *p; + size_t i; + + // turn backslash into slash + for (p = path; *p; ++p) { + if (*p == '\\') { + *p = '/'; + } + } + + // turn c:/... into /c/... + p = path; + if (IsAlpha(p[0]) && p[1] == ':' && p[2] == '/') { + p[1] = p[0]; + p[0] = '/'; + } + for (; *p; ++p) { + if (p[0] == ';' && IsAlpha(p[1]) && p[2] == ':' && p[3] == '/') { + p[2] = p[1]; + p[1] = '/'; + } + } + + // turn semicolon into colon + for (p = path; *p; ++p) { + if (*p == ';') { + *p = ':'; + } + } +} + /** * Transcodes NT environment variable block from UTF-16 to UTF-8. * @@ -66,12 +118,17 @@ textwindows noasan noinstrument int GetDosEnviron(const char16_t *env, char *buf, size_t size, char **envp, size_t max) { int i; + char *p; axdx_t r; i = 0; --size; while (*env) { if (i + 1 < max) envp[i++] = buf; r = Recode16to8(buf, size, env); + if ((p = memchr(buf, '=', r.ax)) && IsAlpha(p[1]) && p[2] == ':' && + (p[3] == '\\' || p[3] == '/')) { + FixPath(p + 1); + } size -= r.ax + 1; buf += r.ax + 1; env += r.dx; diff --git a/libc/runtime/getinstructionlengths.c b/libc/runtime/getinstructionlengths.c new file mode 100644 index 000000000..73b57d8a3 --- /dev/null +++ b/libc/runtime/getinstructionlengths.c @@ -0,0 +1,59 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/macros.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/prot.h" +#include "third_party/xed/x86.h" + +/** + * Returns lengths of x86 ops in binary. + * + * The first decoded instruction is at `_ereal`. Lengths can be 1 to 15 + * bytes. Each byte in the return value is in that range, and the array + * is NUL terminated. The returned memory is memoized, since this costs + * some time. For example, for a 10mb Python binary, it takes 20 millis + * so the basic idea is is you can use this output multiple times which + * is a faster way to iterate over the binary than calling Xed. + * + * @return nul-terminated length array on success, or null + */ +privileged unsigned char *GetInstructionLengths(void) { + static bool once; + int i, n, err, len, rem; + static unsigned char *res; + struct XedDecodedInst xedd; + unsigned char *p, *mem, *code; + if (!once) { + if ((mem = mmap(0, ROUNDUP(__privileged_addr - _ereal + 1, FRAMESIZE), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, + 0)) != MAP_FAILED) { + for (p = mem, code = _ereal; code < __privileged_addr; code += len) { + rem = __privileged_addr - code; + xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); + err = xed_instruction_length_decode(&xedd, code, rem); + *p++ = len = !err ? xedd.length : 1; + } + res = mem; + } + once = true; + } + return res; +} diff --git a/libc/runtime/getinterpreterexecutablename.c b/libc/runtime/getinterpreterexecutablename.c index 2f3aa6c24..f31ec9c7b 100644 --- a/libc/runtime/getinterpreterexecutablename.c +++ b/libc/runtime/getinterpreterexecutablename.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/macros.internal.h" #include "libc/runtime/runtime.h" @@ -51,6 +51,9 @@ char *GetInterpreterExecutableName(char *p, size_t n) { if (n < 2) { errno = ENAMETOOLONG; } else if (IsWindows() || IsXnu()) { + // TODO(jart): Does XNU guarantee argv[0] is legit? + // Otherwise we should return NULL. + // What about OpenBSD? if (strlen(GetProgramExecutableName()) < n) { strcpy(p, GetProgramExecutableName()); return p; diff --git a/libc/runtime/getmaxfd.c b/libc/runtime/getmaxfd.c index 81b8c06ae..59704886e 100644 --- a/libc/runtime/getmaxfd.c +++ b/libc/runtime/getmaxfd.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/rlimit.h" diff --git a/libc/runtime/getsymboltable.greg.c b/libc/runtime/getsymboltable.c similarity index 84% rename from libc/runtime/getsymboltable.greg.c rename to libc/runtime/getsymboltable.c index 60af4749a..45c8c4750 100644 --- a/libc/runtime/getsymboltable.greg.c +++ b/libc/runtime/getsymboltable.c @@ -20,6 +20,7 @@ #include "libc/bits/bits.h" #include "libc/bits/weaken.h" #include "libc/calls/strace.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/symbols.internal.h" @@ -29,7 +30,8 @@ #include "libc/zip.h" #include "libc/zipos/zipos.internal.h" -static struct SymbolTable *g_symtab; +static int g_lock; +hidden struct SymbolTable *__symtab; // for kprintf /** * Looks for `.symtab` in zip central directory. @@ -68,6 +70,7 @@ static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) { memcpy(res, (void *)ZIP_LFILE_CONTENT(zipos->map + lf), size); break; #if 0 + // TODO(jart): fix me case kZipCompressionDeflate: rc = undeflate(res, size, (void *)ZIP_LFILE_CONTENT(zipos->map + lf), GetZipLfileCompressedSize(zipos->map + lf), &ds); @@ -93,7 +96,13 @@ static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) { * @note This code can't depend on dlmalloc() */ static struct SymbolTable *GetSymbolTableFromElf(void) { - return OpenSymbolTable(FindDebugBinary()); + int e; + const char *s; + if ((s = FindDebugBinary())) { + return OpenSymbolTable(s); + } else { + return 0; + } } /** @@ -114,24 +123,26 @@ static struct SymbolTable *GetSymbolTableFromElf(void) { * Function tracing is disabled throughout the duration of this call. * Backtraces and other core runtime functionality depend on this. * - * @return symbol table, or NULL w/ errno on first call + * @return symbol table, or NULL if not found */ struct SymbolTable *GetSymbolTable(void) { struct Zipos *z; - if (!g_symtab && !__isworker) { + if (_trylock(&g_lock)) return 0; + if (!__symtab && !__isworker) { if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) { - if ((g_symtab = GetSymbolTableFromZip(z))) { - g_symtab->names = - (uint32_t *)((char *)g_symtab + g_symtab->names_offset); - g_symtab->name_base = - (char *)((char *)g_symtab + g_symtab->name_base_offset); + if ((__symtab = GetSymbolTableFromZip(z))) { + __symtab->names = + (uint32_t *)((char *)__symtab + __symtab->names_offset); + __symtab->name_base = + (char *)((char *)__symtab + __symtab->name_base_offset); } } - if (!g_symtab) { - g_symtab = GetSymbolTableFromElf(); + if (!__symtab) { + __symtab = GetSymbolTableFromElf(); } } - return g_symtab; + _spunlock(&g_lock); + return __symtab; } /** @@ -140,11 +151,14 @@ struct SymbolTable *GetSymbolTable(void) { * @param t if null will be auto-populated only if already open * @return index or -1 if nothing found */ -privileged int __get_symbol(struct SymbolTable *t, intptr_t a) { - /* asan runtime depends on this function */ +noinstrument privileged int __get_symbol(struct SymbolTable *t, intptr_t a) { + // we need privileged because: + // kprintf is privileged and it depends on this + // we don't want function tracing because: + // function tracing depends on this function via kprintf unsigned l, m, r, n, k; - if (!t && g_symtab) { - t = g_symtab; + if (!t && __symtab) { + t = __symtab; } if (t) { l = 0; diff --git a/libc/runtime/hook.greg.c b/libc/runtime/hook.greg.c index a6fea7f8d..8ba9cda96 100644 --- a/libc/runtime/hook.greg.c +++ b/libc/runtime/hook.greg.c @@ -18,11 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/sigbits.h" #include "libc/calls/struct/sigset.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/log/libfatal.internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/symbols.internal.h" @@ -56,82 +56,70 @@ privileged noinstrument noasan int __hook(void *ifunc, uint64_t code, mcode; sigset_t mask, oldmask; intptr_t kMcount = (intptr_t)&mcount; - intptr_t kProgramCodeStart = (intptr_t)&_ereal; - intptr_t kPrivilegedStart = (intptr_t)&__privileged_start; - bool kIsBinaryAligned = !(kPrivilegedStart & (PAGESIZE - 1)); - if (!IsWindows()) { - sigfillset(&mask); - sys_sigprocmask(SIG_BLOCK, &mask, &oldmask); - } - if ((rc = mprotect( - (void *)symbols->addr_base, kPrivilegedStart - symbols->addr_base, - kIsBinaryAligned ? PROT_READ | PROT_WRITE - : PROT_READ | PROT_WRITE | PROT_EXEC)) != -1) { - for (i = 0; i < symbols->count; ++i) { - if (symbols->addr_base + symbols->symbols[i].x < kProgramCodeStart) { - continue; - } - if (symbols->addr_base + symbols->symbols[i].y >= kPrivilegedStart) { + intptr_t kProgramCodeStart = (intptr_t)_ereal; + intptr_t kPrivilegedStart = (intptr_t)__privileged_addr; + if (!symbols) return -1; + __morph_begin(); + for (i = 0; i < symbols->count; ++i) { + if (symbols->addr_base + symbols->symbols[i].x < kProgramCodeStart) { + continue; + } + if (symbols->addr_base + symbols->symbols[i].y >= kPrivilegedStart) { + break; + } + for (p = (char *)symbols->addr_base + symbols->symbols[i].x, + pe = (char *)symbols->addr_base + symbols->symbols[i].y; + p + 8 - 1 <= pe; ++p) { + code = ((uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 | + (uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 | + (uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 | + (uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000); + + /* + * Test for -mrecord-mcount (w/ -fpie or -fpic) + * + * nopw 0x00(%rax,%rax,1) ← morphed by package.com + * call *mcount(%rip) ← linked w/o -static + * addr32 call mcount ← relaxed w/ -static + * addr32 call mcount ← relaxed w/ -static + * + * Note that gcc refuses to insert the six byte nop. + */ + if ((code & 0x0000FFFFFFFFFFFF) == 0x0000441F0F66 || + (code & 0x0000FFFFFFFFFFFF) == + ((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xE867) & + 0x0000FFFFFFFFFFFF) || + (code & 0x0000FFFFFFFFFFFF) == + ((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xFF15) & + 0x0000FFFFFFFFFFFF)) { + p[0] = 0x67; + p[1] = 0xE8; + addr = (intptr_t)ifunc - ((intptr_t)&p[2] + 4); + p[2] = (addr & 0x000000ff) >> 000; + p[3] = (addr & 0x0000ff00) >> 010; + p[4] = (addr & 0x00ff0000) >> 020; + p[5] = (addr & 0xff000000) >> 030; break; } - for (p = (char *)symbols->addr_base + symbols->symbols[i].x, - pe = (char *)symbols->addr_base + symbols->symbols[i].y; - p + 8 - 1 <= pe; ++p) { - code = ((uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 | - (uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 | - (uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 | - (uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000); - /* - * Test for -mrecord-mcount (w/ -fpie or -fpic) - * - * nopw 0x00(%rax,%rax,1) ← morphed by package.com - * call *mcount(%rip) ← linked w/o -static - * addr32 call mcount ← relaxed w/ -static - * addr32 call mcount ← relaxed w/ -static - * - * Note that gcc refuses to insert the six byte nop. - */ - if ((code & 0x0000FFFFFFFFFFFF) == 0x0000441F0F66 || - (code & 0x0000FFFFFFFFFFFF) == - ((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xE867) & - 0x0000FFFFFFFFFFFF) || - (code & 0x0000FFFFFFFFFFFF) == - ((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xFF15) & - 0x0000FFFFFFFFFFFF)) { - p[0] = 0x67; - p[1] = 0xE8; - addr = (intptr_t)ifunc - ((intptr_t)&p[2] + 4); - p[2] = (addr & 0x000000ff) >> 000; - p[3] = (addr & 0x0000ff00) >> 010; - p[4] = (addr & 0x00ff0000) >> 020; - p[5] = (addr & 0xff000000) >> 030; - break; - } - - /* - * Test for -mnop-mcount (w/ -fno-pie) - */ - mcode = code & 0x000000FFFFFFFFFF; - if ((mcode == 0x00441F0F /* nopl 0x00(%eax,%eax,1) [canonical] */) || - (mcode == 0x00041F0F67 /* nopl (%eax,%eax,1) [older gcc] */)) { - if (p[-1] != 0x66 /* nopw 0x0(%rax,%rax,1) [donotwant] */) { - p[0] = 0xE8 /* call Jvds */; - addr = (intptr_t)ifunc - ((intptr_t)&p[1] + 4); - p[1] = (addr & 0x000000ff) >> 000; - p[2] = (addr & 0x0000ff00) >> 010; - p[3] = (addr & 0x00ff0000) >> 020; - p[4] = (addr & 0xff000000) >> 030; - } - break; + /* + * Test for -mnop-mcount (w/ -fno-pie) + */ + mcode = code & 0x000000FFFFFFFFFF; + if ((mcode == 0x00441F0F /* nopl 0x00(%eax,%eax,1) [canonical] */) || + (mcode == 0x00041F0F67 /* nopl (%eax,%eax,1) [older gcc] */)) { + if (p[-1] != 0x66 /* nopw 0x0(%rax,%rax,1) [donotwant] */) { + p[0] = 0xE8 /* call Jvds */; + addr = (intptr_t)ifunc - ((intptr_t)&p[1] + 4); + p[1] = (addr & 0x000000ff) >> 000; + p[2] = (addr & 0x0000ff00) >> 010; + p[3] = (addr & 0x00ff0000) >> 020; + p[4] = (addr & 0xff000000) >> 030; } + break; } } - mprotect((void *)symbols->addr_base, kPrivilegedStart - symbols->addr_base, - PROT_READ | PROT_EXEC); } - if (!IsWindows()) { - sys_sigprocmask(SIG_SETMASK, &oldmask, NULL); - } - return rc; + __morph_end(); + return 0; } diff --git a/libc/runtime/isheap.c b/libc/runtime/isheap.c index a532b4380..6d3796e43 100644 --- a/libc/runtime/isheap.c +++ b/libc/runtime/isheap.c @@ -26,7 +26,9 @@ * @assume stack addresses are always greater than heap addresses * @assume stack memory isn't stored beneath %rsp (-mno-red-zone) */ -noasan bool _isheap(void *p) { - return kAutomapStart <= (intptr_t)p && - (intptr_t)p < kAutomapStart + kAutomapSize; +optimizesize noasan bool _isheap(void *p) { + intptr_t x, y; + x = kAutomapStart; + y = x + kAutomapSize; + return x <= (intptr_t)p && (intptr_t)p < y; } diff --git a/libc/runtime/memtrack.greg.c b/libc/runtime/memtrack.greg.c index 2d69982d6..9ea60d1e1 100644 --- a/libc/runtime/memtrack.greg.c +++ b/libc/runtime/memtrack.greg.c @@ -26,6 +26,7 @@ #include "libc/errno.h" #include "libc/intrin/asan.internal.h" #include "libc/log/libfatal.internal.h" +#include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/runtime/directmap.internal.h" @@ -38,7 +39,7 @@ static void *MoveMemoryIntervals(struct MemoryInterval *d, const struct MemoryInterval *s, int n) { - /* asan runtime depends on this function */ + // asan runtime depends on this function int i; assert(n >= 0); if (d > s) { @@ -54,7 +55,7 @@ static void *MoveMemoryIntervals(struct MemoryInterval *d, } static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) { - /* asan runtime depends on this function */ + // asan runtime depends on this function assert(i >= 0); assert(i + n <= mm->i); MoveMemoryIntervals(mm->p + i, mm->p + i + n, mm->i - (i + n)); @@ -70,7 +71,7 @@ static bool ExtendMemoryIntervals(struct MemoryIntervals *mm) { base = (char *)kMemtrackStart; prot = PROT_READ | PROT_WRITE; flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED; - /* TODO(jart): These map handles should not leak across NT fork() */ + // TODO(jart): These map handles should not leak across NT fork() if (mm->p == mm->s) { if (IsAsan()) { shad = (char *)(((intptr_t)base >> 3) + 0x7fff8000); @@ -99,7 +100,7 @@ static bool ExtendMemoryIntervals(struct MemoryIntervals *mm) { } int CreateMemoryInterval(struct MemoryIntervals *mm, int i) { - /* asan runtime depends on this function */ + // asan runtime depends on this function int rc; rc = 0; assert(i >= 0); @@ -112,7 +113,9 @@ int CreateMemoryInterval(struct MemoryIntervals *mm, int i) { static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) { if (CreateMemoryInterval(mm, i) == -1) return -1; - mm->p[i].y = x - 1; + mm->p[i + 0].size -= (size_t)(mm->p[i + 0].y - (x - 1)) * FRAMESIZE; + mm->p[i + 0].y = x - 1; + mm->p[i + 1].size -= (size_t)((y + 1) - mm->p[i + 1].x) * FRAMESIZE; mm->p[i + 1].x = y + 1; return 0; } @@ -123,31 +126,60 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, assert(y >= x); assert(AreMemoryIntervalsOk(mm)); if (!mm->i) return 0; + + // binary search for the lefthand side l = FindMemoryInterval(mm, x); if (l == mm->i) return 0; - if (!l && y < mm->p[l].x) return 0; if (y < mm->p[l].x) return 0; + + // binary search for the righthand side r = FindMemoryInterval(mm, y); if (r == mm->i || (r > l && y < mm->p[r].x)) --r; assert(r >= l); assert(x <= mm->p[r].y); + + // remove the middle of an existing map + // + // ----|mmmmmmmmmmmmmmmm|--------- before + // xxxxx + // ----|mmmm|-----|mmmmm|--------- after + // + // this isn't possible on windows because we track each + // 64kb segment on that platform using a separate entry if (l == r && x > mm->p[l].x && y < mm->p[l].y) { return PunchHole(mm, x, y, l); } + + // trim the right side of the lefthand map + // + // ----|mmmmmmm|-------------- before + // xxxxx + // ----|mmmm|----------------- after + // if (x > mm->p[l].x && x <= mm->p[l].y) { assert(y >= mm->p[l].y); if (IsWindows()) return einval(); + mm->p[l].size -= (size_t)(mm->p[l].y - (x - 1)) * FRAMESIZE; mm->p[l].y = x - 1; assert(mm->p[l].x <= mm->p[l].y); ++l; } + + // trim the left side of the righthand map + // + // ------------|mmmmm|-------- before + // xxxxx + // ---------------|mm|-------- after + // if (y >= mm->p[r].x && y < mm->p[r].y) { assert(x <= mm->p[r].x); if (IsWindows()) return einval(); + mm->p[r].size -= (size_t)((y + 1) - mm->p[r].x) * FRAMESIZE; mm->p[r].x = y + 1; assert(mm->p[r].x <= mm->p[r].y); --r; } + if (l <= r) { if (IsWindows() && wf) { wf(mm, l, r); @@ -160,23 +192,42 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, int prot, int flags, bool readonlyfile, bool iscow, long offset, long size) { - /* asan runtime depends on this function */ + // asan runtime depends on this function unsigned i; assert(y >= x); assert(AreMemoryIntervalsOk(mm)); + i = FindMemoryInterval(mm, x); + + // try to extend the righthand side of the lefthand entry + // we can't do that if we're tracking independent handles + // we can't do that if it's a file map with a small size! if (i && x == mm->p[i - 1].y + 1 && h == mm->p[i - 1].h && - prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags) { + prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags && + mm->p[i - 1].size == + (size_t)(mm->p[i - 1].y - mm->p[i - 1].x) * FRAMESIZE + FRAMESIZE) { + mm->p[i - 1].size += (size_t)(y - mm->p[i - 1].y) * FRAMESIZE; mm->p[i - 1].y = y; + // if we filled the hole then merge the two mappings if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h && prot == mm->p[i].prot && flags == mm->p[i].flags) { mm->p[i - 1].y = mm->p[i].y; + mm->p[i - 1].size += mm->p[i].size; RemoveMemoryIntervals(mm, i, 1); } - } else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h && - prot == mm->p[i].prot && flags == mm->p[i].flags) { + } + + // try to extend the lefthand side of the righthand entry + // we can't do that if we're creating a smaller file map! + else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h && + prot == mm->p[i].prot && flags == mm->p[i].flags && + size == (size_t)(y - x) * FRAMESIZE + FRAMESIZE) { + mm->p[i].size += (size_t)(mm->p[i].x - x) * FRAMESIZE; mm->p[i].x = x; - } else { + } + + // otherwise, create a new entry and memmove the items + else { if (CreateMemoryInterval(mm, i) == -1) return -1; mm->p[i].x = x; mm->p[i].y = y; diff --git a/libc/runtime/memtrack.internal.h b/libc/runtime/memtrack.internal.h index ce551b24b..ea64eaec6 100644 --- a/libc/runtime/memtrack.internal.h +++ b/libc/runtime/memtrack.internal.h @@ -1,10 +1,10 @@ #ifndef COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_ #define COSMOPOLITAN_LIBC_RUNTIME_MEMTRACK_H_ #include "libc/assert.h" +#include "libc/bits/midpoint.h" #include "libc/dce.h" #include "libc/macros.internal.h" -#include "libc/nt/enum/version.h" -#include "libc/runtime/runtime.h" +#include "libc/nt/version.h" #include "libc/runtime/stack.h" #include "libc/sysv/consts/ss.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) @@ -28,16 +28,16 @@ COSMOPOLITAN_C_START_ ROUNDUP(VSPACE / FRAMESIZE * (intptr_t)sizeof(struct MemoryInterval), \ FRAMESIZE) #define _kMem(NORMAL, WIN7) \ - (!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7) + (!IsWindows() || IsAtLeastWindows10() ? NORMAL : WIN7) struct MemoryInterval { int x; int y; long h; + long size; int prot; int flags; long offset; - long size; bool iscow; bool readonlyfile; }; @@ -46,7 +46,7 @@ struct MemoryIntervals { size_t i, n; struct MemoryInterval *p; struct MemoryInterval s[OPEN_MAX]; - _Alignas(64) char lock; + _Alignas(64) int lock; }; extern hidden struct MemoryIntervals _mmi; @@ -90,25 +90,27 @@ forceinline pureconst bool IsShadowFrame(int x) { } forceinline pureconst bool IsKernelFrame(int x) { - return (int)(GetStaticStackAddr(0) >> 16) <= x && - x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> - 16); + intptr_t stack = (intptr_t)GetStaticStackAddr(0); + return (int)(stack >> 16) <= x && + x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16); } forceinline pureconst bool IsStaticStackFrame(int x) { - return (int)(GetStaticStackAddr(0) >> 16) <= x && - x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> - 16); + intptr_t stack = (intptr_t)GetStaticStackAddr(0); + return (int)(stack >> 16) <= x && + x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16); } forceinline pureconst bool IsStackFrame(int x) { - return (int)(GetStackAddr(0) >> 16) <= x && - x <= (int)((GetStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16); + intptr_t stack = (intptr_t)GetStackAddr(0); + return (int)(stack >> 16) <= x && + x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16); } forceinline pureconst bool IsSigAltStackFrame(int x) { - return (int)(GetStackAddr(0) >> 16) <= x && - x <= (int)((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16); + intptr_t stack = (intptr_t)GetStackAddr(0); + return (int)(stack >> 16) <= x && + x <= (int)((stack + (SIGSTKSZ - FRAMESIZE)) >> 16); } forceinline pureconst bool IsOldStackFrame(int x) { @@ -166,7 +168,7 @@ forceinline unsigned FindMemoryInterval(const struct MemoryIntervals *mm, l = 0; r = mm->i; while (l < r) { - m = (l + r) >> 1; + m = _midpoint(l, r); if (mm->p[m].y < x) { l = m + 1; } else { diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index d9e0337ab..34f5f507f 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -22,6 +22,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" @@ -68,57 +69,83 @@ static wontreturn void OnUnrecoverableMmapError(const char *s) { _Exit(199); } -noasan static bool IsMapped(char *p, size_t n) { - return OverlapsImageSpace(p, n) || IsMemtracked(FRAME(p), FRAME(p + (n - 1))); +static noasan inline bool OverlapsExistingMapping(char *p, size_t n) { + int a, b, i; + assert(n > 0); + a = FRAME(p); + b = FRAME(p + (n - 1)); + i = FindMemoryInterval(&_mmi, a); + if (i < _mmi.i) { + if (a <= _mmi.p[i].x && _mmi.p[i].x <= b) return true; + if (a <= _mmi.p[i].y && _mmi.p[i].y <= b) return true; + if (_mmi.p[i].x <= a && b <= _mmi.p[i].y) return true; + } + return false; } -noasan static bool NeedAutomap(char *p, size_t n) { - return !p || OverlapsArenaSpace(p, n) || OverlapsShadowSpace(p, n) || - IsMapped(p, n); -} - -noasan static bool ChooseMemoryInterval(int x, int n, int *res) { - int i; +static noasan bool ChooseMemoryInterval(int x, int n, int align, int *res) { + int i, start, end; + assert(align > 0); if (_mmi.i) { + + // find the start of the automap memory region i = FindMemoryInterval(&_mmi, x); if (i < _mmi.i) { - if (x + n < _mmi.p[i].x) { - *res = x; - return true; + + // check to see if there's space available before the first entry + if (!__builtin_add_overflow(x, align - 1, &start)) { + start &= -align; + if (!__builtin_add_overflow(start, n - 1, &end)) { + if (end < _mmi.p[i].x) { + *res = start; + return true; + } + } } + + // check to see if there's space available between two entries while (++i < _mmi.i) { - if (_mmi.p[i].x - _mmi.p[i - 1].y > n) { - *res = _mmi.p[i - 1].y + 1; - return true; + if (!__builtin_add_overflow(_mmi.p[i - 1].y, 1, &start) && + !__builtin_add_overflow(start, align - 1, &start)) { + start &= -align; + if (!__builtin_add_overflow(start, n - 1, &end)) { + if (end < _mmi.p[i].x) { + *res = start; + return true; + } + } } } } - if (INT_MAX - _mmi.p[i - 1].y >= n) { - *res = _mmi.p[i - 1].y + 1; - return true; + + // otherwise append after the last entry if space is available + if (!__builtin_add_overflow(_mmi.p[i - 1].y, 1, &start) && + !__builtin_add_overflow(start, align - 1, &start)) { + start &= -align; + if (!__builtin_add_overflow(start, n - 1, &end)) { + *res = start; + return true; + } } - return false; + } else { - *res = x; - return true; + // if memtrack is empty, then just assign the requested address + // assuming it doesn't overflow + if (!__builtin_add_overflow(x, align - 1, &start)) { + start &= -align; + if (!__builtin_add_overflow(start, n - 1, &end)) { + *res = start; + return true; + } + } } + + return false; } -noasan static bool Automap(int n, int *res) { - *res = -1; - if (ChooseMemoryInterval(FRAME(kAutomapStart), n, res)) { - assert(*res >= FRAME(kAutomapStart)); - if (*res + n <= FRAME(kAutomapStart + (kAutomapStart - 1))) { - return true; - } else { - STRACE("mmap(%.12p, %p) ENOMEM (automap interval exhausted)", ADDR(*res), - ADDR(n + 1)); - return false; - } - } else { - STRACE("mmap(%.12p, %p) ENOMEM (automap failed)", ADDR(*res), ADDR(n + 1)); - return false; - } +noasan static bool Automap(int count, int align, int *res) { + return ChooseMemoryInterval(FRAME(kAutomapStart), count, align, res) && + *res + count <= FRAME(kAutomapStart + (kAutomapSize - 1)); } noasan static size_t GetMemtrackSize(struct MemoryIntervals *mm) { @@ -221,21 +248,16 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, } #endif char *p = addr; - bool needguard; struct DirectMap dm; - size_t virtualused, virtualneed; int a, b, i, f, m, n, x; + bool needguard, clashes; + size_t virtualused, virtualneed; if (UNLIKELY(!size)) { STRACE("size=0"); return VIP(einval()); } - if (UNLIKELY(!IsLegalSize(size))) { - STRACE("size isn't 48-bit"); - return VIP(einval()); - } - if (UNLIKELY(!IsLegalPointer(p))) { STRACE("p isn't 48-bit"); return VIP(einval()); @@ -266,29 +288,28 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, return VIP(einval()); } - if (UNLIKELY(INT64_MAX - size < off)) { - STRACE("too large"); - return VIP(einval()); - } - if (UNLIKELY(!ALIGNED(off))) { STRACE("p isn't 64kb aligned"); return VIP(einval()); } - if ((flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) { -#ifdef SYSDEBUG - if (OverlapsImageSpace(p, size)) { - STRACE("overlaps image"); - } else { - STRACE("overlaps existing"); + if (fd == -1) { + size = ROUNDUP(size, FRAMESIZE); + if (IsWindows()) { + prot |= PROT_WRITE; /* kludge */ } -#endif - return VIP(efault()); + } else if (__isfdkind(fd, kFdZip)) { + STRACE("fd is zipos handle"); + return VIP(einval()); } - if (__isfdkind(fd, kFdZip)) { - STRACE("fd is zipos handle"); + if (UNLIKELY(!IsLegalSize(size))) { + STRACE("size isn't 48-bit"); + return VIP(einval()); + } + + if (UNLIKELY(INT64_MAX - size < off)) { + STRACE("too large"); return VIP(einval()); } @@ -301,15 +322,29 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, return VIP(enomem()); } - if (fd == -1) { - size = ROUNDUP(size, FRAMESIZE); - if (IsWindows()) { - prot |= PROT_WRITE; /* kludge */ - } + clashes = OverlapsImageSpace(p, size) || OverlapsExistingMapping(p, size); + + if ((flags & MAP_FIXED_NOREPLACE) == MAP_FIXED_NOREPLACE && clashes) { + STRACE("noreplace overlaps existing"); + return VIP(eexist()); + } + + if (__builtin_add_overflow((int)(size >> 16), (int)!!(size & (FRAMESIZE - 1)), + &n)) { + STRACE("memory range overflows"); + return VIP(einval()); + } + + // if size is a two power then automap will use it as alignment + if (IS2POW(size)) { + a = size >> 16; + if (!a) { + a = 1; + } + } else { + a = 1; } - n = (int)(size >> 16) + !!(size & (FRAMESIZE - 1)); - assert(n > 0); f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; if (flags & MAP_FIXED) { x = FRAME(p); @@ -318,10 +353,11 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, OnUnrecoverableMmapError("FIXED UNTRACK FAILED"); } } - } else if (!NeedAutomap(p, size)) { + } else if (p && !clashes && !OverlapsArenaSpace(p, size) && + !OverlapsShadowSpace(p, size)) { x = FRAME(p); - } else if (!Automap(n, &x)) { - STRACE("AUTOMAP OUT OF MEMORY D:"); + } else if (!Automap(n, a, &x)) { + STRACE("automap has no room for %d frames with %d alignment", n, a); return VIP(enomem()); } @@ -429,14 +465,21 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags, * compile-time checks to ensure some char[8192] vars will not * create an undetectable overflow into another thread's stack * Your `flags` may optionally bitwise or any of the following: - * - `MAP_FIXED` in which case `addr` becomes more than a hint - * - `MAP_FIXED_NOREPLACE` to protect existing maps (Linux-only) * - `MAP_ANONYMOUS` in which case `fd == -1` should be the case + * - `MAP_FIXED` in which case `addr` becomes more than a hint + * - `MAP_FIXED_NOREPLACE` to protect existing mappings; this is + * always polyfilled by mmap() which tracks its own memory and + * removed before passing to the kernel, in order to support + * old versions; if you believe mappings exist which only the + * kernel knows, then this flag may be passed to sys_mmap() on + * Linux 4.17+ and FreeBSD (where it has multiple bits) * - `MAP_CONCEAL` is FreeBSD/NetBSD/OpenBSD-only * - `MAP_NORESERVE` is Linux/XNU/NetBSD-only - * - `MAP_LOCKED` is Linux-only - * - `MAP_POPULATE` is Linux-only + * - `MAP_POPULATE` is Linux/FreeBSD-only * - `MAP_NONBLOCK` is Linux-only + * - `MAP_NOSYNC` is FreeBSD-only + * - `MAP_INHERIT` is NetBSD-only + * - `MAP_LOCKED` is Linux-only * @param fd is an open()'d file descriptor, whose contents shall be * made available w/ automatic reading at the chosen address and * must be -1 if MAP_ANONYMOUS is specified diff --git a/libc/runtime/morph.greg.c b/libc/runtime/morph.greg.c new file mode 100644 index 000000000..1f11a7f31 --- /dev/null +++ b/libc/runtime/morph.greg.c @@ -0,0 +1,79 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#define ShouldUseMsabiAttribute() 1 +#include "libc/bits/asmflag.h" +#include "libc/calls/internal.h" +#include "libc/calls/sigbits.h" +#include "libc/calls/struct/sigset.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/intrin/kprintf.h" +#include "libc/nt/enum/pageflags.h" +#include "libc/nt/memory.h" +#include "libc/nt/runtime.h" +#include "libc/nt/thunk/msabi.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/nr.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sig.h" + +__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect; + +static int64_t vector; +static sigset_t oldss; + +static privileged void __morph_mprotect(void *addr, size_t size, int prot, + int ntprot) { + int ax, dx; + uint32_t op; + if (!IsWindows()) { + asm volatile("syscall" + : "=a"(ax), "=d"(dx) + : "0"(__NR_mprotect), "D"(addr), "S"(size), "1"(prot) + : "rcx", "r11", "memory"); + } else { + __imp_VirtualProtect(addr, size, ntprot, &op); + } +} + +/** + * Begins code morphing execuatble. + * + * @return 0 on success, or -1 w/ errno + */ +privileged void __morph_begin(void) { + sigset_t ss; + if (!IsWindows()) { + sigfillset(&ss); + sys_sigprocmask(SIG_BLOCK, &ss, &oldss); + } + __morph_mprotect(_base, __privileged_addr - _base, PROT_READ | PROT_WRITE, + kNtPageWritecopy); +} + +/** + * Begins code morphing execuatble. + */ +privileged void __morph_end(void) { + __morph_mprotect(_base, __privileged_addr - _base, PROT_READ | PROT_EXEC, + kNtPageExecuteRead); + if (!IsWindows()) { + sys_sigprocmask(SIG_SETMASK, &oldss, 0); + } +} diff --git a/libc/runtime/mprotect.greg.c b/libc/runtime/mprotect.greg.c index b15e36c76..5b38ba2e4 100644 --- a/libc/runtime/mprotect.greg.c +++ b/libc/runtime/mprotect.greg.c @@ -17,9 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/likely.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" +#include "libc/errno.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/kprintf.h" #include "libc/runtime/internal.h" @@ -35,15 +36,17 @@ * @return 0 on success, or -1 w/ errno * @see mmap() */ -privileged int mprotect(void *addr, size_t size, int prot) { +int mprotect(void *addr, size_t size, int prot) { int64_t rc; if (SupportsWindows() && (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_GROWSDOWN | PROT_GROWSUP))) { - rc = einval(); // unix checks prot before checking size + errno = EINVAL; // unix checks prot before checking size + rc = -1; } else if (!size) { return 0; // make new technology consistent with unix } else if (UNLIKELY((intptr_t)addr & 4095)) { - rc = einval(); + errno = EINVAL; // unix checks prot before checking size + rc = -1; } else if (!IsWindows()) { rc = sys_mprotect(addr, size, prot); } else { diff --git a/libc/runtime/mremap.c b/libc/runtime/mremap.c index 0233e962d..1ff4a3a84 100644 --- a/libc/runtime/mremap.c +++ b/libc/runtime/mremap.c @@ -20,7 +20,6 @@ #include "libc/bits/likely.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" diff --git a/libc/runtime/msync-nt.c b/libc/runtime/msync-nt.c index 22e680587..d20221144 100644 --- a/libc/runtime/msync-nt.c +++ b/libc/runtime/msync-nt.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/nt/files.h" diff --git a/libc/runtime/msync.c b/libc/runtime/msync.c index b23370cf3..4547c4e97 100644 --- a/libc/runtime/msync.c +++ b/libc/runtime/msync.c @@ -18,8 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-nt.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/macros.internal.h" #include "libc/sysv/consts/msync.h" diff --git a/libc/runtime/munmap.c b/libc/runtime/munmap.c index 19146c221..b929d9648 100644 --- a/libc/runtime/munmap.c +++ b/libc/runtime/munmap.c @@ -16,16 +16,23 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/bits/likely.h" -#include "libc/calls/internal.h" +#include "libc/bits/weaken.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" +#include "libc/log/backtrace.internal.h" #include "libc/log/libfatal.internal.h" +#include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/runtime/directmap.internal.h" +#include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" @@ -36,89 +43,123 @@ #define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16) #define FRAME(x) ((int)((intptr_t)(x) >> 16)) -static noasan int Munmap(void *v, size_t n) { - char poison, *p = v; +static noasan int Munmap(char *, size_t); + +static noasan void MunmapShadow(char *p, size_t n) { + intptr_t a, b, x, y; + KERNTRACE("MunmapShadow(%p, %'zu)", p, n); + a = ((intptr_t)p >> 3) + 0x7fff8000; + b = a + (n >> 3); + if (IsMemtracked(FRAME(a), FRAME(b - 1))) { + x = ROUNDUP(a, FRAMESIZE); + y = ROUNDDOWN(b, FRAMESIZE); + if (0 && x < y) { + // delete shadowspace if unmapping ≥512kb. in practice it has + // to be >1mb since we can only unmap it if it's aligned, and + // as such we poison the edges if there are any. + __repstosb((void *)a, kAsanUnmapped, x - a); + Munmap((void *)x, y - x); + __repstosb((void *)y, kAsanUnmapped, b - y); + } else { + // otherwise just poison and assume reuse + __repstosb((void *)a, kAsanUnmapped, b - a); + } + } else { + STRACE("unshadow(%.12p, %p) EFAULT", a, b - a); + } +} + +// our api supports doing things like munmap(0, 0x7fffffffffff) but some +// platforms (e.g. openbsd) require that we know the specific intervals +// or else it returns EINVAL. so we munmap a piecewise. +static noasan void MunmapImpl(char *p, size_t n) { + char *q; + size_t m; + intptr_t a, b, c; + int i, l, r, rc, beg, end; + KERNTRACE("MunmapImpl(%p, %'zu)", p, n); + l = FRAME(p); + r = FRAME(p + n - 1); + i = FindMemoryInterval(&_mmi, l); + for (; i < _mmi.i && r >= _mmi.p[i].x; ++i) { + if (l >= _mmi.p[i].x && r <= _mmi.p[i].y) { + + // it's contained within the entry + beg = l; + end = r; + } else if (l <= _mmi.p[i].x && r >= _mmi.p[i].x) { + + // it overlaps with the lefthand side of the entry + beg = _mmi.p[i].x; + end = MIN(r, _mmi.p[i].y); + } else if (l <= _mmi.p[i].y && r >= _mmi.p[i].y) { + + // it overlaps with the righthand side of the entry + beg = MAX(_mmi.p[i].x, l); + end = _mmi.p[i].y; + } else { + // shouldn't be possible + assert(!"binary search panic"); + continue; + } + // openbsd even requires that if we mapped, for instance a 5 byte + // file, that we be sure to call munmap(file, 5). let's abstract! + a = ADDR(beg); + b = ADDR(end) + FRAMESIZE; + c = ADDR(_mmi.p[i].x) + _mmi.p[i].size; + q = (char *)a; + m = MIN(b, c) - a; + if (!IsWindows()) { + rc = sys_munmap(q, m); + assert(!rc); + } else { + // Handled by UntrackMemoryIntervals() on Windows + } + if (IsAsan() && !OverlapsShadowSpace(p, n)) { + MunmapShadow(q, m); + } + } +} + +static noasan int Munmap(char *p, size_t n) { + unsigned i; + char poison; intptr_t a, b, x, y; assert(!__vforked); - if (UNLIKELY(!n)) { - STRACE("munmap(%.12p, %'zu) %s (n=0)", p, n); + STRACE("munmap(%.12p, %'zu) EINVAL (n=0)", p, n); return einval(); } - if (UNLIKELY(!IsLegalSize(n))) { STRACE("munmap(%.12p, %'zu) EINVAL (n isn't 48-bit)", p, n); return einval(); } - if (UNLIKELY(!IsLegalPointer(p))) { STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, n); return einval(); } - if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) { STRACE("munmap(%.12p, %'zu) EINVAL (p+(n-1) isn't 48-bit)", p, n); return einval(); } - if (UNLIKELY(!ALIGNED(p))) { STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, n); return einval(); } - - if (!IsMemtracked(FRAME(p), FRAME(p + (n - 1)))) { - STRACE("munmap(%.12p, %'zu) EFAULT (interval not tracked)", p, n); - return efault(); - } - - if (UntrackMemoryIntervals(p, n) == -1) { - return -1; - } - - if (IsWindows()) { - return 0; // UntrackMemoryIntervals does it for NT - } - - if (sys_munmap(p, n) == -1) { - return -1; // ouch - } - - if (IsAsan() && !OverlapsShadowSpace(p, n)) { - a = ((intptr_t)p >> 3) + 0x7fff8000; - b = a + (n >> 3); - if (IsMemtracked(FRAME(a), FRAME(b - 1))) { - x = ROUNDUP(a, FRAMESIZE); - y = ROUNDDOWN(b, FRAMESIZE); - if (x < y) { - // delete shadowspace if unmapping ≥512kb - __repstosb((void *)a, kAsanUnmapped, x - a); - Munmap((void *)x, y - x); - __repstosb((void *)y, kAsanUnmapped, b - y); - } else { - // otherwise just poison and assume reuse - __repstosb((void *)a, kAsanUnmapped, b - a); - } - } else { - STRACE("unshadow(%.12p, %p) EFAULT", a, b - a); - } - } - - return 0; + MunmapImpl(p, n); + return UntrackMemoryIntervals(p, n); } /** * Releases memory pages. * - * This function may be used to punch holes in existing mappings, but - * your mileage may vary on Windows. - * - * @param p is a pointer within any memory mapped region the process - * has permission to control, such as address ranges returned by - * mmap(), the program image itself, etc. - * @param n is the number of bytes to be unmapped, and needs to be a - * multiple of FRAMESIZE for anonymous mappings, because windows - * and for files size needs to be perfect to the byte bc openbsd + * @param p is the beginning of the memory region to unmap + * @param n is the number of bytes to be unmapped * @return 0 on success, or -1 w/ errno + * @raises EINVAL if `n == 0` + * @raises EINVAL if `n` isn't 48-bit + * @raises EINVAL if `p+(n-1)` isn't 48-bit + * @raises EINVAL if `p` isn't 65536-byte aligned */ noasan int munmap(void *p, size_t n) { int rc; diff --git a/libc/runtime/printargs.greg.c b/libc/runtime/printargs.greg.c index 3d871d8fb..55e2f98f1 100644 --- a/libc/runtime/printargs.greg.c +++ b/libc/runtime/printargs.greg.c @@ -147,8 +147,8 @@ textstartup void __printargs(const char *prologue) { struct pollfd pfds[128]; } u; - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); + --__ftrace; + --__strace; e = errno; PRINT(""); @@ -337,7 +337,7 @@ textstartup void __printargs(const char *prologue) { PRINT(""); PRINT("MEMTRACK"); - PrintMemoryIntervals(2, &_mmi); + __print_maps(); PRINT(""); PRINT("TERMIOS"); @@ -547,7 +547,7 @@ textstartup void __printargs(const char *prologue) { } PRINT(""); - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); + ++__strace; + ++__ftrace; errno = e; } diff --git a/libc/runtime/printmaps.c b/libc/runtime/printmaps.c new file mode 100644 index 000000000..adba80522 --- /dev/null +++ b/libc/runtime/printmaps.c @@ -0,0 +1,30 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/spinlock.h" +#include "libc/runtime/memtrack.internal.h" +#include "libc/runtime/runtime.h" + +/** + * Prints memory mappings to stderr. + */ +void __print_maps(void) { + _spinlock(&_mmi.lock); + PrintMemoryIntervals(2, &_mmi); + _spunlock(&_mmi.lock); +} diff --git a/libc/runtime/printmemoryintervals.c b/libc/runtime/printmemoryintervals.c index 2fdfebce4..00a1e5825 100644 --- a/libc/runtime/printmemoryintervals.c +++ b/libc/runtime/printmemoryintervals.c @@ -41,10 +41,16 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) { for (i = 0; i < mm->i; ++i) { frames = mm->p[i].y + 1 - mm->p[i].x; maptally += frames; - kprintf("%012lx-%012lx %s %'*ldx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1), + kprintf("%08x-%08x %s %'*ldx%s", mm->p[i].x, mm->p[i].y, DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames, DescribeFrame(mm->p[i].x)); - if (i + 1 < _mmi.i) { + if (mm->p[i].iscow) kprintf(" cow"); + if (mm->p[i].readonlyfile) kprintf(" readonlyfile"); + if (mm->p[i].size != + (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE + FRAMESIZE) { + kprintf(" size=%'zu", mm->p[i].size); + } + if (i + 1 < mm->i) { frames = mm->p[i + 1].x - mm->p[i].y - 1; if (frames && IsNoteworthyHole(i, mm)) { gaptally += frames; diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index 989c6b2de..f486d4909 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -14,10 +14,12 @@ extern char **__argv; /* CRT */ extern char **__envp; /* CRT */ extern unsigned long *__auxv; /* CRT */ extern intptr_t __oldstack; /* CRT */ +extern uint64_t __nosync; /* SYS */ +extern _Atomic(int) __ftrace; /* SYS */ +extern _Atomic(int) __strace; /* SYS */ extern char *program_invocation_name; /* RII */ extern char *program_invocation_short_name; /* RII */ -extern int g_ftrace; /* CRT */ -extern uint64_t g_syscount; /* RII */ +extern uint64_t __syscount; /* RII */ extern const uint64_t kStartTsc; /* RII */ extern const char kTmpPath[]; /* RII */ extern const char kNtSystemDirectory[]; /* RII */ @@ -28,15 +30,16 @@ extern unsigned char _etext[] forcealign(PAGESIZE); /* αpε */ extern unsigned char _edata[] forcealign(PAGESIZE); /* αpε */ extern unsigned char _ezip[]; /* αpε */ extern unsigned char _end[] forcealign(FRAMESIZE); /* αpε */ -extern unsigned char _ereal; /* αpε */ -extern unsigned char __privileged_start; /* αpε */ -extern unsigned char __test_start; /* αpε */ -extern unsigned char __ro; /* αpε */ +extern unsigned char _ereal[]; /* αpε */ +extern unsigned char __privileged_start[]; /* αpε */ +extern unsigned char __privileged_addr[]; /* αpε */ +extern unsigned char __privileged_size[]; /* αpε */ +extern unsigned char __test_start[]; /* αpε */ +extern unsigned char __ro[]; /* αpε */ extern unsigned char *__relo_start[]; /* αpε */ extern unsigned char *__relo_end[]; /* αpε */ extern uint8_t __zip_start[]; /* αpε */ extern uint8_t __zip_end[]; /* αpε */ -extern bool ftrace_enabled; extern size_t __virtualmax; extern bool __isworker; @@ -105,6 +108,11 @@ char *GetInterpreterExecutableName(char *, size_t); void __printargs(const char *); void __paginate(int, const char *); int __arg_max(void); +void __morph_begin(void); +void __morph_end(void); +unsigned char *GetFirstInstruction(void); +unsigned char *GetInstructionLengths(void); +void __print_maps(void); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/runtime/runtime.mk b/libc/runtime/runtime.mk index 1892b2408..43501f3a3 100644 --- a/libc/runtime/runtime.mk +++ b/libc/runtime/runtime.mk @@ -43,7 +43,8 @@ LIBC_RUNTIME_A_DIRECTDEPS = \ LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ - LIBC_SYSV_CALLS + LIBC_SYSV_CALLS \ + THIRD_PARTY_XED LIBC_RUNTIME_A_DEPS := \ $(call uniq,$(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x)))) @@ -57,22 +58,26 @@ $(LIBC_RUNTIME_A).pkg: \ $(LIBC_RUNTIME_A_OBJS) \ $(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x)_A).pkg) +# we can't use asan and ubsan because: +# asan and ubsan can be function traced +# we can't use function tracing because: +# this is the function tracing runtime +o/$(MODE)/libc/runtime/ftracer.o: \ + OVERRIDE_CFLAGS += \ + -x-no-pg \ + -mno-fentry \ + -ffreestanding \ + -fno-sanitize=all + o/$(MODE)/libc/runtime/fork-nt.o \ o/$(MODE)/libc/runtime/printmemoryintervals.o \ o/$(MODE)/libc/runtime/arememoryintervalsok.o \ -o/$(MODE)/libc/runtime/directmap.o \ -o/$(MODE)/libc/runtime/directmapnt.o \ o/$(MODE)/libc/runtime/findmemoryinterval.o \ -o/$(MODE)/libc/runtime/ftrace.greg.o \ -o/$(MODE)/libc/runtime/ftracer.o \ -o/$(MODE)/libc/runtime/ezmap.o \ +o/$(MODE)/libc/runtime/sys_mprotect.greg.o \ o/$(MODE)/libc/runtime/getdosargv.o \ o/$(MODE)/libc/runtime/getdosenviron.o \ o/$(MODE)/libc/runtime/hook.greg.o \ -o/$(MODE)/libc/runtime/mprotect.greg.o \ -o/$(MODE)/libc/runtime/mprotect-nt.greg.o \ o/$(MODE)/libc/runtime/ismemtracked.greg.o \ -o/$(MODE)/libc/runtime/isheap.o \ o/$(MODE)/libc/runtime/memtracknt.o \ o/$(MODE)/libc/runtime/memtrack.greg.o \ o/$(MODE)/libc/runtime/metalprintf.greg.o \ @@ -82,9 +87,9 @@ o/$(MODE)/libc/runtime/print.greg.o \ o/$(MODE)/libc/runtime/stackchkfail.o \ o/$(MODE)/libc/runtime/stackchkfaillocal.o \ o/$(MODE)/libc/runtime/winmain.greg.o \ -o/$(MODE)/libc/runtime/opensymboltable.o \ -o/$(MODE)/libc/runtime/getsymboltable.greg.o: \ +o/$(MODE)/libc/runtime/opensymboltable.o: \ OVERRIDE_CFLAGS += \ + -Os \ -ffreestanding \ $(NO_MAGIC) diff --git a/libc/runtime/stack.h b/libc/runtime/stack.h index 789094553..88781ced6 100644 --- a/libc/runtime/stack.h +++ b/libc/runtime/stack.h @@ -12,6 +12,7 @@ * This defaults to `STACKSIZE`. The bottom-most page will be protected * to ensure your stack does not magically grow beyond this value. It's * possible to detect stack overflows, by calling `ShowCrashReports()`. + * Your stack size must be a power of two; the linker will check this. * * If you want to know how much stack your programs needs, then * @@ -28,11 +29,17 @@ /** * Tunes APE stack virtual address. * - * This defaults to `0x7e0000000000 - STACKSIZE`. The value defined by - * this macro will be respected, with two exceptions: (1) in MODE=tiny - * the operating system provided stack is used instead and (2) Windows - * Seven doesn't support 64-bit addresses so 0x10000000 - GetStackSize - * is used instead. + * This value must be aligned according to your stack size, and that's + * checked by your linker script. This defaults to `0x700000000000` so + * + * 1. It's easy to see how close you are to the bottom + * 2. The linker script error is unlikely to happen + * + * This macro will be respected, with two exceptions + * + * 1. In MODE=tiny the operating system provided stack is used instead + * 2. Windows 7 doesn't support 64-bit addresses, so we'll instead use + * `0x10000000 - GetStackSize()` as the stack address * * @see libc/sysv/systemfive.S * @see libc/nt/winmain.greg.c @@ -56,16 +63,33 @@ extern char ape_stack_prot[] __attribute__((__weak__)); extern char ape_stack_memsz[] __attribute__((__weak__)); extern char ape_stack_align[] __attribute__((__weak__)); +/** + * Returns size of stack, which is always a two power. + */ #define GetStackSize() ((uintptr_t)ape_stack_memsz) /** * Returns address of bottom of stack. + * + * This takes into consideration threads and sigaltstack. This is + * implemented as a fast pure expression, since we're able to make the + * assumption that stack sizes are two powers and aligned. This is + * thanks to (1) the linker script checks the statically chosen sizes, + * and (2) the mmap() address picker will choose aligned addresses when + * the provided size is a two power. */ -#define GetStackAddr(ADDEND) \ - ((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + (ADDEND)) +#define GetStackAddr(ADDEND) \ + ((void *)((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + \ + (ADDEND))) /** * Returns preferred bottom address of stack. + * + * This is the stakc address of the main process. The only time that + * isn't guaranteed to be the case is in MODE=tiny, since it doesn't + * link the code for stack creation at startup. This generally isn't + * problematic, since MODE=tiny doesn't use any of the runtime codes + * which want the stack to be cheaply knowable, e.g. ftrace, kprintf */ #define GetStaticStackAddr(ADDEND) \ ({ \ @@ -78,7 +102,7 @@ extern char ape_stack_align[] __attribute__((__weak__)); } else { \ vAddr = 0x10000000; \ } \ - vAddr; \ + (void *)vAddr; \ }) COSMOPOLITAN_C_END_ diff --git a/libc/runtime/stackchkfail.c b/libc/runtime/stackchkfail.c index ad42a392d..29caaeb51 100644 --- a/libc/runtime/stackchkfail.c +++ b/libc/runtime/stackchkfail.c @@ -16,59 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/pushpop.h" -#include "libc/nt/enum/version.h" -#include "libc/nt/runtime.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/internal.h" -#include "libc/sysv/consts/fileno.h" -#include "libc/sysv/consts/nr.h" -#define STACK_SMASH_MESSAGE "stack smashed\n" - -/** - * Aborts program under enemy fire to avoid being taken alive. - */ -privileged noasan void __stack_chk_fail(void) { - size_t len; - const char *msg; - int64_t ax, cx, si; - if (!IsWindows()) { - msg = STACK_SMASH_MESSAGE; - len = pushpop(sizeof(STACK_SMASH_MESSAGE) - 1); - if (!IsMetal()) { - asm volatile("syscall" - : "=a"(ax) - : "0"(__NR_write), "D"(pushpop(STDERR_FILENO)), "S"(msg), - "d"(len) - : "rcx", "r11", "cc", "memory"); - asm volatile("syscall" - : "=a"(ax) - : "0"(__NR_exit_group), "D"(pushpop(23)) - : "rcx", "r11", "cc", "memory"); - } - asm volatile("rep outsb" - : "=S"(si), "=c"(cx) - : "0"(msg), "1"(len), "d"(0x3F8 /* COM1 */) - : "memory"); - asm("push\t$0\n\t" - "push\t$0\n\t" - "cli\n\t" - "lidt\t(%rsp)"); - for (;;) asm("ud2"); - } - if (NtGetVersion() < kNtVersionFuture) { - do { - asm volatile("syscall" - : "=a"(ax), "=c"(cx) - : "0"(NtGetVersion() < kNtVersionWindows8 ? 0x0029 - : NtGetVersion() < kNtVersionWindows81 ? 0x002a - : NtGetVersion() < kNtVersionWindows10 ? 0x002b - : 0x002c), - "1"(pushpop(-1L)), "d"(42) - : "r11", "cc", "memory"); - } while (!ax); - } - for (;;) { - TerminateProcess(GetCurrentProcess(), 42); - } +privileged noasan noinstrument void __stack_chk_fail(void) { + kprintf("stack smashed\n"); + __restorewintty(); + _Exit(207); } diff --git a/libc/runtime/stackuse.c b/libc/runtime/stackuse.c index 9e7138ae0..def93da70 100644 --- a/libc/runtime/stackuse.c +++ b/libc/runtime/stackuse.c @@ -16,9 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" #include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/fmt/itoa.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" #include "libc/str/str.h" @@ -26,16 +28,23 @@ static char stacklog[1024]; -static size_t NullLength(const char *s) { - typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16))); - size_t n; - xmm_t v, z = {0}; - unsigned m, k = (uintptr_t)s & 15; - const xmm_t *p = (const xmm_t *)((uintptr_t)s & -16); - m = (__builtin_ia32_pmovmskb128(*p == z) ^ 0xffff) >> k << k; - while (!m) m = __builtin_ia32_pmovmskb128(*++p == z) ^ 0xffff; - n = (const char *)p + __builtin_ctzl(m) - s; - return n; +size_t GetStackUsage(char *s, size_t n) { + // RHEL5 MAP_GROWSDOWN seems to only grow to 68kb :'( + // So we count non-zero bytes down from the top + // First clear 64 bytes is considered the end + long *p; + size_t got; + p = (long *)(s + n); + got = 0; + for (;;) { + p -= 8; + if (p[0] | p[1] | p[2] | p[3] | p[4] | p[5] | p[6] | p[7]) { + ++got; + } else { + break; + } + } + return got * 8 * sizeof(long); } static textexit void LogStackUse(void) { @@ -43,10 +52,8 @@ static textexit void LogStackUse(void) { bool quote; char *p, *q; size_t n, usage; - const char *stack; + usage = GetStackUsage(GetStackAddr(0), GetStackSize()); fd = open(stacklog, O_APPEND | O_CREAT | O_WRONLY, 0644); - stack = (char *)GetStackAddr(0); - usage = GetStackSize() - (NullLength(stack + PAGESIZE) + PAGESIZE); p = FormatUint64(stacklog, usage); for (i = 0; i < __argc; ++i) { n = strlen(__argv[i]); diff --git a/libc/intrin/winthread.c b/libc/runtime/symbols.c similarity index 83% rename from libc/intrin/winthread.c rename to libc/runtime/symbols.c index 89c193fbe..846eba41e 100644 --- a/libc/intrin/winthread.c +++ b/libc/runtime/symbols.c @@ -16,23 +16,15 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/weaken.h" #include "libc/dce.h" -#include "libc/intrin/tls.h" -#include "libc/intrin/winthread.internal.h" +#include "libc/log/backtrace.internal.h" +#include "libc/log/log.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/symbols.internal.h" -/** - * @fileoverview TLS slot for clone() win32 polyfill. - */ - -int __winthread; - -static textstartup void __winthread_init(void) { - if (IsWindows()) { - __winthread = TlsAlloc(); - TlsSetValue(__winthread, 0); +void __init_symbols(void) { + if (__strace || (IsAsan() && weaken(__die))) { + GetSymbolTable(); } } - -const void *const __winthread_ctor[] initarray = { - __winthread_init, -}; diff --git a/libc/runtime/untrackmemoryintervals.c b/libc/runtime/untrackmemoryintervals.c index 58d757ce4..16ccca652 100644 --- a/libc/runtime/untrackmemoryintervals.c +++ b/libc/runtime/untrackmemoryintervals.c @@ -16,17 +16,16 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/dce.h" #include "libc/macros.internal.h" #include "libc/runtime/memtrack.internal.h" int UntrackMemoryIntervals(void *addr, size_t size) { int a, b; + assert(size > 0); a = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16; b = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16; - if (SupportsWindows()) { - return ReleaseMemoryIntervals(&_mmi, a, b, ReleaseMemoryNt); - } else { - return ReleaseMemoryIntervals(&_mmi, a, b, 0); - } + return ReleaseMemoryIntervals(&_mmi, a, b, + SupportsWindows() ? ReleaseMemoryNt : 0); } diff --git a/libc/runtime/vfork.S b/libc/runtime/vfork.S index b09a0ff36..8d8030ee5 100644 --- a/libc/runtime/vfork.S +++ b/libc/runtime/vfork.S @@ -53,7 +53,7 @@ vfork: call __stracef #endif /* SYSDEBUG */ mov __NR_vfork(%rip),%eax - mov errno(%rip),%r8d # avoid question of @vforksafe errno + mov __errno(%rip),%r8d # avoid question of @vforksafe errno pop %rsi # saves return address in a register #if SupportsBsd() testb IsBsd() @@ -65,7 +65,7 @@ vfork: cmp $-4095,%eax jae systemfive_error #endif -0: mov %r8d,errno(%rip) +0: mov %r8d,__errno(%rip) ezlea __vforked,di test %eax,%eax jz 1f diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 74bc3e64d..de60e3d78 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -19,8 +19,9 @@ #include "libc/bits/bits.h" #include "libc/bits/pushpop.h" #include "libc/bits/weaken.h" -#include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/elf/pf2prot.internal.h" #include "libc/errno.h" @@ -121,6 +122,16 @@ forceinline void MakeLongDoubleLongAgain(void) { asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw)); } +// https://nullprogram.com/blog/2022/02/18/ +static inline char16_t *MyCommandLine(void) { + void *cmd; + asm("mov\t%%gs:(0x60),%0\n" + "mov\t0x20(%0),%0\n" + "mov\t0x78(%0),%0\n" + : "=r"(cmd)); + return cmd; +} + static inline size_t StrLen16(const char16_t *s) { size_t n; for (n = 0;; ++n) { @@ -188,7 +199,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { _mmi.p = _mmi.s; _mmi.n = ARRAYLEN(_mmi.s); argsize = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE); - stackaddr = GetStaticStackAddr(0); + stackaddr = (intptr_t)GetStaticStackAddr(0); stacksize = GetStackSize(); allocsize = argsize + stacksize; allocaddr = stackaddr - argsize; @@ -206,7 +217,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { _mmi.p[0].x = allocaddr >> 16; _mmi.p[0].y = (allocaddr >> 16) + ((allocsize >> 16) - 1); _mmi.p[0].prot = prot; - _mmi.p[0].flags = MAP_PRIVATE | MAP_ANONYMOUS; + _mmi.p[0].flags = 0x00000026; // stack+anonymous _mmi.p[0].size = allocsize; _mmi.i = 1; wa = (struct WinArgs *)allocaddr; @@ -271,7 +282,7 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance, #if !IsTiny() __wincrashearly = AddVectoredExceptionHandler(1, (void *)OnEarlyWinCrash); #endif - cmdline = GetCommandLine(); + cmdline = MyCommandLine(); #ifdef SYSDEBUG /* sloppy flag-only check for early initialization */ if (__strstr16(cmdline, u"--strace")) ++__strace; diff --git a/libc/runtime/winthreadlaunch.S b/libc/runtime/winthreadlaunch.S new file mode 100644 index 000000000..fc86864be --- /dev/null +++ b/libc/runtime/winthreadlaunch.S @@ -0,0 +1,46 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" +.text.windows + +// Used by clone() on Windows to launch thread. +// +// Windows owns the stack memory when we initially enter threads. +// This function switches us over, so that we can start using the +// runtime facilities. +// +// @param %rdi is arg +// @param %rsi is func +// @param %rdx is stack +// @return %rax is exit code +// @see clone() +WinThreadLaunch: + push %rbx + push %r15 + mov %rbp,%r15 + mov %rsp,%rbx + mov %rdx,%rsp + xor %rbp,%rbp + call *%rsi + mov %r15,%rbp + mov %rbx,%rsp + pop %r15 + pop %rbx + ret + .endfn WinThreadLaunch,globl,hidden diff --git a/libc/sock/accept-nt.c b/libc/sock/accept-nt.c index d0bd84f4d..e0c667bd8 100644 --- a/libc/sock/accept-nt.c +++ b/libc/sock/accept-nt.c @@ -18,20 +18,16 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" -#include "libc/intrin/kprintf.h" +#include "libc/calls/state.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/mem/mem.h" -#include "libc/nt/files.h" -#include "libc/nt/struct/pollfd.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" -#include "libc/sock/yoink.inc" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/consts/fio.h" -#include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" -#include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sock.h" -#include "libc/sysv/consts/sol.h" #include "libc/sysv/errfuns.h" textwindows int sys_accept_nt(struct Fd *fd, void *addr, uint32_t *addrsize, @@ -44,7 +40,9 @@ textwindows int sys_accept_nt(struct Fd *fd, void *addr, uint32_t *addrsize, for (;;) { if (!WSAPoll(&(struct sys_pollfd_nt){fd->handle, POLLIN}, 1, __SIG_POLLING_INTERVAL_MS)) { - if (_check_interrupts(true, g_fds.p)) return eintr(); + if (_check_interrupts(true, g_fds.p)) { + return eintr(); + } continue; } if ((h = WSAAccept(fd->handle, addr, (int32_t *)addrsize, 0, 0)) != -1) { @@ -54,7 +52,8 @@ textwindows int sys_accept_nt(struct Fd *fd, void *addr, uint32_t *addrsize, if ((!(flags & SOCK_NONBLOCK) || __sys_ioctlsocket_nt(h, FIONBIO, (uint32_t[]){1}) != -1) && (sockfd2 = calloc(1, sizeof(struct SockFd)))) { - if ((client = __reservefd(-1)) != -1) { + _spinlock(&__fds_lock); + if ((client = __reservefd_unlocked(-1)) != -1) { sockfd2->family = sockfd->family; sockfd2->type = sockfd->type; sockfd2->protocol = sockfd->protocol; @@ -63,8 +62,10 @@ textwindows int sys_accept_nt(struct Fd *fd, void *addr, uint32_t *addrsize, g_fds.p[client].mode = 0140666; g_fds.p[client].handle = h; g_fds.p[client].extra = (uintptr_t)sockfd2; + _spunlock(&__fds_lock); return client; } + _spunlock(&__fds_lock); free(sockfd2); } __sys_closesocket_nt(h); diff --git a/libc/sock/accept4.c b/libc/sock/accept4.c index 168ca77b7..94120bfb2 100644 --- a/libc/sock/accept4.c +++ b/libc/sock/accept4.c @@ -16,13 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/sock/sockdebug.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/bind-nt.c b/libc/sock/bind-nt.c index 616a60220..d48c7a38a 100644 --- a/libc/sock/bind-nt.c +++ b/libc/sock/bind-nt.c @@ -17,13 +17,14 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/calls/internal.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/yoink.inc" #include "libc/sysv/errfuns.h" -textwindows int sys_bind_nt(struct Fd *fd, const void *addr, uint32_t addrsize) { +textwindows int sys_bind_nt(struct Fd *fd, const void *addr, + uint32_t addrsize) { assert(fd->kind == kFdSocket); if (__sys_bind_nt(fd->handle, addr, addrsize) != -1) { return 0; diff --git a/libc/sock/bind.c b/libc/sock/bind.c index a269b21a0..0a9074278 100644 --- a/libc/sock/bind.c +++ b/libc/sock/bind.c @@ -24,6 +24,7 @@ #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/sock/sockdebug.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" diff --git a/libc/sock/closesocket-nt.c b/libc/sock/closesocket-nt.c index baf2352ef..435017b23 100644 --- a/libc/sock/closesocket-nt.c +++ b/libc/sock/closesocket-nt.c @@ -16,8 +16,12 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/weaken.h" +#include "libc/intrin/kprintf.h" +#include "libc/log/backtrace.internal.h" #include "libc/mem/mem.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" /** * Closes socket on Windows. diff --git a/libc/sock/connect-nt.c b/libc/sock/connect-nt.c index 1481edfcf..bd66fe80c 100644 --- a/libc/sock/connect-nt.c +++ b/libc/sock/connect-nt.c @@ -17,9 +17,9 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/calls/internal.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/yoink.inc" #include "libc/sysv/errfuns.h" diff --git a/libc/sock/connect.c b/libc/sock/connect.c index 814cc18d4..71cf4c0c3 100644 --- a/libc/sock/connect.c +++ b/libc/sock/connect.c @@ -21,6 +21,7 @@ #include "libc/intrin/asan.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sockdebug.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/epoll.c b/libc/sock/epoll.c index 99e508734..14112e1a8 100644 --- a/libc/sock/epoll.c +++ b/libc/sock/epoll.c @@ -34,8 +34,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/intrin/spinlock.h" #include "libc/limits.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" @@ -1324,7 +1327,8 @@ static textwindows dontinline int sys_epoll_create1_nt(uint32_t flags) { struct PortState *port_state; struct TsTreeNode *tree_node; if (wepoll_init() < 0) return -1; - if ((fd = __reservefd(-1)) == -1) return -1; + fd = __reservefd(-1); + if (fd == -1) return -1; port_state = port_new(&ephnd); if (!port_state) { __releasefd(fd); @@ -1338,10 +1342,12 @@ static textwindows dontinline int sys_epoll_create1_nt(uint32_t flags) { __releasefd(fd); return -1; } + _spinlock(&__fds_lock); g_fds.p[fd].kind = kFdEpoll; g_fds.p[fd].handle = ephnd; g_fds.p[fd].flags = flags; g_fds.p[fd].mode = 0140666; + _spunlock(&__fds_lock); return fd; } diff --git a/libc/sock/firewall.c b/libc/sock/firewall.c index 738eaa21a..10bdfb4b7 100644 --- a/libc/sock/firewall.c +++ b/libc/sock/firewall.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" +#include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/log/log.h" #include "libc/sock/internal.h" diff --git a/libc/sock/fixupnewsockfd.c b/libc/sock/fixupnewsockfd.c index f73bc85c6..c4116a9af 100644 --- a/libc/sock/fixupnewsockfd.c +++ b/libc/sock/fixupnewsockfd.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/sock/internal.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/sock.h" diff --git a/libc/sock/gethostips.c b/libc/sock/gethostips.c index f0fa33a4a..7b47f901f 100644 --- a/libc/sock/gethostips.c +++ b/libc/sock/gethostips.c @@ -17,7 +17,11 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" -#include "libc/calls/internal.h" +#include "libc/calls/calls.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/dce.h" +#include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/nt/errors.h" #include "libc/nt/iphlpapi.h" diff --git a/libc/sock/getpeername-nt.c b/libc/sock/getpeername-nt.c index e21462a78..8ed54e952 100644 --- a/libc/sock/getpeername-nt.c +++ b/libc/sock/getpeername-nt.c @@ -17,10 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/yoink.inc" #include "libc/sysv/errfuns.h" diff --git a/libc/sock/getpeername.c b/libc/sock/getpeername.c index 677a2e5cf..db25832c0 100644 --- a/libc/sock/getpeername.c +++ b/libc/sock/getpeername.c @@ -16,13 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/sock/sockdebug.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/getsockname-nt.c b/libc/sock/getsockname-nt.c index 765c3357a..e8e1cb6e4 100644 --- a/libc/sock/getsockname-nt.c +++ b/libc/sock/getsockname-nt.c @@ -17,15 +17,15 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/yoink.inc" #include "libc/sysv/errfuns.h" textwindows int sys_getsockname_nt(struct Fd *fd, void *out_addr, - uint32_t *out_addrsize) { + uint32_t *out_addrsize) { assert(fd->kind == kFdSocket); if (__sys_getsockname_nt(fd->handle, out_addr, out_addrsize) != -1) { return 0; diff --git a/libc/sock/getsockname.c b/libc/sock/getsockname.c index 3def705a9..9add6709f 100644 --- a/libc/sock/getsockname.c +++ b/libc/sock/getsockname.c @@ -16,13 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/sock/sockdebug.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/getsockopt-nt.c b/libc/sock/getsockopt-nt.c index d64f6c5f6..41e521ed9 100644 --- a/libc/sock/getsockopt-nt.c +++ b/libc/sock/getsockopt-nt.c @@ -17,18 +17,15 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/bits/bits.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/timeval.h" #include "libc/nt/struct/linger.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" -#include "libc/sock/yoink.inc" +#include "libc/sock/syscall_fd.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sol.h" -#include "libc/sysv/errfuns.h" textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname, void *out_opt_optval, diff --git a/libc/sock/getsockopt.c b/libc/sock/getsockopt.c index d60d8d601..105d7ff26 100644 --- a/libc/sock/getsockopt.c +++ b/libc/sock/getsockopt.c @@ -16,13 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" #include "libc/fmt/magnumstrs.internal.h" #include "libc/intrin/asan.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/inet_pton.c b/libc/sock/inet_pton.c index baa0ce034..feba1780d 100644 --- a/libc/sock/inet_pton.c +++ b/libc/sock/inet_pton.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/fmt.h" +#include "libc/macros.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/sysv/consts/af.h" diff --git a/libc/sock/internal.h b/libc/sock/internal.h index 50486fb8a..29f130f11 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -1,6 +1,5 @@ #ifndef COSMOPOLITAN_LIBC_SOCK_INTERNAL_H_ #define COSMOPOLITAN_LIBC_SOCK_INTERNAL_H_ -#include "libc/calls/internal.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/thunk/msabi.h" #include "libc/nt/winsock.h" @@ -114,14 +113,6 @@ int32_t sys_epoll_wait(int32_t, void *, int32_t, int32_t) hidden; int sys_poll_metal(struct pollfd *, size_t, unsigned); int sys_poll_nt(struct pollfd *, uint64_t, uint64_t *) hidden; -int sys_getsockopt_nt(struct Fd *, int, int, void *, uint32_t *) hidden; -int sys_getsockname_nt(struct Fd *, void *, uint32_t *) hidden; -int sys_getpeername_nt(struct Fd *, void *, uint32_t *) hidden; -int sys_listen_nt(struct Fd *, int) hidden; -int sys_connect_nt(struct Fd *, const void *, uint32_t) hidden; -int sys_bind_nt(struct Fd *, const void *, uint32_t); -int sys_accept_nt(struct Fd *, void *, uint32_t *, int) hidden; -int sys_closesocket_nt(struct Fd *) hidden; int sys_socket_nt(int, int, int) hidden; /* int sys_socketpair_nt_stream(int, int, int, int[2]) hidden; @@ -129,18 +120,13 @@ int sys_socketpair_nt_dgram(int, int, int, int[2]) hidden; */ int sys_socketpair_nt(int, int, int, int[2]) hidden; int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *) hidden; -int sys_shutdown_nt(struct Fd *, int) hidden; -int sys_setsockopt_nt(struct Fd *, int, int, const void *, uint32_t) hidden; bool __asan_is_valid_msghdr(const struct msghdr *); ssize_t sys_send_nt(int, const struct iovec *, size_t, uint32_t) hidden; -ssize_t sys_recv_nt(struct Fd *, const struct iovec *, size_t, uint32_t) hidden; size_t __iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *, size_t) hidden; ssize_t sys_sendto_nt(int, const struct iovec *, size_t, uint32_t, void *, uint32_t) hidden; -ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t, - void *, uint32_t *) hidden; void WinSockInit(void) hidden; int64_t __winsockerr(void) nocallback hidden; diff --git a/libc/sock/kntwsadata.c b/libc/sock/kntwsadata.c index 133dffe3c..32950b2da 100644 --- a/libc/sock/kntwsadata.c +++ b/libc/sock/kntwsadata.c @@ -20,6 +20,7 @@ #include "libc/calls/calls.h" #include "libc/calls/strace.internal.h" #include "libc/dce.h" +#include "libc/intrin/spinlock.h" #include "libc/mem/mem.h" #include "libc/nt/runtime.h" #include "libc/nt/winsock.h" @@ -40,12 +41,6 @@ hidden struct NtWsaData kNtWsaData; static textwindows void WinSockCleanup(void) { int i, rc; NTTRACE("WinSockCleanup()"); - for (i = g_fds.n; i--;) { - if (g_fds.p[i].kind == kFdSocket) { - close(i); - } - } - // TODO(jart): Check WSACleanup() result code rc = WSACleanup(); NTTRACE("WSACleanup() → %d% lm", rc); } diff --git a/libc/sock/listen-nt.c b/libc/sock/listen-nt.c index be8800b4f..1816e5223 100644 --- a/libc/sock/listen-nt.c +++ b/libc/sock/listen-nt.c @@ -20,8 +20,7 @@ #include "libc/calls/internal.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" -#include "libc/sock/yoink.inc" -#include "libc/sysv/errfuns.h" +#include "libc/sock/syscall_fd.internal.h" textwindows int sys_listen_nt(struct Fd *fd, int backlog) { assert(fd->kind == kFdSocket); diff --git a/libc/sock/listen.c b/libc/sock/listen.c index c452a2ae9..a883ba7ff 100644 --- a/libc/sock/listen.c +++ b/libc/sock/listen.c @@ -21,6 +21,7 @@ #include "libc/dce.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/ntstdin.greg.c b/libc/sock/ntstdin.greg.c deleted file mode 100644 index b435a91da..000000000 --- a/libc/sock/ntstdin.greg.c +++ /dev/null @@ -1,150 +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 2022 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/calls/internal.h" -#include "libc/calls/strace.internal.h" -#include "libc/intrin/kprintf.h" -#include "libc/intrin/refcount.h" -#include "libc/intrin/spinlock.h" -#include "libc/mem/mem.h" -#include "libc/nexgen32e/nt2sysv.h" -#include "libc/nt/createfile.h" -#include "libc/nt/enum/accessmask.h" -#include "libc/nt/enum/creationdisposition.h" -#include "libc/nt/enum/fileflagandattributes.h" -#include "libc/nt/errors.h" -#include "libc/nt/events.h" -#include "libc/nt/ipc.h" -#include "libc/nt/runtime.h" -#include "libc/nt/synchronization.h" -#include "libc/nt/thread.h" -#include "libc/nt/thunk/msabi.h" -#include "libc/sock/ntstdin.internal.h" - -/** - * @fileoverview Pollable Standard Input for the New Technology. - */ - -static textwindows uint32_t StdinWorkerThread(void *arg) { - char buf[512]; - bool32 ok = true; - uint32_t i, rc, got, err, wrote; - struct NtStdinWorker w, *wp = arg; - NTTRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader, - wp->writer, wp->consumer, getpid(), gettid()); - _spunlock(&wp->sync); - w = *wp; - do { - ok = ReadFile(w.reader, buf, sizeof(buf), &got, 0); - /* When writing to a non-blocking, byte-mode pipe handle with - insufficient buffer space, WriteFile returns TRUE with - *lpNumberOfBytesWritten < nNumberOfBytesToWrite. - ──Quoth MSDN WriteFile() */ - for (i = 0; ok && i < got; i += wrote) { - ok = WriteFile(w.writer, buf + i, got - i, &wrote, 0); - } - } while (ok && got); - err = GetLastError(); - if (!ok) { - if (err == kNtErrorHandleEof || err == kNtErrorBrokenPipe || - err == kNtErrorNoData) { - ok = true; - } - } - NTTRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %u", w.reader, w.writer, - w.consumer, err); - return !ok; -} - -/** - * Converts read-only file descriptor to pollable named pipe. - * - * @param fd is open file descriptor to convert - * @return new object on success, or 0 w/ errno - */ -textwindows struct NtStdinWorker *NewNtStdinWorker(int fd) { - struct NtStdinWorker *w; - NTTRACE("LaunchNtStdinWorker(%d) pid %d tid %d", fd, getpid(), gettid()); - assert(!g_fds.p[fd].worker); - assert(__isfdopen(fd)); - if (!(w = calloc(1, sizeof(struct NtStdinWorker)))) return 0; - w->refs = 1; - w->sync = 1; - w->reader = g_fds.p[fd].handle; - if ((w->consumer = CreateNamedPipe( - CreatePipeName(w->name), - kNtPipeAccessInbound | kNtFileFlagOverlapped, - kNtPipeTypeByte | kNtPipeReadmodeByte | kNtPipeRejectRemoteClients, - 1, 512, 512, 0, 0)) != -1) { - if ((w->writer = CreateFile(w->name, kNtGenericWrite, 0, 0, kNtOpenExisting, - kNtFileFlagOverlapped, 0)) != -1) { - if ((w->worker = CreateThread(0, 0, NT2SYSV(StdinWorkerThread), w, 0, - &w->tid)) != -1) { - _spinlock(&w->sync); - g_fds.p[fd].handle = w->consumer; - g_fds.p[fd].worker = w; - return w; - } - CloseHandle(w->writer); - } - CloseHandle(w->consumer); - } - free(w); - return w; -} - -/** - * References stdin worker on the New Technology. - * @param w is non-null worker object - * @return worker object for new fd - */ -textwindows struct NtStdinWorker *RefNtStdinWorker(struct NtStdinWorker *w) { - _incref(&w->refs); - return w; -} - -/** - * Dereferences stdin worker on the New Technology. - * @param w is non-null worker object - * @return true if ok otherwise false - */ -textwindows bool UnrefNtStdinWorker(struct NtStdinWorker *w) { - bool ok = true; - if (_decref(&w->refs)) return true; - if (!CloseHandle(w->consumer)) ok = false; - if (!CloseHandle(w->writer)) ok = false; - if (!CloseHandle(w->reader)) ok = false; - if (!CloseHandle(w->worker)) ok = false; - free(w); - return ok; -} - -/** - * Runs post fork for stdin workers on the New Technology. - */ -textwindows void ForkNtStdinWorker(void) { - for (int i = 0; i < g_fds.n; ++i) { - if (g_fds.p[i].kind && g_fds.p[i].worker) { - g_fds.p[i].handle = g_fds.p[i].worker->reader; - free(g_fds.p[i].worker); - g_fds.p[i].worker = 0; - } - } -} diff --git a/libc/sock/ntstdin.internal.h b/libc/sock/ntstdin.internal.h deleted file mode 100644 index 4afd2d023..000000000 --- a/libc/sock/ntstdin.internal.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_ -#define COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -struct NtStdinWorker { /* non-inherited */ - volatile char sync; /* spin sync start */ - int refs; /* reference count */ - uint32_t tid; /* of the worker */ - int64_t reader; /* the real handle */ - int64_t writer; /* for the worker */ - int64_t worker; /* thread handle */ - int64_t consumer; /* same as Fd::handle */ - char16_t name[64]; /* for named pipe */ -}; - -struct NtStdinWorker *NewNtStdinWorker(int) hidden; -struct NtStdinWorker *RefNtStdinWorker(struct NtStdinWorker *) hidden; -bool UnrefNtStdinWorker(struct NtStdinWorker *) hidden; -void ForkNtStdinWorker(void) hidden; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_ */ diff --git a/libc/sock/recv-nt.c b/libc/sock/recv-nt.c index 5c2e0bc99..46dc83ebe 100644 --- a/libc/sock/recv-nt.c +++ b/libc/sock/recv-nt.c @@ -16,11 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/struct/iovec.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/recv.c b/libc/sock/recv.c index c818bcd83..79993705f 100644 --- a/libc/sock/recv.c +++ b/libc/sock/recv.c @@ -22,6 +22,7 @@ #include "libc/intrin/asan.internal.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/recvfrom-nt.c b/libc/sock/recvfrom-nt.c index 6ce60ca11..ba229096d 100644 --- a/libc/sock/recvfrom-nt.c +++ b/libc/sock/recvfrom-nt.c @@ -16,11 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/struct/iovec.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/recvfrom.c b/libc/sock/recvfrom.c index 7dde89a4a..3ff010a06 100644 --- a/libc/sock/recvfrom.c +++ b/libc/sock/recvfrom.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/iovec.h" #include "libc/dce.h" @@ -24,6 +23,7 @@ #include "libc/nt/winsock.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/recvmsg.c b/libc/sock/recvmsg.c index 3c70b0e47..644f61886 100644 --- a/libc/sock/recvmsg.c +++ b/libc/sock/recvmsg.c @@ -22,6 +22,7 @@ #include "libc/dce.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" diff --git a/libc/sock/select-nt.c b/libc/sock/select-nt.c index c2080efad..dfd1bd08f 100644 --- a/libc/sock/select-nt.c +++ b/libc/sock/select-nt.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" #include "libc/calls/struct/timeval.h" #include "libc/macros.internal.h" #include "libc/sock/internal.h" diff --git a/libc/sock/sendfile.c b/libc/sock/sendfile.c index 6cba06075..11d0d6b13 100644 --- a/libc/sock/sendfile.c +++ b/libc/sock/sendfile.c @@ -19,33 +19,78 @@ #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/sig.internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" +#include "libc/intrin/kprintf.h" +#include "libc/nt/enum/wait.h" +#include "libc/nt/errors.h" +#include "libc/nt/files.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/sendfile.internal.h" #include "libc/str/str.h" #include "libc/sysv/errfuns.h" +// sendfile() isn't specified as raising eintr +static textwindows int SendfileBlock(int64_t handle, + struct NtOverlapped *overlapped) { + uint32_t i, got, flags = 0; + if (WSAGetLastError() != kNtErrorIoPending) { + NTTRACE("TransmitFile failed %lm"); + return __winsockerr(); + } + for (;;) { + i = WSAWaitForMultipleEvents(1, &overlapped->hEvent, true, + __SIG_POLLING_INTERVAL_MS, true); + if (i == kNtWaitFailed) { + NTTRACE("WSAWaitForMultipleEvents failed %lm"); + return __winsockerr(); + } else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) { + _check_interrupts(true, g_fds.p); +#if _NTTRACE + POLLTRACE("WSAWaitForMultipleEvents..."); +#endif + } else { + break; + } + } + if (!WSAGetOverlappedResult(handle, overlapped, &got, false, &flags)) { + NTTRACE("WSAGetOverlappedResult failed %lm"); + return __winsockerr(); + } + return got; +} + static textwindows ssize_t sendfile_linux2nt(int outfd, int infd, int64_t *inout_opt_inoffset, size_t uptobytes) { - struct NtOverlapped Overlapped; - struct NtOverlapped *lpOverlapped; - if (!__isfdkind(outfd, kFdSocket) || !__isfdkind(outfd, kFdFile)) - return ebadf(); + ssize_t rc; + int64_t offset; + struct NtOverlapped overlapped; + if (!__isfdkind(outfd, kFdSocket)) return ebadf(); + if (!__isfdkind(infd, kFdFile)) return ebadf(); if (inout_opt_inoffset) { - bzero(&Overlapped, sizeof(Overlapped)); - Overlapped.Pointer = (void *)(intptr_t)(*inout_opt_inoffset); - lpOverlapped = &Overlapped; - } else { - lpOverlapped = NULL; + offset = *inout_opt_inoffset; + } else if (!SetFilePointerEx(g_fds.p[infd].handle, 0, &offset, SEEK_CUR)) { + return __winerr(); } - /* TODO(jart): Fetch this on a per-socket basis via GUID. */ + bzero(&overlapped, sizeof(overlapped)); + overlapped.Pointer = (void *)(intptr_t)offset; + overlapped.hEvent = WSACreateEvent(); if (TransmitFile(g_fds.p[outfd].handle, g_fds.p[infd].handle, uptobytes, 0, - lpOverlapped, NULL, 0)) { - return uptobytes; + &overlapped, 0, 0)) { + rc = uptobytes; } else { - return __winsockerr(); + rc = SendfileBlock(g_fds.p[outfd].handle, &overlapped); } + if (rc != -1 && inout_opt_inoffset) { + *inout_opt_inoffset = offset + rc; + } + WSACloseEvent(overlapped.hEvent); + return rc; } static ssize_t sendfile_linux2bsd(int outfd, int infd, @@ -88,7 +133,6 @@ ssize_t sendfile(int outfd, int infd, int64_t *inout_opt_inoffset, size_t uptobytes) { if (!uptobytes) return einval(); if (uptobytes > 0x7ffffffe /* Microsoft's off-by-one */) return eoverflow(); - if (IsModeDbg() && uptobytes > 1) uptobytes >>= 1; if (IsLinux()) { return sys_sendfile(outfd, infd, inout_opt_inoffset, uptobytes); } else if (IsFreebsd() || IsXnu()) { diff --git a/libc/sock/sendfile.internal.h b/libc/sock/sendfile.internal.h new file mode 100644 index 000000000..b8b237226 --- /dev/null +++ b/libc/sock/sendfile.internal.h @@ -0,0 +1,16 @@ +#ifndef COSMOPOLITAN_LIBC_SOCK_SENDFILE_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_SOCK_SENDFILE_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +int sys_sendfile_xnu(int32_t infd, int32_t outfd, int64_t offset, + int64_t *out_opt_sbytes, const void *opt_hdtr, + int32_t flags) hidden; + +int sys_sendfile_freebsd(int32_t infd, int32_t outfd, int64_t offset, + size_t nbytes, const void *opt_hdtr, + int64_t *out_opt_sbytes, int32_t flags) hidden; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_SOCK_SENDFILE_INTERNAL_H_ */ diff --git a/libc/sock/setsockopt-nt.c b/libc/sock/setsockopt-nt.c index 4f637d8cd..3b4106875 100644 --- a/libc/sock/setsockopt-nt.c +++ b/libc/sock/setsockopt-nt.c @@ -21,6 +21,7 @@ #include "libc/macros.internal.h" #include "libc/nt/struct/linger.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sol.h" #include "libc/sysv/errfuns.h" diff --git a/libc/sock/setsockopt.c b/libc/sock/setsockopt.c index c66b078eb..181f67703 100644 --- a/libc/sock/setsockopt.c +++ b/libc/sock/setsockopt.c @@ -25,6 +25,7 @@ #include "libc/nt/winsock.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/consts/so.h" #include "libc/sysv/errfuns.h" diff --git a/libc/sock/shutdown-nt.c b/libc/sock/shutdown-nt.c index d6433526b..c4582d02f 100644 --- a/libc/sock/shutdown-nt.c +++ b/libc/sock/shutdown-nt.c @@ -16,9 +16,9 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sock/syscall_fd.internal.h" textwindows int sys_shutdown_nt(struct Fd *fd, int how) { if (__sys_shutdown_nt(fd->handle, how) != -1) { diff --git a/libc/sock/shutdown.c b/libc/sock/shutdown.c index 47b0ade0f..1f35fe3af 100644 --- a/libc/sock/shutdown.c +++ b/libc/sock/shutdown.c @@ -21,6 +21,7 @@ #include "libc/dce.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/errfuns.h" /** diff --git a/libc/sock/sock.mk b/libc/sock/sock.mk index 4ffe02852..49205fc56 100644 --- a/libc/sock/sock.mk +++ b/libc/sock/sock.mk @@ -59,11 +59,6 @@ $(LIBC_SOCK_A).pkg: \ $(LIBC_SOCK_A_OBJS) \ $(foreach x,$(LIBC_SOCK_A_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/libc/sock/ntstdin.greg.o: \ - OVERRIDE_COPTS += \ - -ffreestanding \ - $(NO_MAGIC) - LIBC_SOCK_LIBS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x))) LIBC_SOCK_SRCS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_SRCS)) LIBC_SOCK_HDRS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/sock/socket-nt.c b/libc/sock/socket-nt.c index e919f017a..ab043b905 100644 --- a/libc/sock/socket-nt.c +++ b/libc/sock/socket-nt.c @@ -17,6 +17,8 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/mem/mem.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/iphlpapi.h" @@ -43,7 +45,8 @@ textwindows int sys_socket_nt(int family, int type, int protocol) { int64_t h; struct SockFd *sockfd; int fd, oflags, truetype; - if ((fd = __reservefd(-1)) == -1) return -1; + fd = __reservefd(-1); + if (fd == -1) return -1; truetype = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK); if ((h = WSASocket(family, truetype, protocol, NULL, 0, kNtWsaFlagOverlapped)) != -1) { @@ -61,11 +64,13 @@ textwindows int sys_socket_nt(int family, int type, int protocol) { sockfd->family = family; sockfd->type = truetype; sockfd->protocol = protocol; + _spinlock(&__fds_lock); g_fds.p[fd].kind = kFdSocket; g_fds.p[fd].flags = oflags; g_fds.p[fd].mode = 0140666; g_fds.p[fd].handle = h; g_fds.p[fd].extra = (uintptr_t)sockfd; + _spunlock(&__fds_lock); return fd; } else { __releasefd(fd); diff --git a/libc/sock/socketpair-nt.c b/libc/sock/socketpair-nt.c index fb71e728f..f490916db 100644 --- a/libc/sock/socketpair-nt.c +++ b/libc/sock/socketpair-nt.c @@ -16,6 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" +#include "libc/calls/syscall_support-nt.internal.h" +#include "libc/intrin/spinlock.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/creationdisposition.h" @@ -29,10 +33,10 @@ #include "libc/sysv/errfuns.h" textwindows int sys_socketpair_nt(int family, int type, int proto, int sv[2]) { - int64_t hpipe, h1, h2; - int reader, writer, oflags; - char16_t pipename[64]; uint32_t mode; + char16_t pipename[64]; + int64_t hpipe, h1, h2; + int rc, reader, writer, oflags; // Supports only AF_UNIX if (family != AF_UNIX) { @@ -52,9 +56,13 @@ textwindows int sys_socketpair_nt(int family, int type, int proto, int sv[2]) { } CreatePipeName(pipename); - if ((reader = __reservefd(-1)) == -1) return -1; - if ((writer = __reservefd(-1)) == -1) { - __releasefd(reader); + _spinlock(&__fds_lock); + reader = __reservefd_unlocked(-1); + writer = __reservefd_unlocked(-1); + _spunlock(&__fds_lock); + if (reader == -1 || writer == -1) { + if (reader != -1) __releasefd(reader); + if (writer != -1) __releasefd(writer); return -1; } if ((hpipe = CreateNamedPipe( @@ -67,24 +75,33 @@ textwindows int sys_socketpair_nt(int family, int type, int proto, int sv[2]) { h1 = CreateFile(pipename, kNtGenericWrite | kNtGenericRead, 0, &kNtIsInheritable, kNtOpenExisting, kNtFileFlagOverlapped, 0); - if (h1 == -1) { + + _spinlock(&__fds_lock); + + if (h1 != -1) { + + g_fds.p[reader].kind = kFdFile; + g_fds.p[reader].flags = oflags; + g_fds.p[reader].mode = 0140444; + g_fds.p[reader].handle = hpipe; + + g_fds.p[writer].kind = kFdFile; + g_fds.p[writer].flags = oflags; + g_fds.p[writer].mode = 0140222; + g_fds.p[writer].handle = h1; + + sv[0] = reader; + sv[1] = writer; + + rc = 0; + } else { CloseHandle(hpipe); - __releasefd(writer); - __releasefd(reader); - return -1; + __releasefd_unlocked(writer); + __releasefd_unlocked(reader); + rc = -1; } - g_fds.p[reader].kind = kFdFile; - g_fds.p[reader].flags = oflags; - g_fds.p[reader].mode = 0140444; - g_fds.p[reader].handle = hpipe; + _spunlock(&__fds_lock); - g_fds.p[writer].kind = kFdFile; - g_fds.p[writer].flags = oflags; - g_fds.p[writer].mode = 0140222; - g_fds.p[writer].handle = h1; - - sv[0] = reader; - sv[1] = writer; - return 0; + return rc; } diff --git a/libc/sock/sys_sendfile_freebsd.S b/libc/sock/sys_sendfile_freebsd.S new file mode 100644 index 000000000..286aa09b9 --- /dev/null +++ b/libc/sock/sys_sendfile_freebsd.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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + +sys_sendfile_freebsd: + jmp sys_sendfile + .endfn sys_sendfile_freebsd,globl diff --git a/libc/sock/sys_sendfile_xnu.S b/libc/sock/sys_sendfile_xnu.S new file mode 100644 index 000000000..ea1fa7400 --- /dev/null +++ b/libc/sock/sys_sendfile_xnu.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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.internal.h" + +sys_sendfile_xnu: + jmp sys_sendfile + .endfn sys_sendfile_xnu,globl diff --git a/libc/sock/syscall_fd.internal.h b/libc/sock/syscall_fd.internal.h new file mode 100644 index 000000000..6b5db464e --- /dev/null +++ b/libc/sock/syscall_fd.internal.h @@ -0,0 +1,24 @@ +#ifndef COSMOPOLITAN_LIBC_SOCK_SYSCALL_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_SOCK_SYSCALL_INTERNAL_H_ +#include "libc/calls/internal.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +int sys_accept_nt(struct Fd *, void *, uint32_t *, int) hidden; +int sys_bind_nt(struct Fd *, const void *, uint32_t); +int sys_closesocket_nt(struct Fd *) hidden; +int sys_connect_nt(struct Fd *, const void *, uint32_t) hidden; +int sys_getpeername_nt(struct Fd *, void *, uint32_t *) hidden; +int sys_getsockname_nt(struct Fd *, void *, uint32_t *) hidden; +int sys_getsockopt_nt(struct Fd *, int, int, void *, uint32_t *) hidden; +int sys_listen_nt(struct Fd *, int) hidden; +int sys_setsockopt_nt(struct Fd *, int, int, const void *, uint32_t) hidden; +int sys_shutdown_nt(struct Fd *, int) hidden; +ssize_t sys_recv_nt(struct Fd *, const struct iovec *, size_t, uint32_t) hidden; + +ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t, + void *, uint32_t *) hidden; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_SOCK_SYSCALL_INTERNAL_H_ */ diff --git a/libc/sock/wsablock.c b/libc/sock/wsablock.c index 16883b76d..d7ac994b3 100644 --- a/libc/sock/wsablock.c +++ b/libc/sock/wsablock.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" #include "libc/calls/sig.internal.h" #include "libc/calls/strace.internal.h" #include "libc/nt/enum/wait.h" diff --git a/libc/stdio/dirstream.c b/libc/stdio/dirstream.c index be831b5c8..364c0bf08 100644 --- a/libc/stdio/dirstream.c +++ b/libc/stdio/dirstream.c @@ -23,6 +23,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/dirent.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/kprintf.h" diff --git a/libc/stdio/fclose.c b/libc/stdio/fclose.c index 94b5aebe6..ebb7b6e65 100644 --- a/libc/stdio/fclose.c +++ b/libc/stdio/fclose.c @@ -19,7 +19,6 @@ #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/errno.h" -#include "libc/intrin/spinlock.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/stdio/internal.h" @@ -40,6 +39,7 @@ int fclose(FILE *f) { if (!f) return 0; __fflush_unregister(f); fflush(f); + free_s(&f->getln); if (!f->nofree) { free_s(&f->buf); } diff --git a/libc/stdio/fflush.c b/libc/stdio/fflush.c index 28f9f18e6..5618a8ae4 100644 --- a/libc/stdio/fflush.c +++ b/libc/stdio/fflush.c @@ -1,7 +1,7 @@ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ @@ -16,83 +16,19 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/alg/arraylist.internal.h" -#include "libc/bits/bits.h" -#include "libc/bits/pushpop.h" -#include "libc/calls/calls.h" -#include "libc/errno.h" -#include "libc/intrin/spinlock.h" -#include "libc/macros.internal.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" -#include "libc/stdio/fflush.internal.h" -#include "libc/stdio/internal.h" #include "libc/stdio/stdio.h" -#include "libc/sysv/consts/o.h" /** * Blocks until data from stream buffer is written out. * - * @param f is the stream handle + * @param f is the stream handle, or 0 for all streams * @return is 0 on success or -1 on error + * @threadsafe */ -int fflush_unlocked(FILE *f) { - int rc = 0; - size_t i; - if (!f) { - _spinlock(&__fflush.lock); - for (i = __fflush.handles.i; i; --i) { - if ((f = __fflush.handles.p[i - 1])) { - if (fflush(f) == -1) { - rc = -1; - } - } - } - _spunlock(&__fflush.lock); - } else if (f->fd != -1) { - if (__fflush_impl(f) == -1) { - rc = -1; - } - } else if (f->beg && f->beg < f->size) { - f->buf[f->beg] = 0; - } - return rc; -} - -textstartup int __fflush_register(FILE *f) { +int fflush(FILE *f) { int rc; - size_t i; - struct StdioFlush *sf; - _spinlock(&__fflush.lock); - sf = &__fflush; - if (!sf->handles.p) { - sf->handles.p = sf->handles_initmem; - pushmov(&sf->handles.n, ARRAYLEN(sf->handles_initmem)); - __cxa_atexit(fflush_unlocked, 0, 0); - } - for (i = sf->handles.i; i; --i) { - if (!sf->handles.p[i - 1]) { - sf->handles.p[i - 1] = f; - _spunlock(&__fflush.lock); - return 0; - } - } - rc = append(&sf->handles, &f); - _spunlock(&__fflush.lock); + if (f) flockfile(f); + rc = fflush_unlocked(f); + if (f) funlockfile(f); return rc; } - -void __fflush_unregister(FILE *f) { - size_t i; - struct StdioFlush *sf; - _spinlock(&__fflush.lock); - sf = &__fflush; - sf = pushpop(sf); - for (i = sf->handles.i; i; --i) { - if (sf->handles.p[i - 1] == f) { - pushmov(&sf->handles.p[i - 1], 0); - break; - } - } - _spunlock(&__fflush.lock); -} diff --git a/libc/stdio/fflush.internal.h b/libc/stdio/fflush.internal.h index 1dd682498..39fbe5e25 100644 --- a/libc/stdio/fflush.internal.h +++ b/libc/stdio/fflush.internal.h @@ -10,7 +10,7 @@ struct StdioFlushHandles { }; struct StdioFlush { - char lock; + int lock; struct StdioFlushHandles handles; FILE *handles_initmem[8]; }; diff --git a/libc/stdio/fflush_unlocked.c b/libc/stdio/fflush_unlocked.c new file mode 100644 index 000000000..b9411a5bc --- /dev/null +++ b/libc/stdio/fflush_unlocked.c @@ -0,0 +1,98 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/alg/arraylist.internal.h" +#include "libc/bits/bits.h" +#include "libc/bits/pushpop.h" +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/intrin/spinlock.h" +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/fflush.internal.h" +#include "libc/stdio/internal.h" +#include "libc/stdio/stdio.h" +#include "libc/sysv/consts/o.h" + +/** + * Blocks until data from stream buffer is written out. + * + * @param f is the stream handle, or 0 for all streams + * @return is 0 on success or -1 on error + */ +int fflush_unlocked(FILE *f) { + int rc = 0; + size_t i; + if (!f) { + _spinlock(&__fflush.lock); + for (i = __fflush.handles.i; i; --i) { + if ((f = __fflush.handles.p[i - 1])) { + if (fflush(f) == -1) { + rc = -1; + } + } + } + _spunlock(&__fflush.lock); + } else if (f->fd != -1) { + if (__fflush_impl(f) == -1) { + rc = -1; + } + } else if (f->beg && f->beg < f->size) { + f->buf[f->beg] = 0; + } + return rc; +} + +textstartup int __fflush_register(FILE *f) { + int rc; + size_t i; + struct StdioFlush *sf; + _spinlock(&__fflush.lock); + sf = &__fflush; + if (!sf->handles.p) { + sf->handles.p = sf->handles_initmem; + pushmov(&sf->handles.n, ARRAYLEN(sf->handles_initmem)); + __cxa_atexit(fflush_unlocked, 0, 0); + } + for (i = sf->handles.i; i; --i) { + if (!sf->handles.p[i - 1]) { + sf->handles.p[i - 1] = f; + _spunlock(&__fflush.lock); + return 0; + } + } + rc = append(&sf->handles, &f); + _spunlock(&__fflush.lock); + return rc; +} + +void __fflush_unregister(FILE *f) { + size_t i; + struct StdioFlush *sf; + _spinlock(&__fflush.lock); + sf = &__fflush; + sf = pushpop(sf); + for (i = sf->handles.i; i; --i) { + if (sf->handles.p[i - 1] == f) { + pushmov(&sf->handles.p[i - 1], 0); + break; + } + } + _spunlock(&__fflush.lock); +} diff --git a/libc/stdio/fflushimpl.c b/libc/stdio/fflushimpl.c index 9d6ecea49..8805b9a76 100644 --- a/libc/stdio/fflushimpl.c +++ b/libc/stdio/fflushimpl.c @@ -18,12 +18,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/errno.h" +#include "libc/runtime/runtime.h" #include "libc/stdio/internal.h" #include "libc/sysv/consts/o.h" int __fflush_impl(FILE *f) { size_t i; ssize_t rc; + free_s(&f->getln); if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) { for (i = 0; i < f->beg; i += rc) { if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) { diff --git a/libc/stdio/fgetln.c b/libc/stdio/fgetln.c index 6749197e3..94c5643c9 100644 --- a/libc/stdio/fgetln.c +++ b/libc/stdio/fgetln.c @@ -18,13 +18,35 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/stdio.h" +/** + * Retrieves line from stream, e.g. + * + * char *line; + * while ((line = _chomp(fgetln(stdin, 0)))) { + * printf("%s\n", line); + * } + * + * The returned memory is owned by the stream. It'll be reused when + * fgetln() is called again. It's free()'d upon fclose() / fflush() + * + * @param stream specifies non-null open input stream + * @param len optionally receives byte length of line + * @return nul-terminated line string, including the `\n` character + * unless a line happened before EOF without `\n`, otherwise it + * returns `NULL` and feof() and ferror() can examine the state + * @see getdelim() + */ char *fgetln(FILE *stream, size_t *len) { + char *res; ssize_t rc; size_t n = 0; - if ((rc = getdelim(&stream->getln, &n, '\n', stream)) > 0) { - *len = rc; - return stream->getln; + flockfile(stream); + if ((rc = getdelim_unlocked(&stream->getln, &n, '\n', stream)) > 0) { + if (len) *len = rc; + res = stream->getln; } else { - return 0; + res = 0; } + funlockfile(stream); + return res; } diff --git a/libc/stdio/flockfile.c b/libc/stdio/flockfile.c index 5ffe0c691..7a575904b 100644 --- a/libc/stdio/flockfile.c +++ b/libc/stdio/flockfile.c @@ -16,12 +16,30 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/spinlock.h" +#include "libc/calls/calls.h" +#include "libc/intrin/cmpxchg.h" +#include "libc/intrin/lockcmpxchgp.h" +#include "libc/nexgen32e/threaded.h" #include "libc/stdio/stdio.h" /** - * Acquires lock on stdio object, blocking if needed. + * Acquires reentrant lock on stdio object, blocking if needed. */ void flockfile(FILE *f) { - _spinlock(&f->lock); + int me, owner; + unsigned tries; + if (__threaded) { + for (tries = 0, me = gettid();;) { + owner = 0; + if (_lockcmpxchgp(&f->lock, &owner, me) || owner == me) { + break; + } + if (++tries & 7) { + __builtin_ia32_pause(); + } else { + sched_yield(); + } + } + } + ++f->reent; } diff --git a/libc/stdio/flushlbf.c b/libc/stdio/flushlbf.c index bacc56caa..e4b40a07a 100644 --- a/libc/stdio/flushlbf.c +++ b/libc/stdio/flushlbf.c @@ -31,11 +31,11 @@ void _flushlbf(void) { _spinlock(&__fflush.lock); for (i = 0; i < __fflush.handles.i; ++i) { if ((f = __fflush.handles.p[i])) { - _spinlock(&f->lock); + flockfile(f); if (f->bufmode == _IOLBF) { fflush_unlocked(f); } - _spunlock(&f->lock); + funlockfile(f); } } _spunlock(&__fflush.lock); diff --git a/libc/stdio/fprintf.c b/libc/stdio/fprintf.c index 10223fb6c..939a6cd69 100644 --- a/libc/stdio/fprintf.c +++ b/libc/stdio/fprintf.c @@ -18,11 +18,17 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/stdio.h" +/** + * Formats and writes text to stream. + * @see printf() for further documentation + */ int(fprintf)(FILE *f, const char *fmt, ...) { int rc; va_list va; + flockfile(f); va_start(va, fmt); - rc = (vfprintf)(f, fmt, va); + rc = (vfprintf_unlocked)(f, fmt, va); va_end(va); + funlockfile(f); return rc; } diff --git a/libc/calls/sched_yield.c b/libc/stdio/fprintf_unlocked.c similarity index 85% rename from libc/calls/sched_yield.c rename to libc/stdio/fprintf_unlocked.c index 04b744961..f6267dab2 100644 --- a/libc/calls/sched_yield.c +++ b/libc/stdio/fprintf_unlocked.c @@ -16,18 +16,17 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" -#include "libc/calls/internal.h" -#include "libc/dce.h" +#include "libc/stdio/stdio.h" /** - * Asks kernel to deschedule thread momentarily. + * Formats and writes text to stream. + * @see printf() for further documentation */ -int sched_yield(void) { - /* TODO(jart): Add get_sched_yield() so we can STRACE() */ - if (!IsWindows()) { - return sys_sched_yield(); - } else { - return sys_sched_yield_nt(); - } +int(fprintf_unlocked)(FILE *f, const char *fmt, ...) { + int rc; + va_list va; + va_start(va, fmt); + rc = (vfprintf_unlocked)(f, fmt, va); + va_end(va); + return rc; } diff --git a/libc/stdio/fputc.c b/libc/stdio/fputc.c index 9b432718d..8aa5e1494 100644 --- a/libc/stdio/fputc.c +++ b/libc/stdio/fputc.c @@ -29,7 +29,7 @@ int fputc_unlocked(int c, FILE *f) { unsigned char b; if (c != '\n' && f->beg < f->size && f->bufmode != _IONBF) { f->buf[f->beg++] = c; - return c & 0xff; + return c & 255; } else { b = c; if (!fwrite_unlocked(&b, 1, 1, f)) return -1; diff --git a/libc/stdio/freopen.c b/libc/stdio/freopen.c index 4d5a4218c..1099e79b8 100644 --- a/libc/stdio/freopen.c +++ b/libc/stdio/freopen.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/intrin/spinlock.h" #include "libc/stdio/stdio.h" #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/fd.h" @@ -41,7 +40,7 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) { FILE *res; unsigned flags; flags = fopenflags(mode); - _spinlock(&stream->lock); + flockfile(stream); fflush_unlocked(stream); if (pathname) { /* open new stream, overwriting existing alloc */ @@ -60,6 +59,6 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) { fcntl(stream->fd, F_SETFL, flags & ~O_CLOEXEC); res = stream; } - _spunlock(&stream->lock); + funlockfile(stream); return res; } diff --git a/libc/stdio/fseeko.c b/libc/stdio/fseeko.c index 2248dffae..0a7c08bdb 100644 --- a/libc/stdio/fseeko.c +++ b/libc/stdio/fseeko.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/errno.h" -#include "libc/intrin/spinlock.h" #include "libc/stdio/internal.h" #include "libc/stdio/stdio.h" #include "libc/sysv/consts/o.h" @@ -36,11 +35,10 @@ * @param whence can be SEET_SET, SEEK_CUR, or SEEK_END * @returns 0 on success or -1 on error */ -int fseeko(FILE *f, int64_t offset, int whence) { +int fseeko_unlocked(FILE *f, int64_t offset, int whence) { int res; ssize_t rc; int64_t pos; - _spinlock(&f->lock); if (f->fd != -1) { if (__fflush_impl(f) == -1) return -1; if (whence == SEEK_CUR && f->beg < f->end) { @@ -77,6 +75,5 @@ int fseeko(FILE *f, int64_t offset, int whence) { res = -1; } } - _spunlock(&f->lock); return res; } diff --git a/libc/stdio/ftello.c b/libc/stdio/ftello.c index d3b88c846..9e5f97b48 100644 --- a/libc/stdio/ftello.c +++ b/libc/stdio/ftello.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/errno.h" -#include "libc/intrin/spinlock.h" #include "libc/runtime/runtime.h" #include "libc/stdio/internal.h" #include "libc/stdio/stdio.h" @@ -49,8 +48,8 @@ static int64_t ftello_unlocked(FILE *f) { */ int64_t ftello(FILE *f) { int64_t rc; - _spinlock(&f->lock); + flockfile(f); rc = ftello_unlocked(f); - _spunlock(&f->lock); + funlockfile(f); return rc; } diff --git a/libc/stdio/ftrylockfile.c b/libc/stdio/ftrylockfile.c index 97d21da2f..eeed1e490 100644 --- a/libc/stdio/ftrylockfile.c +++ b/libc/stdio/ftrylockfile.c @@ -16,13 +16,26 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/spinlock.h" +#include "libc/calls/calls.h" +#include "libc/intrin/lockcmpxchgp.h" +#include "libc/nexgen32e/threaded.h" #include "libc/stdio/stdio.h" /** - * Tries to acquire stdio object lock. - * @return 0 for success or non-zero if someone else has the lock + * Tries to acquire reentrant stdio object lock. + * + * @return 0 on success, or non-zero if another thread owns the lock */ int ftrylockfile(FILE *f) { - return _trylock(&f->lock); + int me, owner = 0; + if (__threaded) { + me = gettid(); + if (!_lockcmpxchgp(&f->lock, &owner, me) && owner == me) { + owner = 0; + } + } + if (!owner) { + ++f->reent; + } + return owner; } diff --git a/libc/stdio/funlockfile.c b/libc/stdio/funlockfile.c index 46d68d0fd..0e1601a1c 100644 --- a/libc/stdio/funlockfile.c +++ b/libc/stdio/funlockfile.c @@ -16,12 +16,24 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/spinlock.h" +#include "libc/assert.h" +#include "libc/calls/calls.h" +#include "libc/nexgen32e/threaded.h" #include "libc/stdio/stdio.h" /** * Releases lock on stdio object. */ void funlockfile(FILE *f) { - _spunlock(&f->lock); + int owner; + bool shouldunlock; + assert(f->reent > 0); + shouldunlock = --f->reent <= 0; + if (__threaded) { + assert(f->lock == gettid()); + if (shouldunlock) { + owner = 0; + __atomic_store(&f->lock, &owner, __ATOMIC_RELAXED); + } + } } diff --git a/libc/stdio/getdelim.c b/libc/stdio/getdelim.c index ae2a91f95..1bfffabfb 100644 --- a/libc/stdio/getdelim.c +++ b/libc/stdio/getdelim.c @@ -16,65 +16,18 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/calls/calls.h" -#include "libc/errno.h" -#include "libc/intrin/spinlock.h" -#include "libc/macros.internal.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/o.h" - -static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) { - char *p; - ssize_t rc; - size_t i, m; - if ((f->iomode & O_ACCMODE) == O_WRONLY) { - f->state = errno = EBADF; - return -1; - } - if (f->beg > f->end) { - f->state = errno = EINVAL; - return -1; - } - if (!*s) *n = 0; - for (i = 0;; i += m) { - m = f->end - f->beg; - if ((p = memchr(f->buf + f->beg, delim, m))) m = p + 1 - (f->buf + f->beg); - if (i + m + 1 > *n) { - *n = i + m + 1; - *s = realloc(*s, *n); - if (!*s) { - abort(); - } - } - memcpy(*s + i, f->buf + f->beg, m); - (*s)[i + m] = '\0'; - if ((f->beg += m) == f->end) f->beg = f->end = 0; - if (p) { - return i + m; - } else if (f->fd == -1) { - break; - } else if ((rc = read(f->fd, f->buf, f->size)) != -1) { - if (!rc) break; - f->end = rc; - } else if (errno != EINTR) { - f->state = errno; - return -1; - } - } - f->state = -1; - if (i + m) { - return i + m; - } else { - return -1; - } -} /** - * Reads string from stream. + * Reads string from stream, e.g. + * + * char *line = NULL; + * size_t linesize = 0; + * while (getdelim(&line, &linesize, '\n', stdin) > 0) { + * _chomp(line); + * printf("%s\n", line); + * } + * free(line); * * @param s is the caller's buffer (in/out) which is extended or * allocated automatically, also NUL-terminated is guaranteed @@ -82,13 +35,14 @@ static ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) { * @param delim is the stop char (and NUL is implicitly too) * @return number of bytes read >0, including delim, excluding NUL, * or -1 w/ errno on EOF or error; see ferror() and feof() - * @note this function can't punt EINTR to caller - * @see getline(), _chomp(), gettok_r() + * @note this function will ignore EINTR if it occurs mid-line + * @raises EBADF if stream isn't open for reading + * @see fgetln(), getline(), _chomp(), gettok_r() */ ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) { ssize_t rc; - _spinlock(&f->lock); + flockfile(f); rc = getdelim_unlocked(s, n, delim, f); - _spunlock(&f->lock); + funlockfile(f); return rc; } diff --git a/libc/stdio/getdelim_unlocked.c b/libc/stdio/getdelim_unlocked.c new file mode 100644 index 000000000..3314c4379 --- /dev/null +++ b/libc/stdio/getdelim_unlocked.c @@ -0,0 +1,81 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" + +/** + * Reads string from unlocked stream. + * @see getdelim() for documentation + */ +ssize_t getdelim_unlocked(char **s, size_t *n, int delim, FILE *f) { + ssize_t rc; + char *p, *s2; + size_t i, m, n2; + if ((f->iomode & O_ACCMODE) == O_WRONLY) { + f->state = errno = EBADF; + return -1; + } + if (f->beg > f->end) { + f->state = errno = EINVAL; + return -1; + } + if (!*s) *n = 0; + for (i = 0;; i += m) { + m = f->end - f->beg; + if ((p = memchr(f->buf + f->beg, delim, m))) { + m = p + 1 - (f->buf + f->beg); + } + if (i + m + 1 > *n) { + n2 = i + m + 1; + s2 = realloc(*s, n2); + if (s2) { + *s = s2; + *n = n2; + } else { + f->state = errno; + return -1; + } + } + memcpy(*s + i, f->buf + f->beg, m); + (*s)[i + m] = '\0'; + if ((f->beg += m) == f->end) { + f->beg = f->end = 0; + } + if (p) { + return i + m; + } else if (f->fd == -1) { + break; + } else if ((rc = read(f->fd, f->buf, f->size)) != -1) { + if (!rc) break; + f->end = rc; + } else if (errno != EINTR) { + f->state = errno; + return -1; + } + } + f->state = -1; + if (i + m) { + return i + m; + } else { + return -1; + } +} diff --git a/libc/stdio/getline.c b/libc/stdio/getline.c index 6f0fd43b8..88f17836e 100644 --- a/libc/stdio/getline.c +++ b/libc/stdio/getline.c @@ -19,7 +19,15 @@ #include "libc/stdio/stdio.h" /** - * Reads line from stream. + * Reads line from stream, e.g. + * + * char *line = NULL; + * size_t linesize = 0; + * while (getline(&line, &linesize, stdin) > 0) { + * _chomp(line); + * printf("%s\n", line); + * } + * free(line); * * This function delegates to getdelim(), which provides further * documentation. Concerning lines, please note the \n or \r\n are @@ -30,7 +38,7 @@ * NUL-termination is guaranteed FTMP * @return number of bytes read, including delim, excluding NUL, or -1 * w/ errno on EOF or error; see ferror() and feof() - * @see xgetline(), getdelim(), gettok_r() + * @see fgetln(), xgetline(), getdelim(), gettok_r() */ ssize_t getline(char **line, size_t *n, FILE *f) { return getdelim(line, n, '\n', f); diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index 5dcffa13a..bfd4acf3a 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -19,7 +19,7 @@ #include "libc/stdio/stdio.h" /** - * Formats and writes string to stdout. + * Formats and writes text to stdout. * * Cosmopolitan supports most of the standard formatting behaviors * described by `man 3 printf`, in addition to the following diff --git a/libc/stdio/puts.c b/libc/stdio/puts.c index 044420e20..fcd0280a2 100644 --- a/libc/stdio/puts.c +++ b/libc/stdio/puts.c @@ -18,21 +18,32 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/stdio.h" -/** - * Writes string w/ trailing newline to stdout. - */ -int puts(const char *s) { - FILE *f; +static int PutsImpl(const char *s, FILE *f) { size_t n, r; - f = stdout; if ((n = strlen(s))) { - r = fwrite(s, 1, n, f); + r = fwrite_unlocked(s, 1, n, f); if (!r) return -1; if (r < n) return r; } - if (fputc('\n', f) == -1) { - if (feof(f)) return n; + if (fputc_unlocked('\n', f) == -1) { + if (feof_unlocked(f)) return n; return -1; } return n + 1; } + +/** + * Writes string w/ trailing newline to stdout. + * + * @return non-negative number on success, or `EOF` on error with + * `errno` set and the `ferror(stdout)` state is updated + */ +int puts(const char *s) { + FILE *f; + int bytes; + f = stdout; + flockfile(f); + bytes = PutsImpl(s, f); + funlockfile(f); + return bytes; +} diff --git a/libc/stdio/rewind.c b/libc/stdio/rewind.c index 03aa3f5c4..8f655d960 100644 --- a/libc/stdio/rewind.c +++ b/libc/stdio/rewind.c @@ -26,6 +26,9 @@ * EOF state, without reopening it. */ void rewind(FILE *f) { - fseek(f, 0, SEEK_SET); - f->state = 0; + flockfile(f); + if (!fseeko_unlocked(f, 0, SEEK_SET)) { + f->state = 0; + } + funlockfile(f); } diff --git a/libc/stdio/setvbuf.c b/libc/stdio/setvbuf.c index 8cba7b9d4..d6ba56932 100644 --- a/libc/stdio/setvbuf.c +++ b/libc/stdio/setvbuf.c @@ -30,6 +30,7 @@ * @return 0 on success or -1 on error */ int setvbuf(FILE *f, char *buf, int mode, size_t size) { + flockfile(f); if (buf) { if (!size) size = BUFSIZ; if (!f->nofree && f->buf != buf) free_s(&f->buf); @@ -38,5 +39,6 @@ int setvbuf(FILE *f, char *buf, int mode, size_t size) { f->nofree = true; } f->bufmode = mode; + funlockfile(f); return 0; } diff --git a/libc/stdio/stdio.h b/libc/stdio/stdio.h index 6c0914db8..f39c53b41 100644 --- a/libc/stdio/stdio.h +++ b/libc/stdio/stdio.h @@ -24,8 +24,9 @@ typedef struct FILE { uint32_t size; /* 0x20 */ uint32_t nofree; /* 0x24 */ int pid; /* 0x28 */ - char lock; /* 0x2c */ - char *getln; /* 0x30 */ + int lock; /* 0x2c */ + int reent; /* 0x30 */ + char *getln; /* 0x38 */ } FILE; extern FILE *stdin; @@ -39,6 +40,7 @@ int getc(FILE *) paramsnonnull(); int putc(int, FILE *) paramsnonnull(); int fflush(FILE *); int fgetc(FILE *) paramsnonnull(); +char *fgetln(FILE *, size_t *) paramsnonnull((1)); int ungetc(int, FILE *) paramsnonnull(); int fileno(FILE *) paramsnonnull() nosideeffect; int fputc(int, FILE *) paramsnonnull(); @@ -116,37 +118,13 @@ int wprintf(const wchar_t *, ...); int wscanf(const wchar_t *, ...); int fwide(FILE *, int); -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § standard i/o » optimizations ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -#define getc(f) fgetc(f) -#define getwc(f) fgetwc(f) -#define putc(c, f) fputc(c, f) -#define putwc(c, f) fputwc(c, f) - -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__) -#define vprintf(FMT, VA) (vprintf)(PFLINK(FMT), VA) -#define fprintf(F, FMT, ...) (fprintf)(F, PFLINK(FMT), ##__VA_ARGS__) -#define vfprintf(F, FMT, VA) (vfprintf)(F, PFLINK(FMT), VA) -#define vscanf(FMT, VA) (vscanf)(SFLINK(FMT), VA) -#define scanf(FMT, ...) (scanf)(SFLINK(FMT), ##__VA_ARGS__) -#define fscanf(F, FMT, ...) (fscanf)(F, SFLINK(FMT), ##__VA_ARGS__) -#define vfscanf(F, FMT, VA) (vfscanf)(F, SFLINK(FMT), VA) -#endif - -#define stdin SYMBOLIC(stdin) -#define stdout SYMBOLIC(stdout) -#define stderr SYMBOLIC(stderr) - /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § standard i/o » without mutexes ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -void flockfile(FILE *); -void funlockfile(FILE *); -int ftrylockfile(FILE *); +void flockfile(FILE *) paramsnonnull(); +void funlockfile(FILE *) paramsnonnull(); +int ftrylockfile(FILE *) paramsnonnull(); int getc_unlocked(FILE *) paramsnonnull(); int getchar_unlocked(void); int putc_unlocked(int, FILE *) paramsnonnull(); @@ -172,12 +150,46 @@ wchar_t *fgetws_unlocked(wchar_t *, int, FILE *); int fputws_unlocked(const wchar_t *, FILE *); wint_t ungetwc_unlocked(wint_t, FILE *) paramsnonnull(); int ungetc_unlocked(int, FILE *) paramsnonnull(); +int fseeko_unlocked(FILE *, int64_t, int) paramsnonnull(); +ssize_t getdelim_unlocked(char **, size_t *, int, FILE *) paramsnonnull(); +int fprintf_unlocked(FILE *, const char *, ...) printfesque(2) + paramsnonnull((1, 2)) dontthrow nocallback; +int vfprintf_unlocked(FILE *, const char *, va_list) + paramsnonnull() dontthrow nocallback; #define getc_unlocked(f) fgetc_unlocked(f) #define getwc_unlocked(f) fgetwc_unlocked(f) #define putc_unlocked(c, f) fputc_unlocked(c, f) #define putwc_unlocked(c, f) fputwc_unlocked(c, f) +/*───────────────────────────────────────────────────────────────────────────│─╗ +│ cosmopolitan § standard i/o » optimizations ─╬─│┼ +╚────────────────────────────────────────────────────────────────────────────│*/ + +#define getc(f) fgetc(f) +#define getwc(f) fgetwc(f) +#define putc(c, f) fputc(c, f) +#define putwc(c, f) fputwc(c, f) + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +/* clang-format off */ +#define printf(FMT, ...) (printf)(PFLINK(FMT), ##__VA_ARGS__) +#define vprintf(FMT, VA) (vprintf)(PFLINK(FMT), VA) +#define fprintf(F, FMT, ...) (fprintf)(F, PFLINK(FMT), ##__VA_ARGS__) +#define vfprintf(F, FMT, VA) (vfprintf)(F, PFLINK(FMT), VA) +#define fprintf_unlocked(F, FMT, ...) (fprintf_unlocked)(F, PFLINK(FMT), ##__VA_ARGS__) +#define vfprintf_unlocked(F, FMT, VA) (vfprintf_unlocked)(F, PFLINK(FMT), VA) +#define vscanf(FMT, VA) (vscanf)(SFLINK(FMT), VA) +#define scanf(FMT, ...) (scanf)(SFLINK(FMT), ##__VA_ARGS__) +#define fscanf(F, FMT, ...) (fscanf)(F, SFLINK(FMT), ##__VA_ARGS__) +#define vfscanf(F, FMT, VA) (vfscanf)(F, SFLINK(FMT), VA) +/* clang-format on */ +#endif + +#define stdin SYMBOLIC(stdin) +#define stdout SYMBOLIC(stdout) +#define stderr SYMBOLIC(stderr) + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_STDIO_STDIO_H_ */ diff --git a/libc/stdio/unlocked/clearerr_unlocked.S b/libc/stdio/unlocked/clearerr_unlocked.S index b62225c26..8f8c7e9f4 100644 --- a/libc/stdio/unlocked/clearerr_unlocked.S +++ b/libc/stdio/unlocked/clearerr_unlocked.S @@ -22,6 +22,7 @@ // // @param rdi has stream pointer // @see clearerr_unlocked() +// @threadsafe clearerr: mov %rdi,%r11 ezlea clearerr_unlocked,ax diff --git a/libc/stdio/unlocked/feof_unlocked.S b/libc/stdio/unlocked/feof_unlocked.S index a498c5359..d60b6bfad 100644 --- a/libc/stdio/unlocked/feof_unlocked.S +++ b/libc/stdio/unlocked/feof_unlocked.S @@ -23,6 +23,7 @@ // @param rdi has file stream object pointer // @note EOF doesn't count // @see feof_unlocked() +// @threadsafe feof: mov %rdi,%r11 ezlea feof_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/ferror_unlocked.S b/libc/stdio/unlocked/ferror_unlocked.S index 3c5fb28f4..9db9ce695 100644 --- a/libc/stdio/unlocked/ferror_unlocked.S +++ b/libc/stdio/unlocked/ferror_unlocked.S @@ -23,6 +23,7 @@ // @param rdi has file stream object pointer // @note EOF doesn't count // @see ferror_unlocked() +// @threadsafe ferror: mov %rdi,%r11 ezlea ferror_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fgetc_unlocked.S b/libc/stdio/unlocked/fgetc_unlocked.S index 59f250529..ec857991c 100644 --- a/libc/stdio/unlocked/fgetc_unlocked.S +++ b/libc/stdio/unlocked/fgetc_unlocked.S @@ -23,6 +23,7 @@ // @param rdi has stream object pointer // @return byte in range 0..255, or -1 w/ errno // @see fgetc_unlocked() +// @threadsafe fgetc: mov %rdi,%r11 ezlea fgetc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fgets_unlocked.S b/libc/stdio/unlocked/fgets_unlocked.S index 8b155e990..4f2116ec9 100644 --- a/libc/stdio/unlocked/fgets_unlocked.S +++ b/libc/stdio/unlocked/fgets_unlocked.S @@ -30,6 +30,7 @@ // @return rax has rdi on success, NULL on error or // NULL if EOF happens with zero chars read // @see fgets_unlocked() +// @threadsafe fgets: mov %rdx,%r11 ezlea fgets_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fgetwc_unlocked.S b/libc/stdio/unlocked/fgetwc_unlocked.S index 667a67756..ec28e1370 100644 --- a/libc/stdio/unlocked/fgetwc_unlocked.S +++ b/libc/stdio/unlocked/fgetwc_unlocked.S @@ -23,6 +23,7 @@ // @param rdi has stream object pointer // @return wide character or -1 on EOF or error // @see fgetwc_unlocked() +// @threadsafe fgetwc: mov %rdi,%r11 ezlea fgetwc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fgetws_unlocked.S b/libc/stdio/unlocked/fgetws_unlocked.S index 1057725c0..f20844603 100644 --- a/libc/stdio/unlocked/fgetws_unlocked.S +++ b/libc/stdio/unlocked/fgetws_unlocked.S @@ -28,6 +28,7 @@ // @param rsi is size of rdi buffer // @param rsi is file stream object pointer // @see fgetws_unlocked() +// @threadsafe fgetws: mov %rdx,%r11 ezlea fgetws_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fileno_unlocked.S b/libc/stdio/unlocked/fileno_unlocked.S index d8804a18e..c67f09214 100644 --- a/libc/stdio/unlocked/fileno_unlocked.S +++ b/libc/stdio/unlocked/fileno_unlocked.S @@ -22,6 +22,7 @@ // // @param rdi has file stream object pointer // @see fileno_unlocked() +// @threadsafe fileno: mov %rdi,%r11 ezlea fileno_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fputc_unlocked.S b/libc/stdio/unlocked/fputc_unlocked.S index a51feb9bc..ca0db43bf 100644 --- a/libc/stdio/unlocked/fputc_unlocked.S +++ b/libc/stdio/unlocked/fputc_unlocked.S @@ -24,6 +24,7 @@ // @param rsi has stream object pointer // @return c as unsigned char if written or -1 w/ errno // @see fputc_unlocked() +// @threadsafe fputc: mov %rsi,%r11 ezlea fputc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fputs_unlocked.S b/libc/stdio/unlocked/fputs_unlocked.S index 1a2cdfa2a..c5e24f7dd 100644 --- a/libc/stdio/unlocked/fputs_unlocked.S +++ b/libc/stdio/unlocked/fputs_unlocked.S @@ -28,6 +28,7 @@ // @param rsi is file object stream pointer // @return strlen(rdi) on success or -1 w/ errno // @see fputs_unlocked() +// @threadsafe fputs: mov %rsi,%r11 ezlea fputs_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fputwc_unlocked.S b/libc/stdio/unlocked/fputwc_unlocked.S index 0c140da48..ee134b8f2 100644 --- a/libc/stdio/unlocked/fputwc_unlocked.S +++ b/libc/stdio/unlocked/fputwc_unlocked.S @@ -24,6 +24,7 @@ // @param rsi has file object stream pointer // @return rax is wide character if written or -1 w/ errno // @see fputwc_unlocked() +// @threadsafe fputwc: mov %rsi,%r11 ezlea fputwc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fputws_unlocked.S b/libc/stdio/unlocked/fputws_unlocked.S index 3258d4a7f..ca80d9bde 100644 --- a/libc/stdio/unlocked/fputws_unlocked.S +++ b/libc/stdio/unlocked/fputws_unlocked.S @@ -28,6 +28,7 @@ // @param rsi is file object stream pointer // @return strlen(rdi) on success or -1 w/ errno // @see fputws_unlocked() +// @threadsafe fputws: mov %rsi,%r11 ezlea fputws_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/fread_unlocked.S b/libc/stdio/unlocked/fread_unlocked.S index e8084b9b8..4b62cb410 100644 --- a/libc/stdio/unlocked/fread_unlocked.S +++ b/libc/stdio/unlocked/fread_unlocked.S @@ -26,6 +26,7 @@ // @param rcx has file object stream pointer // @return count on success, [0,count) on EOF, 0 on error or count==0 // @see fread_unlocked() +// @threadsafe fread: mov %rcx,%r11 ezlea fread_unlocked,ax jmp stdio_unlock diff --git a/libc/calls/sched_yield-nt.c b/libc/stdio/unlocked/fseeko_unlocked.S similarity index 67% rename from libc/calls/sched_yield-nt.c rename to libc/stdio/unlocked/fseeko_unlocked.S index fc6fbb0fb..dc182fed7 100644 --- a/libc/calls/sched_yield-nt.c +++ b/libc/stdio/unlocked/fseeko_unlocked.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 │ │ │ @@ -16,19 +16,22 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" -#include "libc/nt/enum/status.h" -#include "libc/nt/ntdll.h" -#include "libc/nt/synchronization.h" +#include "libc/macros.internal.h" -textwindows int sys_sched_yield_nt(void) { - // A value of zero, together with the bAlertable parameter set to - // FALSE, causes the thread to relinquish the remainder of its time - // slice to any other thread that is ready to run, if there are no - // pending user APCs on the calling thread. If there are no other - // threads ready to run and no user APCs are queued, the function - // returns immediately, and the thread continues execution. - // ──Quoth MSDN - SleepEx(0, false); - return 0; -} +// Repositions open file stream. +// +// This function flushes the buffer (unless it's currently in the EOF +// state) and then calls lseek() on the underlying file. If the stream +// is in the EOF state, this function can be used to restore it without +// needing to reopen the file. +// +// @param rdi is stream handle +// @param rsi is offset is the byte delta +// @param rdx is whence and can be SEET_SET, SEEK_CUR, or SEEK_END +// @return 0 on success or -1 w/ errno +// @see fflush_unlocked() +// @threadsafe +fseeko: mov %rdi,%r11 + ezlea fseeko_unlocked,ax + jmp stdio_unlock + .endfn fseeko,globl diff --git a/libc/stdio/unlocked/fwrite_unlocked.S b/libc/stdio/unlocked/fwrite_unlocked.S index 7ea005850..cf57f397a 100644 --- a/libc/stdio/unlocked/fwrite_unlocked.S +++ b/libc/stdio/unlocked/fwrite_unlocked.S @@ -26,6 +26,7 @@ // @param rcx has file object stream pointer // @return count on success, [0,count) on EOF, 0 on error or count==0 // @see fwrite_unlocked() +// @threadsafe fwrite: mov %rcx,%r11 ezlea fwrite_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/getc_unlocked.S b/libc/stdio/unlocked/getc_unlocked.S index 0d06c5218..d92ea8900 100644 --- a/libc/stdio/unlocked/getc_unlocked.S +++ b/libc/stdio/unlocked/getc_unlocked.S @@ -23,6 +23,7 @@ // @param rdi has file stream object pointer // @return byte in range 0..255, or -1 w/ errno // @see fgetc_unlocked() +// @threadsafe getc: mov %rdi,%r11 ezlea fgetwc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/getchar_unlocked.S b/libc/stdio/unlocked/getchar_unlocked.S index 5bc14faaa..fa39d592b 100644 --- a/libc/stdio/unlocked/getchar_unlocked.S +++ b/libc/stdio/unlocked/getchar_unlocked.S @@ -22,8 +22,9 @@ // // @return byte in range 0..255, or -1 w/ errno // @see fgetc_unlocked() +// @threadsafe getchar: - lea stdin(%rip),%rdi + mov stdin(%rip),%rdi mov %rdi,%r11 ezlea fgetc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/getwc_unlocked.S b/libc/stdio/unlocked/getwc_unlocked.S index c4eca5ee2..70e0047a4 100644 --- a/libc/stdio/unlocked/getwc_unlocked.S +++ b/libc/stdio/unlocked/getwc_unlocked.S @@ -23,6 +23,7 @@ // @param rdi has file stream object pointer // @return wide character or -1 on EOF or error // @see fgetwc_unlocked() +// @threadsafe getwc: mov %rdi,%r11 ezlea fgetwc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/getwchar_unlocked.S b/libc/stdio/unlocked/getwchar_unlocked.S index f76f34285..f6d2d77ca 100644 --- a/libc/stdio/unlocked/getwchar_unlocked.S +++ b/libc/stdio/unlocked/getwchar_unlocked.S @@ -22,8 +22,9 @@ // // @return wide character or -1 on EOF or error // @see fgetwc_unlocked() +// @threadsafe getwchar: - lea stdin(%rip),%rdi + mov stdin(%rip),%rdi mov %rdi,%r11 ezlea fgetwc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/putc_unlocked.S b/libc/stdio/unlocked/putc_unlocked.S index fd5da3886..ae88342b3 100644 --- a/libc/stdio/unlocked/putc_unlocked.S +++ b/libc/stdio/unlocked/putc_unlocked.S @@ -24,6 +24,7 @@ // @param rsi has stream object pointer // @return c as unsigned char if written or -1 w/ errno // @see fputc_unlocked() +// @threadsafe putc: mov %rsi,%r11 ezlea fputc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/putchar_unlocked.S b/libc/stdio/unlocked/putchar_unlocked.S index b1d55fab7..1b769d986 100644 --- a/libc/stdio/unlocked/putchar_unlocked.S +++ b/libc/stdio/unlocked/putchar_unlocked.S @@ -23,8 +23,9 @@ // @param rdi has character // @return c (as unsigned char) if written or -1 w/ errno // @see fputc_unlocked() +// @threadsafe putchar: - lea stdout(%rip),%rsi + mov stdout(%rip),%rsi mov %rsi,%r11 ezlea fputc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/putwc_unlocked.S b/libc/stdio/unlocked/putwc_unlocked.S index d66a91efe..abaa27947 100644 --- a/libc/stdio/unlocked/putwc_unlocked.S +++ b/libc/stdio/unlocked/putwc_unlocked.S @@ -24,6 +24,7 @@ // @param rsi has file object // @return wc if written or -1 w/ errno // @see putwc_unlocked() +// @threadsafe putwc: mov %rsi,%r11 ezlea fputwc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/putwchar_unlocked.S b/libc/stdio/unlocked/putwchar_unlocked.S index a24d6cd02..921ff2ac4 100644 --- a/libc/stdio/unlocked/putwchar_unlocked.S +++ b/libc/stdio/unlocked/putwchar_unlocked.S @@ -23,8 +23,9 @@ // @param rdi has wide character // @return wc if written or -1 w/ errno // @see fputwc_unlocked() +// @threadsafe putwchar: - lea stdout(%rip),%rsi + mov stdout(%rip),%rsi mov %rsi,%r11 ezlea fputwc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/stdio_unlock.S b/libc/stdio/unlocked/stdio_unlock.S index 49f11ce44..3f7a5b94f 100644 --- a/libc/stdio/unlocked/stdio_unlock.S +++ b/libc/stdio/unlocked/stdio_unlock.S @@ -18,52 +18,54 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" -#define LOCK 0x2c /* see struct file in stdio.h */ - // Wrapper for applying locking to stdio functions. // // This function is intended to be called by thunks. // -// @param rax has the delegate function pointer +// @param rax is stdio function pointer // @param rdi is passed along as an arg // @param rsi is passed along as an arg // @param rdx is passed along as an arg // @param rcx is passed along as an arg -// @param r8 is passed along as an arg -// @param r9 is passed along as an arg -// @param r10 is passed along as an arg // @param r11 has the FILE* obj pointer // @return rax is passed along as result // @return rdx is passed along as result +// @threadsafe stdio_unlock: push %rbp mov %rsp,%rbp + .profilable // acquires mutex - push %rcx + push %rax + push %rdi + push %rsi push %rdx - mov $1,%cl -0: mov LOCK(%r11),%dl # optimistic - test %dl,%dl - je 2f -1: pause # hyperyield - jmp 0b -2: mov %ecx,%edx - xchg LOCK(%r11),%dl # locks bus! - test %dl,%dl - jne 1b - pop %rdx + push %rcx + push %r11 + mov %r11,%rdi + call flockfile + pop %r11 pop %rcx + pop %rdx + pop %rsi + pop %rdi + pop %rax // calls delegate - push %rsi push %r11 + push %rsi # align stack call *%rax - pop %r11 pop %rsi + pop %r11 // releases mutex - movb $0,LOCK(%r11) + push %rax + push %rdx + mov %r11,%rdi + call funlockfile + pop %rdx + pop %rax pop %rbp ret diff --git a/libc/stdio/unlocked/ungetc_unlocked.S b/libc/stdio/unlocked/ungetc_unlocked.S index 967cadd3b..f8b455bdb 100644 --- a/libc/stdio/unlocked/ungetc_unlocked.S +++ b/libc/stdio/unlocked/ungetc_unlocked.S @@ -24,6 +24,7 @@ // @param rds has stream object pointer // @return rax has rdi on success or -1 w/ errno // @see ungetc_unlocked() +// @threadsafe ungetc: mov %rsi,%r11 ezlea ungetc_unlocked,ax jmp stdio_unlock diff --git a/libc/stdio/unlocked/ungetwc_unlocked.S b/libc/stdio/unlocked/ungetwc_unlocked.S index 0c17fce2c..0dad092c4 100644 --- a/libc/stdio/unlocked/ungetwc_unlocked.S +++ b/libc/stdio/unlocked/ungetwc_unlocked.S @@ -24,6 +24,7 @@ // @param rds has stream object pointer // @return rax has rdi on success or -1 w/ errno // @see ungetwc_unlocked() +// @threadsafe ungetwc: mov %rsi,%r11 ezlea ungetwc_unlocked,ax diff --git a/libc/stdio/vfprintf.c b/libc/stdio/vfprintf.c index 1fb65e33c..dc389902b 100644 --- a/libc/stdio/vfprintf.c +++ b/libc/stdio/vfprintf.c @@ -16,45 +16,16 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" -#include "libc/fmt/fmt.h" -#include "libc/intrin/spinlock.h" -#include "libc/limits.h" #include "libc/stdio/stdio.h" -#include "libc/sysv/errfuns.h" - -struct state { - FILE *f; - int n; -}; - -static int vfprintfputchar(const char *s, struct state *t, size_t n) { - int rc; - if (n) { - _spinlock(&t->f->lock); - if (n == 1 && *s != '\n' && t->f->beg < t->f->size && - t->f->bufmode != _IONBF) { - t->f->buf[t->f->beg++] = *s; - t->n += n; - rc = 0; - } else if (!fwrite_unlocked(s, 1, n, t->f)) { - rc = -1; - } else { - t->n += n; - rc = 0; - } - _spunlock(&t->f->lock); - } else { - rc = 0; - } - return 0; -} +/** + * Formats and writes text to stream. + * @see printf() for further documentation + */ int(vfprintf)(FILE *f, const char *fmt, va_list va) { - struct state st[1] = {{f, 0}}; - if (__fmt(vfprintfputchar, st, fmt, va) != -1) { - return st->n; - } else { - return -1; - } + int rc; + flockfile(f); + rc = (vfprintf_unlocked)(f, fmt, va); + funlockfile(f); + return rc; } diff --git a/libc/stdio/vfprintf_unlocked.c b/libc/stdio/vfprintf_unlocked.c new file mode 100644 index 000000000..940e3e351 --- /dev/null +++ b/libc/stdio/vfprintf_unlocked.c @@ -0,0 +1,61 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=8 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/fmt/fmt.h" +#include "libc/limits.h" +#include "libc/stdio/stdio.h" +#include "libc/sysv/errfuns.h" + +struct state { + FILE *f; + int n; +}; + +static int vfprintfputchar(const char *s, struct state *t, size_t n) { + int rc; + if (n) { + if (n == 1 && *s != '\n' && t->f->beg < t->f->size && + t->f->bufmode != _IONBF) { + t->f->buf[t->f->beg++] = *s; + t->n += n; + rc = 0; + } else if (!fwrite_unlocked(s, 1, n, t->f)) { + rc = -1; + } else { + t->n += n; + rc = 0; + } + } else { + rc = 0; + } + return 0; +} + +/** + * Formats and writes text to stream. + * @see printf() for further documentation + */ +int(vfprintf_unlocked)(FILE *f, const char *fmt, va_list va) { + int rc; + struct state st[1] = {{f, 0}}; + if ((rc = __fmt(vfprintfputchar, st, fmt, va)) != -1) { + rc = st->n; + } + return rc; +} diff --git a/libc/stdio/vprintf.c b/libc/stdio/vprintf.c index 059923297..a1e273c98 100644 --- a/libc/stdio/vprintf.c +++ b/libc/stdio/vprintf.c @@ -18,6 +18,10 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/stdio/stdio.h" +/** + * Formats and writes text to stdout. + * @see printf() for further documentation + */ int(vprintf)(const char* fmt, va_list va) { return (vfprintf)(stdout, fmt, va); } diff --git a/libc/str/classifypath.c b/libc/str/classifypath.c index 9f26cc410..9213b93fa 100644 --- a/libc/str/classifypath.c +++ b/libc/str/classifypath.c @@ -36,11 +36,11 @@ * inclusive of DOS drive paths, DOS rooted paths, in addition to the * New Technology UNC paths, then you may do the following: * - * if (_classifypath(str) & _PATH_ABS) { ... } + * if (_classifypath(str) & _kPathAbs) { ... } * * To check if path is a relative path: * - * if (~_classifypath(str) & _PATH_ABS) { ... } + * if (~_classifypath(str) & _kPathAbs) { ... } * * Please note the above check includes rooted paths such as `\foo` * which is considered absolute by MSDN and we consider it absolute @@ -52,14 +52,14 @@ * * @return integer value that's one of following: * - `0` if non-weird relative path e.g. `c` - * - `_PATH_ABS` if absolute (or rooted dos) path e.g. `/⋯` - * - `_PATH_DOS` if `c:`, `d:foo` i.e. drive-relative path - * - `_PATH_ABS|_PATH_DOS` if proper dos path e.g. `c:/foo` - * - `_PATH_DOS|_PATH_DEV` if dos device path e.g. `nul`, `conin$` - * - `_PATH_ABS|_PATH_WIN` if `//c`, `//?c`, etc. - * - `_PATH_ABS|_PATH_WIN|_PATH_DEV` if `//./⋯`, `//?/⋯` - * - `_PATH_ABS|_PATH_WIN|_PATH_DEV|_PATH_ROOT` if `//.` or `//?` - * - `_PATH_ABS|_PATH_NT` e.g. `\??\\⋯` (undoc. strict backslash) + * - `_kPathAbs` if absolute (or rooted dos) path e.g. `/⋯` + * - `_kPathDos` if `c:`, `d:foo` i.e. drive-relative path + * - `_kPathAbs|_kPathDos` if proper dos path e.g. `c:/foo` + * - `_kPathDos|_kPathDev` if dos device path e.g. `nul`, `conin$` + * - `_kPathAbs|_kPathWin` if `//c`, `//?c`, etc. + * - `_kPathAbs|_kPathWin|_kPathDev` if `//./⋯`, `//?/⋯` + * - `_kPathAbs|_kPathWin|_kPathDev|_kPathRoot` if `//.` or `//?` + * - `_kPathAbs|_kPathNt` e.g. `\??\\⋯` (undoc. strict backslash) * @see "The Definitive Guide on Win32 to NT Path Conversion", James * Forshaw, Google Project Zero Blog, 2016-02-29 * @see "Naming Files, Paths, and Namespaces", MSDN 01/04/2021 @@ -94,17 +94,17 @@ int _classifypath(const char *s) { (s[2] == 'm' || s[2] == 'M'))) && // ('1' <= s[3] && s[3] <= '9') && // !s[4])) { - return _PATH_DOS | _PATH_DEV; + return _kPathDos | _kPathDev; } switch (s[1]) { case ':': switch (s[2]) { case 0: // c: default: // c:wut⋯ - return _PATH_DOS; + return _kPathDos; case '/': // c:/⋯ case '\\': // c:\⋯ - return _PATH_ABS | _PATH_DOS; + return _kPathAbs | _kPathDos; } default: return 0; @@ -113,37 +113,37 @@ int _classifypath(const char *s) { if (SupportsWindows()) { if (s[1] == '?' && s[2] == '?') { if (!s[3]) { - return _PATH_ABS | _PATH_NT | _PATH_ROOT; // \??\⋯ + return _kPathAbs | _kPathNt | _kPathRoot; // \??\⋯ } else if (s[3] == '\\') { - return _PATH_ABS | _PATH_NT; // \??\⋯ + return _kPathAbs | _kPathNt; // \??\⋯ } } } // fallthrough case '/': if (!SupportsWindows()) { - return _PATH_ABS; + return _kPathAbs; } switch (s[1]) { case 0: // / default: // /⋯ - return _PATH_ABS; + return _kPathAbs; case '/': case '\\': switch (s[2]) { case 0: // // default: // //⋯ - return _PATH_ABS | _PATH_WIN; + return _kPathAbs | _kPathWin; case '.': case '?': switch (s[3]) { case 0: // //? or //. - return _PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT; + return _kPathAbs | _kPathWin | _kPathDev | _kPathRoot; default: // //?⋯ or //.⋯ - return _PATH_ABS | _PATH_WIN; + return _kPathAbs | _kPathWin; case '/': case '\\': // //?/⋯ or //./⋯ - return _PATH_ABS | _PATH_WIN | _PATH_DEV; + return _kPathAbs | _kPathWin | _kPathDev; } } } diff --git a/libc/str/isabspath.c b/libc/str/isabspath.c index 4e40be341..60de5b76a 100644 --- a/libc/str/isabspath.c +++ b/libc/str/isabspath.c @@ -32,5 +32,5 @@ * */ bool _isabspath(const char *path) { - return _classifypath(path) & _PATH_ABS; + return _classifypath(path) & _kPathAbs; } diff --git a/libc/str/path.h b/libc/str/path.h index 10b1fca62..74c65a91f 100644 --- a/libc/str/path.h +++ b/libc/str/path.h @@ -1,12 +1,12 @@ #ifndef COSMOPOLITAN_LIBC_STR_PATH_H_ #define COSMOPOLITAN_LIBC_STR_PATH_H_ -#define _PATH_ABS 1 -#define _PATH_DEV 2 -#define _PATH_ROOT 4 -#define _PATH_DOS 8 -#define _PATH_WIN 16 -#define _PATH_NT 32 +#define _kPathAbs 1 +#define _kPathDev 2 +#define _kPathRoot 4 +#define _kPathDos 8 +#define _kPathWin 16 +#define _kPathNt 32 #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ diff --git a/libc/str/str.mk b/libc/str/str.mk index 8b2a34226..813af6569 100644 --- a/libc/str/str.mk +++ b/libc/str/str.mk @@ -86,6 +86,14 @@ o/$(MODE)/libc/str/windowstimetotimespec.o: \ OVERRIDE_CFLAGS += \ -O2 +# we can't use compiler magic because: +# kprintf() depends on these functions +o/$(MODE)/libc/fmt/strsignal.greg.o: \ + OVERRIDE_CFLAGS += \ + -fpie \ + -ffreestanding \ + $(NO_MAGIC) + LIBC_STR_LIBS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x))) LIBC_STR_SRCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_SRCS)) LIBC_STR_HDRS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/str/strsignal.greg.c b/libc/str/strsignal.greg.c index a349ac47c..b169c1264 100644 --- a/libc/str/strsignal.greg.c +++ b/libc/str/strsignal.greg.c @@ -35,7 +35,9 @@ static char g_strsignal[12]; * @return pointer to static memory that mutates on subsequent calls * @see sigaction() */ -noasan noinstrument char *strsignal(int sig) { +privileged char *strsignal(int sig) { + // we need privileged because: + // kprintf is privileged and it depends on this char *p; const char *s; p = g_strsignal; diff --git a/libc/stubs/ld.S b/libc/stubs/ld.S index 195e33c71..c7e935a5d 100644 --- a/libc/stubs/ld.S +++ b/libc/stubs/ld.S @@ -31,6 +31,8 @@ _ehead = 0 _ereal = 0 __privileged_start = 0 + __privileged_addr = 0 + __privileged_size = 0 __test_start = 0 __ro = 0 __relo_start = 0 @@ -51,6 +53,8 @@ .globl ape_xlm .globl __relo_start .globl __relo_end + .globl __privileged_size + .globl __privileged_addr .globl __privileged_start .globl __ro .globl __test_start @@ -72,6 +76,8 @@ .weak ape_xlm .weak __relo_start .weak __relo_end + .weak __privileged_size + .weak __privileged_addr .weak __privileged_start .weak __ro .weak __test_start diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index 2ad3f7c43..9edf6a7bb 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -224,22 +224,25 @@ syscon mmap MAP_PRIVATE 2 2 2 2 2 2 # forced consensus & faked nt syscon mmap MAP_STACK 6 6 6 6 6 6 # our definition syscon mmap MAP_TYPE 15 15 15 15 15 15 # mask for type of mapping syscon mmap MAP_FIXED 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 # unix consensus; openbsd appears to forbid; faked nt -syscon mmap MAP_FIXED_NOREPLACE 0x08000000 0x08000000 0x08000000 0x08000000 0x08000000 0x08000000 # handled and defined by cosmo runtime; 0x100000 on linux 4.7+ +syscon mmap MAP_FIXED_NOREPLACE 0x08000000 0x00004010 0x08000000 0x08000000 0x08000000 0x08000000 # handled and defined by cosmo runtime; 0x100000 on linux 4.7+; MAP_FIXED|MAP_EXCL on FreeBSD syscon mmap MAP_ANONYMOUS 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt syscon mmap MAP_GROWSDOWN 0x00000100 0 0 0 0 0 # use MAP_STACK; abstracted by MAP_STACK; may be passed to __sys_mmap() for low-level Linux fiddling -syscon mmap MAP_CONCEAL 0 0 0x00020000 0x00008000 0x00008000 0 # omit from core dumps; MAP_NOCORE on FreeBSD syscon mmap MAP_LOCKED 0x00002000 0 0 0 0 0 syscon mmap MAP_NORESERVE 0x00004000 0x00000040 0 0 0x00000040 0 # Linux calls it "reserve"; NT calls it "commit"? which is default? -syscon mmap MAP_POPULATE 0x00008000 0 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping +syscon mmap MAP_POPULATE 0x00008000 0 0x00040000 0 0 0 # MAP_PREFAULT_READ on FreeBSD; can avoid madvise(MADV_WILLNEED) on private file mapping syscon mmap MAP_NONBLOCK 0x00010000 0 0 0 0 0 syscon mmap MAP_HUGETLB 0x00040000 0 0 0 0 0x80000000 # kNtSecLargePages +syscon mmap MAP_INHERIT -1 -1 -1 -1 0x00000080 -1 # make it inherit across execve() +syscon mmap MAP_HASSEMAPHORE 0 0x00000200 0x00000200 0 0x00000200 0 # does it matter on x86? +syscon mmap MAP_NOSYNC 0 0 0x00000800 0 0 0 # flush to physical media only when necessary rather than gratuitously; be sure to use write() rather than ftruncate() with this! +syscon mmap MAP_CONCEAL 0 0 0x00020000 0x00008000 0x00008000 0 # omit from core dumps; MAP_NOCORE on FreeBSD syscon mmap MAP_HUGE_MASK 63 0 0 0 0 0 syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0 0 -syscon compat MAP_NOCORE 0 0 0x0020000 0x8000 0x8000 0 # use MAP_CONCEAL -syscon compat MAP_ANON 0x20 0x1000 0x0001000 0x1000 0x1000 0x20 # bsd consensus; faked nt -syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 0 # ignored -syscon compat MAP_DENYWRITE 0x0800 0 0 0 0 0 -syscon compat MAP_32BIT 0x40 0 0x080000 0 0 0 # iffy +syscon compat MAP_NOCORE 0 0 0x00020000 0x00008000 0x00008000 0 # use MAP_CONCEAL +syscon compat MAP_ANON 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt +syscon compat MAP_EXECUTABLE 0x00001000 0 0 0 0 0 # ignored +syscon compat MAP_DENYWRITE 0x00000800 0 0 0 0 0 +syscon compat MAP_32BIT 0x00000040 0 0x00080000 0 0 0 # iffy # madvise() flags # @@ -337,36 +340,6 @@ syscon waitid WEXITED 4 4 0x10 0 32 0 syscon waitid WSTOPPED 2 8 2 0 2 0 syscon waitid WNOWAIT 0x01000000 0x20 8 0 0x10000 0 -# stat::st_mode constants -# -# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary -syscon stat S_IFREG 0100000 0100000 0100000 0100000 0100000 0100000 # regular file (unix consensus; faked nt) -syscon stat S_IFBLK 0060000 0060000 0060000 0060000 0060000 0060000 # block device (unix consensus; faked nt) -syscon stat S_IFCHR 0020000 0020000 0020000 0020000 0020000 0020000 # character device (unix consensus; faked nt) -syscon stat S_IFDIR 0040000 0040000 0040000 0040000 0040000 0040000 # directory (unix consensus; faked nt) -syscon stat S_IFIFO 0010000 0010000 0010000 0010000 0010000 0010000 # pipe (unix consensus; faked nt) -syscon stat S_IFLNK 0120000 0120000 0120000 0120000 0120000 0120000 # symbolic link (unix consensus; faked nt) -syscon stat S_IFSOCK 0140000 0140000 0140000 0140000 0140000 0140000 # socket (unix consensus; faked nt) -syscon stat S_IFMT 0170000 0170000 0170000 0170000 0170000 0170000 # FILE TYPE MASK (unix consensus; faked nt) -syscon stat S_ISVTX 0001000 0001000 0001000 0001000 0001000 0001000 # THE STICKY BIT (unix consensus; faked nt) -syscon stat S_ISGID 0002000 0002000 0002000 0002000 0002000 0002000 # the setgid bit (unix consensus; faked nt) -syscon stat S_ISUID 0004000 0004000 0004000 0004000 0004000 0004000 # the setuid bit (unix consensus; faked nt) -syscon stat S_IEXEC 0000100 0000100 0000100 0000100 0000100 0000100 # just use octal (unix consensus; faked nt) -syscon stat S_IWRITE 0000200 0000200 0000200 0000200 0000200 0000200 # just use octal (unix consensus; faked nt) -syscon stat S_IREAD 0000400 0000400 0000400 0000400 0000400 0000400 # just use octal (unix consensus; faked nt) -syscon stat S_IXUSR 0000100 0000100 0000100 0000100 0000100 0000100 # just use octal (unix consensus; faked nt) -syscon stat S_IWUSR 0000200 0000200 0000200 0000200 0000200 0000200 # just use octal (unix consensus; faked nt) -syscon stat S_IRUSR 0000400 0000400 0000400 0000400 0000400 0000400 # just use octal (unix consensus; faked nt) -syscon stat S_IRWXU 0000700 0000700 0000700 0000700 0000700 0000700 # just use octal (unix consensus; faked nt) -syscon stat S_IXGRP 0000010 0000010 0000010 0000010 0000010 0000010 # just use octal (unix consensus; faked nt) -syscon stat S_IWGRP 0000020 0000020 0000020 0000020 0000020 0000020 # just use octal (unix consensus; faked nt) -syscon stat S_IRGRP 0000040 0000040 0000040 0000040 0000040 0000040 # just use octal (unix consensus; faked nt) -syscon stat S_IRWXG 0000070 0000070 0000070 0000070 0000070 0000070 # just use octal (unix consensus; faked nt) -syscon stat S_IXOTH 0000001 0000001 0000001 0000001 0000001 0000001 # just use octal (unix consensus; faked nt) -syscon stat S_IWOTH 0000002 0000002 0000002 0000002 0000002 0000002 # just use octal (unix consensus; faked nt) -syscon stat S_IROTH 0000004 0000004 0000004 0000004 0000004 0000004 # just use octal (unix consensus; faked nt) -syscon stat S_IRWXO 0000007 0000007 0000007 0000007 0000007 0000007 # just use octal (unix consensus; faked nt) - # fcntl() # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary @@ -605,7 +578,8 @@ syscon sicode SYS_USER_DISPATCH 2 -1 -1 -1 -1 -1 # SIGSYS; syscall # sigaltstack() values # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary -syscon ss SIGSTKSZ 0x2000 0x020000 0x8800 0x7000 0x7000 0x2000 +syscon ss SIGSTKSZ 8192 131072 34816 28672 28672 8192 # overlayed with STACKSIZE; you need to #undef SIGSTKSZ to access this symbol +syscon ss MINSIGSTKSZ 2048 32768 2048 12288 8192 2048 # overlayed with 32768; you need to #undef MINSIGSTKSZ to access this symbol syscon ss SS_ONSTACK 1 1 1 1 1 1 # unix consensus syscon ss SS_DISABLE 2 4 4 4 4 2 # bsd consensus @@ -1158,18 +1132,18 @@ syscon ms MS_INVALIDATE 2 2 2 4 2 0 # statvfs() flags # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary -syscon statvfs ST_NOSUID 2 2 2 2 2 0 # unix consensus syscon statvfs ST_RDONLY 1 1 1 1 1 0 # unix consensus +syscon statvfs ST_NOSUID 2 2 2 2 2 0 # unix consensus +syscon statvfs ST_NODEV 4 0 0 0 0x00000010 0 +syscon statvfs ST_NOEXEC 8 0 0 0 4 0 +syscon statvfs ST_SYNCHRONOUS 16 0 0 0 2 0 syscon statvfs ST_APPEND 0x0100 0 0 0 0 0 syscon statvfs ST_IMMUTABLE 0x0200 0 0 0 0 0 -syscon statvfs ST_MANDLOCK 0x40 0 0 0 0 0 +syscon statvfs ST_MANDLOCK 0x0040 0 0 0 0 0 syscon statvfs ST_NOATIME 0x0400 0 0 0x04000000 0 0 -syscon statvfs ST_NODEV 4 0 0 0 0x00000010 0 syscon statvfs ST_NODIRATIME 0x0800 0 0 0 0 0 -syscon statvfs ST_NOEXEC 8 0 0 0 4 0 +syscon statvfs ST_WRITE 0x0080 0 0 0 0 0 syscon statvfs ST_RELATIME 0x1000 0 0 0 0x00020000 0 -syscon statvfs ST_SYNCHRONOUS 0x10 0 0 0 2 0 -syscon statvfs ST_WRITE 0x80 0 0 0 0 0 # sendfile() flags # @@ -1349,7 +1323,6 @@ syscon termios TIOCSETD 0x5423 0x8004741b 0x8004741b 0x8004741b 0x800474 syscon termios TIOCSIG 0x40045436 0x2000745f 0x2004745f 0x8004745f 0x8004745f 0 # boop syscon termios TIOCSPGRP 0x5410 0x80047476 0x80047476 0x80047476 0x80047476 0 # boop syscon termios TIOCSTI 0x5412 0x80017472 0x80017472 0 0 0 # boop -syscon termios TIOCGPTN 0x80045430 0 0x4004740f 0 0 0 # boop syscon termios TIOCGSID 0x5429 0x40047463 0x40047463 0x40047463 0x40047463 0 # boop syscon termios TABLDISC 0 0x3 0 0x3 0x3 0 # boop syscon termios SLIPDISC 0 0x4 0x4 0x4 0x4 0 # boop @@ -1442,7 +1415,7 @@ syscon termios IUTF8 0b0100000000000000 0b0100000000000000 0 0 0 0b010 # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary syscon termios OPOST 0b0000000000000001 0b000000000000000001 0b000000000000000001 0b0000000000000001 0b0000000000000001 0b0000000000000001 # termios.c_oflag&=~OPOST disables output processing magic, e.g. MULTICS newlines -syscon termios OLCUC 0b0000000000000010 0 0 0b0000000000100000 0 0b0000000000000010 # termios.c_oflag|=OLCUC maps a-z → A-Z output +syscon termios OLCUC 0b0000000000000010 0 0 0b0000000000100000 0 0b0000000000000010 # termios.c_oflag|=OLCUC maps a-z → A-Z output (SHOUTING) syscon termios ONLCR 0b0000000000000100 0b000000000000000010 0b000000000000000010 0b0000000000000010 0b0000000000000010 0b0000000000000100 # termios.c_oflag|=ONLCR map \n → \r\n output (MULTICS newline) and requires OPOST syscon termios OCRNL 0b0000000000001000 0b000000000000010000 0b000000000000010000 0b0000000000010000 0b0000000000010000 0b0000000000001000 # termios.c_oflag|=OCRNL maps \r → \n output syscon termios ONOCR 0b0000000000010000 0b000000000000100000 0b000000000000100000 0b0000000001000000 0b0000000001000000 0b0000000000010000 # termios.c_oflag|=ONOCR maps \r → ∅ output iff column 0 @@ -1478,14 +1451,14 @@ syscon termios FF1 0b1000000000000000 0b000100000000000000 0b0001000000000 # Teletypewriter Special Control Character Assignments # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary +syscon termios VMIN 6+1 16 16 16 16 6 # termios.c_cc[VMIN]=𝑥 in non-canonical mode can be set to 0 for non-blocking reads, 1 for single character raw mode reads, or higher to buffer +syscon termios VTIME 5+1 17 17 17 17 5 # termios.c_cc[VTIME]=𝑥 sets non-canonical read timeout to 𝑥×𝟷𝟶𝟶ms which is needed when entering escape sequences manually with the escape key syscon termios NCCS 20 20 20 20 20 20 # ARRAYLEN(termios.c_cc); we schlep c_line into c_cc on linux syscon termios VINTR 0+1 8 8 8 8 0 # termios.c_cc[VINTR]=𝑥 syscon termios VQUIT 1+1 9 9 9 9 1 # termios.c_cc[VQUIT]=𝑥 syscon termios VERASE 2+1 3 3 3 3 2 # termios.c_cc[VERASE]=𝑥 syscon termios VKILL 3+1 5 5 5 5 3 # termios.c_cc[VKILL]=𝑥 syscon termios VEOF 4+1 0 0 0 0 4 # termios.c_cc[VEOF]=𝑥 -syscon termios VTIME 5+1 17 17 17 17 5 # termios.c_cc[VTIME]=𝑥 sets non-canonical read timeout to 𝑥×𝟷𝟶𝟶ms which is needed when entering escape sequences manually with the escape key -syscon termios VMIN 6+1 16 16 16 16 6 # termios.c_cc[VMIN]=𝑥 in non-canonical mode can be set to 0 for non-blocking reads, 1 for single character raw mode reads, or higher to buffer syscon termios VSWTC 7+1 0 0 0 0 7 # termios.c_cc[VSWTC]=𝑥 syscon termios VSTART 8+1 12 12 12 12 8 # termios.c_cc[VSTART]=𝑥 syscon termios VSTOP 9+1 13 13 13 13 9 # termios.c_cc[VSTOP]=𝑥 @@ -1534,6 +1507,8 @@ syscon termios CSTOP 19 19 19 19 19 0 # unix consensus # Pseudoteletypewriter Control # # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary +syscon pty TIOCGPTN 0x80045430 0 0x4004740f 0 0 0 # boop +syscon pty TIOCSPTLCK 0x40045431 0 0 0 0 0 # boop syscon pty TIOCPKT 0x5420 0x80047470 0x80047470 0x80047470 0x80047470 -1 # boop syscon pty TIOCPKT_DATA 0 0 0 0 0 0 # consensus syscon pty TIOCPKT_FLUSHREAD 1 1 1 1 1 1 # unix consensus @@ -1543,7 +1518,6 @@ syscon pty TIOCPKT_START 8 8 8 8 8 8 # unix consensus syscon pty TIOCPKT_NOSTOP 16 16 16 16 16 16 # unix consensus syscon pty TIOCPKT_DOSTOP 32 32 32 32 32 32 # unix consensus syscon pty TIOCPKT_IOCTL 64 64 64 64 64 64 # unix consensus -syscon pty TIOCSPTLCK 0x40045431 0 0 0 0 -1 # boop syscon pty PTMGET 0 0 0 0x40287401 0x40287401 -1 # for /dev/ptm # Modem Control @@ -1599,18 +1573,6 @@ syscon sock SOCK_NONBLOCK 0x0800 0x0800 0x20000000 0x4000 0x20000000 syscon sock SOCK_DCCP 6 0 0 0 0 0 # what is it? syscon sock SOCK_PACKET 10 0 0 0 0 0 # what is it? -syscon prsnlty ADDR_COMPAT_LAYOUT 0x0200000 0 0 0 0 0 # linux only -syscon prsnlty READ_IMPLIES_EXEC 0x0400000 0 0 0 0 0 # linux only -syscon prsnlty ADDR_LIMIT_3GB 0x8000000 0 0 0 0 0 # linux only -syscon prsnlty FDPIC_FUNCPTRS 0x0080000 0 0 0 0 0 # linux only -syscon prsnlty STICKY_TIMEOUTS 0x4000000 0 0 0 0 0 # linux only -syscon prsnlty MMAP_PAGE_ZERO 0x0100000 0 0 0 0 0 # linux only -syscon prsnlty ADDR_LIMIT_32BIT 0x0800000 0 0 0 0 0 # linux only -syscon prsnlty WHOLE_SECONDS 0x2000000 0 0 0 0 0 # linux only -syscon prsnlty ADDR_NO_RANDOMIZE 0x0040000 0 0 0 0 0 # linux only -syscon prsnlty SHORT_INODE 0x1000000 0 0 0 0 0 # linux only -syscon prsnlty UNAME26 0x0020000 0 0 0 0 0 # linux only - syscon misc TH_FIN 1 1 1 1 1 1 # consensus syscon misc TH_SYN 2 2 2 2 2 2 # consensus syscon misc TH_RST 4 4 4 4 4 4 # consensus @@ -3131,7 +3093,6 @@ syscon misc CSTATUS 0 20 20 255 255 0 syscon misc DEAD_PROCESS 8 8 7 0 0 0 syscon misc FNM_NOSYS -1 -1 -1 2 2 0 syscon misc INIT_PROCESS 5 5 5 0 0 0 -syscon misc MINSIGSTKSZ 0x0800 0x8000 0x0800 0x3000 0x2000 0 syscon misc MQ_PRIO_MAX 0x8000 0 0x40 0 0 0 syscon misc MTERASE 13 0 12 9 9 0 syscon misc MTLOAD 30 0 19 0 0 0 diff --git a/libc/sysv/consts/ADDR_COMPAT_LAYOUT.S b/libc/sysv/consts/ADDR_COMPAT_LAYOUT.S deleted file mode 100644 index a2613bfd9..000000000 --- a/libc/sysv/consts/ADDR_COMPAT_LAYOUT.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,ADDR_COMPAT_LAYOUT,0x0200000,0,0,0,0,0 diff --git a/libc/sysv/consts/ADDR_LIMIT_32BIT.S b/libc/sysv/consts/ADDR_LIMIT_32BIT.S deleted file mode 100644 index 6ad2491dd..000000000 --- a/libc/sysv/consts/ADDR_LIMIT_32BIT.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,ADDR_LIMIT_32BIT,0x0800000,0,0,0,0,0 diff --git a/libc/sysv/consts/ADDR_LIMIT_3GB.S b/libc/sysv/consts/ADDR_LIMIT_3GB.S deleted file mode 100644 index 6e29ba87c..000000000 --- a/libc/sysv/consts/ADDR_LIMIT_3GB.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,ADDR_LIMIT_3GB,0x8000000,0,0,0,0,0 diff --git a/libc/sysv/consts/ADDR_NO_RANDOMIZE.S b/libc/sysv/consts/ADDR_NO_RANDOMIZE.S deleted file mode 100644 index 3a076ae64..000000000 --- a/libc/sysv/consts/ADDR_NO_RANDOMIZE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,ADDR_NO_RANDOMIZE,0x0040000,0,0,0,0,0 diff --git a/libc/sysv/consts/FDPIC_FUNCPTRS.S b/libc/sysv/consts/FDPIC_FUNCPTRS.S deleted file mode 100644 index 4140c78ca..000000000 --- a/libc/sysv/consts/FDPIC_FUNCPTRS.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,FDPIC_FUNCPTRS,0x0080000,0,0,0,0,0 diff --git a/libc/sysv/consts/MAP_32BIT.S b/libc/sysv/consts/MAP_32BIT.S index 69d1006da..992a099ca 100644 --- a/libc/sysv/consts/MAP_32BIT.S +++ b/libc/sysv/consts/MAP_32BIT.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon compat,MAP_32BIT,0x40,0,0x080000,0,0,0 +.syscon compat,MAP_32BIT,0x00000040,0,0x00080000,0,0,0 diff --git a/libc/sysv/consts/MAP_ANON.S b/libc/sysv/consts/MAP_ANON.S index a1eb02bfe..a5bd6ea5b 100644 --- a/libc/sysv/consts/MAP_ANON.S +++ b/libc/sysv/consts/MAP_ANON.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon compat,MAP_ANON,0x20,0x1000,0x0001000,0x1000,0x1000,0x20 +.syscon compat,MAP_ANON,0x00000020,0x00001000,0x00001000,0x00001000,0x00001000,0x00000020 diff --git a/libc/sysv/consts/MAP_DENYWRITE.S b/libc/sysv/consts/MAP_DENYWRITE.S index 98efad2ec..3f495ded7 100644 --- a/libc/sysv/consts/MAP_DENYWRITE.S +++ b/libc/sysv/consts/MAP_DENYWRITE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon compat,MAP_DENYWRITE,0x0800,0,0,0,0,0 +.syscon compat,MAP_DENYWRITE,0x00000800,0,0,0,0,0 diff --git a/libc/sysv/consts/MAP_EXECUTABLE.S b/libc/sysv/consts/MAP_EXECUTABLE.S index e2efd0d26..078c5b380 100644 --- a/libc/sysv/consts/MAP_EXECUTABLE.S +++ b/libc/sysv/consts/MAP_EXECUTABLE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon compat,MAP_EXECUTABLE,0x1000,0,0,0,0,0 +.syscon compat,MAP_EXECUTABLE,0x00001000,0,0,0,0,0 diff --git a/libc/sysv/consts/MAP_FILE.S b/libc/sysv/consts/MAP_FILE.S index 13a1fe32c..55800b2c4 100644 --- a/libc/sysv/consts/MAP_FILE.S +++ b/libc/sysv/consts/MAP_FILE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon compat,MAP_FILE,0,0,0,0,0,0 +.syscon mmap,MAP_FILE,0,0,0,0,0,0 diff --git a/libc/sysv/consts/MAP_FIXED_NOREPLACE.S b/libc/sysv/consts/MAP_FIXED_NOREPLACE.S index 90b4f3369..0056e9e66 100644 --- a/libc/sysv/consts/MAP_FIXED_NOREPLACE.S +++ b/libc/sysv/consts/MAP_FIXED_NOREPLACE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon mmap,MAP_FIXED_NOREPLACE,0x08000000,0x08000000,0x08000000,0x08000000,0x08000000,0x08000000 +.syscon mmap,MAP_FIXED_NOREPLACE,0x08000000,0x00004010,0x08000000,0x08000000,0x08000000,0x08000000 diff --git a/libc/sysv/consts/MAP_HASSEMAPHORE.S b/libc/sysv/consts/MAP_HASSEMAPHORE.S new file mode 100644 index 000000000..807f606aa --- /dev/null +++ b/libc/sysv/consts/MAP_HASSEMAPHORE.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon mmap,MAP_HASSEMAPHORE,0,0x00000200,0x00000200,0,0x00000200,0 diff --git a/libc/sysv/consts/MAP_INHERIT.S b/libc/sysv/consts/MAP_INHERIT.S new file mode 100644 index 000000000..7216389f8 --- /dev/null +++ b/libc/sysv/consts/MAP_INHERIT.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon mmap,MAP_INHERIT,-1,-1,-1,-1,0x00000080,-1 diff --git a/libc/sysv/consts/MAP_NOCORE.S b/libc/sysv/consts/MAP_NOCORE.S index c0e6b263f..bb2e48762 100644 --- a/libc/sysv/consts/MAP_NOCORE.S +++ b/libc/sysv/consts/MAP_NOCORE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon compat,MAP_NOCORE,0,0,0x0020000,0x8000,0x8000,0 +.syscon compat,MAP_NOCORE,0,0,0x00020000,0x00008000,0x00008000,0 diff --git a/libc/sysv/consts/UNAME26.S b/libc/sysv/consts/MAP_NOSYNC.S similarity index 50% rename from libc/sysv/consts/UNAME26.S rename to libc/sysv/consts/MAP_NOSYNC.S index 7288894b2..054342f35 100644 --- a/libc/sysv/consts/UNAME26.S +++ b/libc/sysv/consts/MAP_NOSYNC.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,UNAME26,0x0020000,0,0,0,0,0 +.syscon mmap,MAP_NOSYNC,0,0,0x00000800,0,0,0 diff --git a/libc/sysv/consts/MAP_POPULATE.S b/libc/sysv/consts/MAP_POPULATE.S index 36d7843ec..bca16d04f 100644 --- a/libc/sysv/consts/MAP_POPULATE.S +++ b/libc/sysv/consts/MAP_POPULATE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon mmap,MAP_POPULATE,0x00008000,0,0,0,0,0 +.syscon mmap,MAP_POPULATE,0x00008000,0,0x00040000,0,0,0 diff --git a/libc/sysv/consts/MINSIGSTKSZ.S b/libc/sysv/consts/MINSIGSTKSZ.S index a5c500930..23a7e9ec8 100644 --- a/libc/sysv/consts/MINSIGSTKSZ.S +++ b/libc/sysv/consts/MINSIGSTKSZ.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,MINSIGSTKSZ,0x0800,0x8000,0x0800,0x3000,0x2000,0 +.syscon ss,MINSIGSTKSZ,2048,32768,2048,12288,8192,2048 diff --git a/libc/sysv/consts/MMAP_PAGE_ZERO.S b/libc/sysv/consts/MMAP_PAGE_ZERO.S deleted file mode 100644 index 44a90993a..000000000 --- a/libc/sysv/consts/MMAP_PAGE_ZERO.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,MMAP_PAGE_ZERO,0x0100000,0,0,0,0,0 diff --git a/libc/sysv/consts/READ_IMPLIES_EXEC.S b/libc/sysv/consts/READ_IMPLIES_EXEC.S deleted file mode 100644 index c2a749151..000000000 --- a/libc/sysv/consts/READ_IMPLIES_EXEC.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,READ_IMPLIES_EXEC,0x0400000,0,0,0,0,0 diff --git a/libc/sysv/consts/SHORT_INODE.S b/libc/sysv/consts/SHORT_INODE.S deleted file mode 100644 index 4605ea47e..000000000 --- a/libc/sysv/consts/SHORT_INODE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,SHORT_INODE,0x1000000,0,0,0,0,0 diff --git a/libc/sysv/consts/SIGSTKSZ.S b/libc/sysv/consts/SIGSTKSZ.S index 1a557a4b5..9f00d1765 100644 --- a/libc/sysv/consts/SIGSTKSZ.S +++ b/libc/sysv/consts/SIGSTKSZ.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon ss,SIGSTKSZ,0x2000,0x020000,0x8800,0x7000,0x7000,0x2000 +.syscon ss,SIGSTKSZ,8192,131072,34816,28672,28672,8192 diff --git a/libc/sysv/consts/STICKY_TIMEOUTS.S b/libc/sysv/consts/STICKY_TIMEOUTS.S deleted file mode 100644 index e15c5f294..000000000 --- a/libc/sysv/consts/STICKY_TIMEOUTS.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,STICKY_TIMEOUTS,0x4000000,0,0,0,0,0 diff --git a/libc/sysv/consts/ST_MANDLOCK.S b/libc/sysv/consts/ST_MANDLOCK.S index e23e806b8..dbfbec538 100644 --- a/libc/sysv/consts/ST_MANDLOCK.S +++ b/libc/sysv/consts/ST_MANDLOCK.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon statvfs,ST_MANDLOCK,0x40,0,0,0,0,0 +.syscon statvfs,ST_MANDLOCK,0x0040,0,0,0,0,0 diff --git a/libc/sysv/consts/ST_SYNCHRONOUS.S b/libc/sysv/consts/ST_SYNCHRONOUS.S index 9e7308849..eaec0a049 100644 --- a/libc/sysv/consts/ST_SYNCHRONOUS.S +++ b/libc/sysv/consts/ST_SYNCHRONOUS.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon statvfs,ST_SYNCHRONOUS,0x10,0,0,0,2,0 +.syscon statvfs,ST_SYNCHRONOUS,16,0,0,0,2,0 diff --git a/libc/sysv/consts/ST_WRITE.S b/libc/sysv/consts/ST_WRITE.S index 1945a52f7..84a0035fd 100644 --- a/libc/sysv/consts/ST_WRITE.S +++ b/libc/sysv/consts/ST_WRITE.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon statvfs,ST_WRITE,0x80,0,0,0,0,0 +.syscon statvfs,ST_WRITE,0x0080,0,0,0,0,0 diff --git a/libc/sysv/consts/S_IEXEC.S b/libc/sysv/consts/S_IEXEC.S deleted file mode 100644 index cec133e38..000000000 --- a/libc/sysv/consts/S_IEXEC.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IEXEC,0000100,0000100,0000100,0000100,0000100,0000100 diff --git a/libc/sysv/consts/S_IFBLK.S b/libc/sysv/consts/S_IFBLK.S deleted file mode 100644 index bb75920eb..000000000 --- a/libc/sysv/consts/S_IFBLK.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IFBLK,0060000,0060000,0060000,0060000,0060000,0060000 diff --git a/libc/sysv/consts/S_IFCHR.S b/libc/sysv/consts/S_IFCHR.S deleted file mode 100644 index c01847833..000000000 --- a/libc/sysv/consts/S_IFCHR.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IFCHR,0020000,0020000,0020000,0020000,0020000,0020000 diff --git a/libc/sysv/consts/S_IFDIR.S b/libc/sysv/consts/S_IFDIR.S deleted file mode 100644 index 58c96c0de..000000000 --- a/libc/sysv/consts/S_IFDIR.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IFDIR,0040000,0040000,0040000,0040000,0040000,0040000 diff --git a/libc/sysv/consts/S_IFIFO.S b/libc/sysv/consts/S_IFIFO.S deleted file mode 100644 index 634433d4f..000000000 --- a/libc/sysv/consts/S_IFIFO.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IFIFO,0010000,0010000,0010000,0010000,0010000,0010000 diff --git a/libc/sysv/consts/S_IFLNK.S b/libc/sysv/consts/S_IFLNK.S deleted file mode 100644 index 7f07c7498..000000000 --- a/libc/sysv/consts/S_IFLNK.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IFLNK,0120000,0120000,0120000,0120000,0120000,0120000 diff --git a/libc/sysv/consts/S_IFMT.S b/libc/sysv/consts/S_IFMT.S deleted file mode 100644 index af076b5ae..000000000 --- a/libc/sysv/consts/S_IFMT.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IFMT,0170000,0170000,0170000,0170000,0170000,0170000 diff --git a/libc/sysv/consts/S_IFREG.S b/libc/sysv/consts/S_IFREG.S deleted file mode 100644 index 8c859e78c..000000000 --- a/libc/sysv/consts/S_IFREG.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IFREG,0100000,0100000,0100000,0100000,0100000,0100000 diff --git a/libc/sysv/consts/S_IFSOCK.S b/libc/sysv/consts/S_IFSOCK.S deleted file mode 100644 index 3cc80067e..000000000 --- a/libc/sysv/consts/S_IFSOCK.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IFSOCK,0140000,0140000,0140000,0140000,0140000,0140000 diff --git a/libc/sysv/consts/S_IREAD.S b/libc/sysv/consts/S_IREAD.S deleted file mode 100644 index 5e0bee1c4..000000000 --- a/libc/sysv/consts/S_IREAD.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IREAD,0000400,0000400,0000400,0000400,0000400,0000400 diff --git a/libc/sysv/consts/S_IRGRP.S b/libc/sysv/consts/S_IRGRP.S deleted file mode 100644 index ad9f3a6f8..000000000 --- a/libc/sysv/consts/S_IRGRP.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRGRP,0000040,0000040,0000040,0000040,0000040,0000040 diff --git a/libc/sysv/consts/S_IROTH.S b/libc/sysv/consts/S_IROTH.S deleted file mode 100644 index 6179fbf38..000000000 --- a/libc/sysv/consts/S_IROTH.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IROTH,0000004,0000004,0000004,0000004,0000004,0000004 diff --git a/libc/sysv/consts/S_IRUSR.S b/libc/sysv/consts/S_IRUSR.S deleted file mode 100644 index 7720d0f60..000000000 --- a/libc/sysv/consts/S_IRUSR.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRUSR,0000400,0000400,0000400,0000400,0000400,0000400 diff --git a/libc/sysv/consts/S_IRWXG.S b/libc/sysv/consts/S_IRWXG.S deleted file mode 100644 index e35589566..000000000 --- a/libc/sysv/consts/S_IRWXG.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRWXG,0000070,0000070,0000070,0000070,0000070,0000070 diff --git a/libc/sysv/consts/S_IRWXO.S b/libc/sysv/consts/S_IRWXO.S deleted file mode 100644 index c9a4db418..000000000 --- a/libc/sysv/consts/S_IRWXO.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRWXO,0000007,0000007,0000007,0000007,0000007,0000007 diff --git a/libc/sysv/consts/S_IRWXU.S b/libc/sysv/consts/S_IRWXU.S deleted file mode 100644 index 3a291a499..000000000 --- a/libc/sysv/consts/S_IRWXU.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IRWXU,0000700,0000700,0000700,0000700,0000700,0000700 diff --git a/libc/sysv/consts/S_ISGID.S b/libc/sysv/consts/S_ISGID.S deleted file mode 100644 index 108508726..000000000 --- a/libc/sysv/consts/S_ISGID.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_ISGID,0002000,0002000,0002000,0002000,0002000,0002000 diff --git a/libc/sysv/consts/S_ISUID.S b/libc/sysv/consts/S_ISUID.S deleted file mode 100644 index 170183946..000000000 --- a/libc/sysv/consts/S_ISUID.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_ISUID,0004000,0004000,0004000,0004000,0004000,0004000 diff --git a/libc/sysv/consts/S_ISVTX.S b/libc/sysv/consts/S_ISVTX.S deleted file mode 100644 index 33636aff5..000000000 --- a/libc/sysv/consts/S_ISVTX.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_ISVTX,0001000,0001000,0001000,0001000,0001000,0001000 diff --git a/libc/sysv/consts/S_IWGRP.S b/libc/sysv/consts/S_IWGRP.S deleted file mode 100644 index 27dd51e4c..000000000 --- a/libc/sysv/consts/S_IWGRP.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IWGRP,0000020,0000020,0000020,0000020,0000020,0000020 diff --git a/libc/sysv/consts/S_IWOTH.S b/libc/sysv/consts/S_IWOTH.S deleted file mode 100644 index 61e7b7ae8..000000000 --- a/libc/sysv/consts/S_IWOTH.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IWOTH,0000002,0000002,0000002,0000002,0000002,0000002 diff --git a/libc/sysv/consts/S_IWRITE.S b/libc/sysv/consts/S_IWRITE.S deleted file mode 100644 index df2360188..000000000 --- a/libc/sysv/consts/S_IWRITE.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IWRITE,0000200,0000200,0000200,0000200,0000200,0000200 diff --git a/libc/sysv/consts/S_IWUSR.S b/libc/sysv/consts/S_IWUSR.S deleted file mode 100644 index 7df8df706..000000000 --- a/libc/sysv/consts/S_IWUSR.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IWUSR,0000200,0000200,0000200,0000200,0000200,0000200 diff --git a/libc/sysv/consts/S_IXGRP.S b/libc/sysv/consts/S_IXGRP.S deleted file mode 100644 index f23c82907..000000000 --- a/libc/sysv/consts/S_IXGRP.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IXGRP,0000010,0000010,0000010,0000010,0000010,0000010 diff --git a/libc/sysv/consts/S_IXOTH.S b/libc/sysv/consts/S_IXOTH.S deleted file mode 100644 index ff3cc2474..000000000 --- a/libc/sysv/consts/S_IXOTH.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IXOTH,0000001,0000001,0000001,0000001,0000001,0000001 diff --git a/libc/sysv/consts/S_IXUSR.S b/libc/sysv/consts/S_IXUSR.S deleted file mode 100644 index fb7f231b5..000000000 --- a/libc/sysv/consts/S_IXUSR.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon stat,S_IXUSR,0000100,0000100,0000100,0000100,0000100,0000100 diff --git a/libc/sysv/consts/WHOLE_SECONDS.S b/libc/sysv/consts/WHOLE_SECONDS.S deleted file mode 100644 index 161ad743f..000000000 --- a/libc/sysv/consts/WHOLE_SECONDS.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/consts/syscon.internal.h" -.syscon prsnlty,WHOLE_SECONDS,0x2000000,0,0,0,0,0 diff --git a/libc/sysv/consts/_posix2.h b/libc/sysv/consts/_posix2.h deleted file mode 100644 index 9a0a08200..000000000 --- a/libc/sysv/consts/_posix2.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS__POSIX2_H_ -#define COSMOPOLITAN_LIBC_SYSV_CONSTS__POSIX2_H_ -#include "libc/runtime/symbolic.h" - -#define _POSIX2_BC_BASE_MAX SYMBOLIC(_POSIX2_BC_BASE_MAX) -#define _POSIX2_BC_DIM_MAX SYMBOLIC(_POSIX2_BC_DIM_MAX) -#define _POSIX2_BC_SCALE_MAX SYMBOLIC(_POSIX2_BC_SCALE_MAX) -#define _POSIX2_BC_STRING_MAX SYMBOLIC(_POSIX2_BC_STRING_MAX) -#define _POSIX2_CHARCLASS_NAME_MAX SYMBOLIC(_POSIX2_CHARCLASS_NAME_MAX) -#define _POSIX2_COLL_WEIGHTS_MAX SYMBOLIC(_POSIX2_COLL_WEIGHTS_MAX) -#define _POSIX2_C_BIND SYMBOLIC(_POSIX2_C_BIND) -#define _POSIX2_EXPR_NEST_MAX SYMBOLIC(_POSIX2_EXPR_NEST_MAX) -#define _POSIX2_LINE_MAX SYMBOLIC(_POSIX2_LINE_MAX) -#define _POSIX2_RE_DUP_MAX SYMBOLIC(_POSIX2_RE_DUP_MAX) -#define _POSIX2_VERSION SYMBOLIC(_POSIX2_VERSION) - -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern const long _POSIX2_BC_BASE_MAX; -extern const long _POSIX2_BC_DIM_MAX; -extern const long _POSIX2_BC_SCALE_MAX; -extern const long _POSIX2_BC_STRING_MAX; -extern const long _POSIX2_CHARCLASS_NAME_MAX; -extern const long _POSIX2_COLL_WEIGHTS_MAX; -extern const long _POSIX2_C_BIND; -extern const long _POSIX2_EXPR_NEST_MAX; -extern const long _POSIX2_LINE_MAX; -extern const long _POSIX2_RE_DUP_MAX; -extern const long _POSIX2_VERSION; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS__POSIX2_H_ */ diff --git a/libc/sysv/consts/map.h b/libc/sysv/consts/map.h index 725ffac82..028aeaf9a 100644 --- a/libc/sysv/consts/map.h +++ b/libc/sysv/consts/map.h @@ -12,13 +12,17 @@ extern const long MAP_DENYWRITE; extern const long MAP_EXECUTABLE; extern const long MAP_FILE; extern const long MAP_FIXED; +extern const long MAP_FIXED_NOREPLACE; extern const long MAP_GROWSDOWN; +extern const long MAP_HASSEMAPHORE; extern const long MAP_HUGETLB; extern const long MAP_HUGE_MASK; extern const long MAP_HUGE_SHIFT; +extern const long MAP_INHERIT; extern const long MAP_LOCKED; extern const long MAP_NONBLOCK; extern const long MAP_NORESERVE; +extern const long MAP_NOSYNC; extern const long MAP_POPULATE; extern const long MAP_PRIVATE; extern const long MAP_SHARED; @@ -26,28 +30,30 @@ extern const long MAP_SHARED; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#define MAP_FILE 0 -#define MAP_SHARED 1 -#define MAP_PRIVATE 2 -#define MAP_STACK 6 -#define MAP_TYPE 15 -#define MAP_FIXED 16 -#define MAP_FIXED_NOREPLACE 0x8000000 +#define MAP_FILE 0 +#define MAP_SHARED 1 +#define MAP_PRIVATE 2 +#define MAP_STACK 6 +#define MAP_TYPE 15 +#define MAP_FIXED 16 -#define MAP_32BIT SYMBOLIC(MAP_32BIT) -#define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS) -#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL) -#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL) -#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE) -#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE) -#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN) -#define MAP_HUGETLB SYMBOLIC(MAP_HUGETLB) -#define MAP_HUGE_MASK SYMBOLIC(MAP_HUGE_MASK) -#define MAP_HUGE_SHIFT SYMBOLIC(MAP_HUGE_SHIFT) -#define MAP_LOCKED SYMBOLIC(MAP_LOCKED) -#define MAP_NONBLOCK SYMBOLIC(MAP_NONBLOCK) -#define MAP_NORESERVE SYMBOLIC(MAP_NORESERVE) -#define MAP_POPULATE SYMBOLIC(MAP_POPULATE) +#define MAP_32BIT SYMBOLIC(MAP_32BIT) +#define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS) +#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL) +#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE) +#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE) +#define MAP_FIXED_NOREPLACE SYMBOLIC(MAP_FIXED_NOREPLACE) +#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN) +#define MAP_HASSEMAPHORE SYMBOLIC(MAP_HASSEMAPHORE) +#define MAP_HUGETLB SYMBOLIC(MAP_HUGETLB) +#define MAP_HUGE_MASK SYMBOLIC(MAP_HUGE_MASK) +#define MAP_HUGE_SHIFT SYMBOLIC(MAP_HUGE_SHIFT) +#define MAP_INHERIT SYMBOLIC(MAP_INHERIT) +#define MAP_LOCKED SYMBOLIC(MAP_LOCKED) +#define MAP_NONBLOCK SYMBOLIC(MAP_NONBLOCK) +#define MAP_NORESERVE SYMBOLIC(MAP_NORESERVE) +#define MAP_NOSYNC SYMBOLIC(MAP_NOSYNC) +#define MAP_POPULATE SYMBOLIC(MAP_POPULATE) #define MAP_ANON MAP_ANONYMOUS #define MAP_NOCORE MAP_CONCEAL diff --git a/libc/sysv/consts/personality.h b/libc/sysv/consts/personality.h index 432f53a0e..00b60d6c6 100644 --- a/libc/sysv/consts/personality.h +++ b/libc/sysv/consts/personality.h @@ -1,34 +1,17 @@ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ #include "libc/runtime/symbolic.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ -extern const long ADDR_COMPAT_LAYOUT; -extern const long READ_IMPLIES_EXEC; -extern const long ADDR_LIMIT_3GB; -extern const long FDPIC_FUNCPTRS; -extern const long STICKY_TIMEOUTS; -extern const long MMAP_PAGE_ZERO; -extern const long ADDR_LIMIT_32BIT; -extern const long WHOLE_SECONDS; -extern const long ADDR_NO_RANDOMIZE; -extern const long SHORT_INODE; -extern const long UNAME26; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ - -#define ADDR_COMPAT_LAYOUT SYMBOLIC(ADDR_COMPAT_LAYOUT) -#define READ_IMPLIES_EXEC SYMBOLIC(READ_IMPLIES_EXEC) -#define ADDR_LIMIT_3GB SYMBOLIC(ADDR_LIMIT_3GB) -#define FDPIC_FUNCPTRS SYMBOLIC(FDPIC_FUNCPTRS) -#define STICKY_TIMEOUTS SYMBOLIC(STICKY_TIMEOUTS) -#define MMAP_PAGE_ZERO SYMBOLIC(MMAP_PAGE_ZERO) -#define ADDR_LIMIT_32BIT SYMBOLIC(ADDR_LIMIT_32BIT) -#define WHOLE_SECONDS SYMBOLIC(WHOLE_SECONDS) -#define ADDR_NO_RANDOMIZE SYMBOLIC(ADDR_NO_RANDOMIZE) -#define SHORT_INODE SYMBOLIC(SHORT_INODE) -#define UNAME26 SYMBOLIC(UNAME26) +#define ADDR_COMPAT_LAYOUT 0x0200000 +#define READ_IMPLIES_EXEC 0x0400000 +#define ADDR_LIMIT_3GB 0x8000000 +#define FDPIC_FUNCPTRS 0x0080000 +#define STICKY_TIMEOUTS 0x4000000 +#define MMAP_PAGE_ZERO 0x0100000 +#define ADDR_LIMIT_32BIT 0x0800000 +#define WHOLE_SECONDS 0x2000000 +#define ADDR_NO_RANDOMIZE 0x0040000 +#define SHORT_INODE 0x1000000 +#define UNAME26 0x0020000 #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_PERSONALITY_H_ */ diff --git a/libc/sysv/consts/ss.h b/libc/sysv/consts/ss.h index 1656da739..a2414c41a 100644 --- a/libc/sysv/consts/ss.h +++ b/libc/sysv/consts/ss.h @@ -3,13 +3,16 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +extern const long SIGSTKSZ; +extern const long MINSIGSTKSZ; extern const long SS_DISABLE; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#define SIGSTKSZ STACKSIZE -#define SS_ONSTACK 1 -#define SS_DISABLE SS_DISABLE +#define SIGSTKSZ STACKSIZE +#define MINSIGSTKSZ 32768 +#define SS_ONSTACK 1 +#define SS_DISABLE SS_DISABLE #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_SS_H_ */ diff --git a/libc/sysv/errfuns.h b/libc/sysv/errfuns.h index 5a0fc56e9..efdc02c37 100644 --- a/libc/sysv/errfuns.h +++ b/libc/sysv/errfuns.h @@ -154,11 +154,14 @@ intptr_t erfkill(void) relegated; intptr_t ehwpoison(void) relegated; #if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__) -#define __ERRFUN(FUNC) \ - ({ \ - intptr_t NegOne; \ - asm("call\t" FUNC : "=a"(NegOne), "=m"(errno)); \ - NegOne; \ +#define __ERRFUN(FUNC) \ + ({ \ + intptr_t NegOne; \ + asm volatile("call\t" FUNC \ + : "=a"(NegOne) \ + : /* no outputs */ \ + : "rcx", "memory"); \ + NegOne; \ }) #define einval() __ERRFUN("einval") #define eperm() __ERRFUN("eperm") diff --git a/libc/sysv/errfuns/e2big.S b/libc/sysv/errfuns/e2big.S index a68faf687..3dee651a0 100644 --- a/libc/sysv/errfuns/e2big.S +++ b/libc/sysv/errfuns/e2big.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + e2big: .leafprologue - .profilable - mov E2BIG(%rip),%eax - mov %eax,errno(%rip) + mov E2BIG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eacces.S b/libc/sysv/errfuns/eacces.S index 4c9bdab5c..f0c068a4a 100644 --- a/libc/sysv/errfuns/eacces.S +++ b/libc/sysv/errfuns/eacces.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eacces: .leafprologue - .profilable - mov EACCES(%rip),%eax - mov %eax,errno(%rip) + mov EACCES(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eaddrinuse.S b/libc/sysv/errfuns/eaddrinuse.S index d6085da6c..88ed82ddf 100644 --- a/libc/sysv/errfuns/eaddrinuse.S +++ b/libc/sysv/errfuns/eaddrinuse.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eaddrinuse: .leafprologue - .profilable - mov EADDRINUSE(%rip),%eax - mov %eax,errno(%rip) + mov EADDRINUSE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eaddrnotavail.S b/libc/sysv/errfuns/eaddrnotavail.S index 590893053..e5d7cd459 100644 --- a/libc/sysv/errfuns/eaddrnotavail.S +++ b/libc/sysv/errfuns/eaddrnotavail.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eaddrnotavail: .leafprologue - .profilable - mov EADDRNOTAVAIL(%rip),%eax - mov %eax,errno(%rip) + mov EADDRNOTAVAIL(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eadv.S b/libc/sysv/errfuns/eadv.S index a29be6ad8..2ec5fad55 100644 --- a/libc/sysv/errfuns/eadv.S +++ b/libc/sysv/errfuns/eadv.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eadv: .leafprologue - .profilable - mov EADV(%rip),%eax - mov %eax,errno(%rip) + mov EADV(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eafnosupport.S b/libc/sysv/errfuns/eafnosupport.S index 8eb3fd1e6..bb61fdf6e 100644 --- a/libc/sysv/errfuns/eafnosupport.S +++ b/libc/sysv/errfuns/eafnosupport.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eafnosupport: .leafprologue - .profilable - mov EAFNOSUPPORT(%rip),%eax - mov %eax,errno(%rip) + mov EAFNOSUPPORT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eagain.S b/libc/sysv/errfuns/eagain.S index 28e7464c1..83ae5326a 100644 --- a/libc/sysv/errfuns/eagain.S +++ b/libc/sysv/errfuns/eagain.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eagain: .leafprologue - .profilable - mov EAGAIN(%rip),%eax - mov %eax,errno(%rip) + mov EAGAIN(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ealready.S b/libc/sysv/errfuns/ealready.S index 34921de3d..901053e4c 100644 --- a/libc/sysv/errfuns/ealready.S +++ b/libc/sysv/errfuns/ealready.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ealready: .leafprologue - .profilable - mov EALREADY(%rip),%eax - mov %eax,errno(%rip) + mov EALREADY(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ebade.S b/libc/sysv/errfuns/ebade.S index d736ef2a0..bba37cbff 100644 --- a/libc/sysv/errfuns/ebade.S +++ b/libc/sysv/errfuns/ebade.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ebade: .leafprologue - .profilable - mov EBADE(%rip),%eax - mov %eax,errno(%rip) + mov EBADE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ebadf.S b/libc/sysv/errfuns/ebadf.S index b07b871e6..faf167f73 100644 --- a/libc/sysv/errfuns/ebadf.S +++ b/libc/sysv/errfuns/ebadf.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ebadf: .leafprologue - .profilable - mov EBADF(%rip),%eax - mov %eax,errno(%rip) + mov EBADF(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ebadfd.S b/libc/sysv/errfuns/ebadfd.S index f81b9725e..8b05e7210 100644 --- a/libc/sysv/errfuns/ebadfd.S +++ b/libc/sysv/errfuns/ebadfd.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ebadfd: .leafprologue - .profilable - mov EBADFD(%rip),%eax - mov %eax,errno(%rip) + mov EBADFD(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ebadmsg.S b/libc/sysv/errfuns/ebadmsg.S index 8d95e7381..5a4560b5e 100644 --- a/libc/sysv/errfuns/ebadmsg.S +++ b/libc/sysv/errfuns/ebadmsg.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ebadmsg: .leafprologue - .profilable - mov EBADMSG(%rip),%eax - mov %eax,errno(%rip) + mov EBADMSG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ebadr.S b/libc/sysv/errfuns/ebadr.S index 69cbfbbe6..7822e2997 100644 --- a/libc/sysv/errfuns/ebadr.S +++ b/libc/sysv/errfuns/ebadr.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ebadr: .leafprologue - .profilable - mov EBADR(%rip),%eax - mov %eax,errno(%rip) + mov EBADR(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ebadrqc.S b/libc/sysv/errfuns/ebadrqc.S index 0a955024a..4ebe49fc0 100644 --- a/libc/sysv/errfuns/ebadrqc.S +++ b/libc/sysv/errfuns/ebadrqc.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ebadrqc: .leafprologue - .profilable - mov EBADRQC(%rip),%eax - mov %eax,errno(%rip) + mov EBADRQC(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ebadslt.S b/libc/sysv/errfuns/ebadslt.S index a32b67f81..389f326b3 100644 --- a/libc/sysv/errfuns/ebadslt.S +++ b/libc/sysv/errfuns/ebadslt.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ebadslt: .leafprologue - .profilable - mov EBADSLT(%rip),%eax - mov %eax,errno(%rip) + mov EBADSLT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ebusy.S b/libc/sysv/errfuns/ebusy.S index 064ef7fa5..0d10fbe26 100644 --- a/libc/sysv/errfuns/ebusy.S +++ b/libc/sysv/errfuns/ebusy.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ebusy: .leafprologue - .profilable - mov EBUSY(%rip),%eax - mov %eax,errno(%rip) + mov EBUSY(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ecanceled.S b/libc/sysv/errfuns/ecanceled.S index cfacf15ed..c1182c9c2 100644 --- a/libc/sysv/errfuns/ecanceled.S +++ b/libc/sysv/errfuns/ecanceled.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ecanceled: .leafprologue - .profilable - mov ECANCELED(%rip),%eax - mov %eax,errno(%rip) + mov ECANCELED(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/echild.S b/libc/sysv/errfuns/echild.S index a276788e9..fb8905559 100644 --- a/libc/sysv/errfuns/echild.S +++ b/libc/sysv/errfuns/echild.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + echild: .leafprologue - .profilable - mov ECHILD(%rip),%eax - mov %eax,errno(%rip) + mov ECHILD(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/echrng.S b/libc/sysv/errfuns/echrng.S index ef21edf0e..272ca1fc5 100644 --- a/libc/sysv/errfuns/echrng.S +++ b/libc/sysv/errfuns/echrng.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + echrng: .leafprologue - .profilable - mov ECHRNG(%rip),%eax - mov %eax,errno(%rip) + mov ECHRNG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ecomm.S b/libc/sysv/errfuns/ecomm.S index 18d5f0f45..159a3057b 100644 --- a/libc/sysv/errfuns/ecomm.S +++ b/libc/sysv/errfuns/ecomm.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ecomm: .leafprologue - .profilable - mov ECOMM(%rip),%eax - mov %eax,errno(%rip) + mov ECOMM(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/econnaborted.S b/libc/sysv/errfuns/econnaborted.S index 40bce5cf8..a3af8c15d 100644 --- a/libc/sysv/errfuns/econnaborted.S +++ b/libc/sysv/errfuns/econnaborted.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + econnaborted: .leafprologue - .profilable - mov ECONNABORTED(%rip),%eax - mov %eax,errno(%rip) + mov ECONNABORTED(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/econnrefused.S b/libc/sysv/errfuns/econnrefused.S index f63ff40ae..293e09244 100644 --- a/libc/sysv/errfuns/econnrefused.S +++ b/libc/sysv/errfuns/econnrefused.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + econnrefused: .leafprologue - .profilable - mov ECONNREFUSED(%rip),%eax - mov %eax,errno(%rip) + mov ECONNREFUSED(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/econnreset.S b/libc/sysv/errfuns/econnreset.S index 41916df81..da02e7656 100644 --- a/libc/sysv/errfuns/econnreset.S +++ b/libc/sysv/errfuns/econnreset.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + econnreset: .leafprologue - .profilable - mov ECONNRESET(%rip),%eax - mov %eax,errno(%rip) + mov ECONNRESET(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/edeadlk.S b/libc/sysv/errfuns/edeadlk.S index fac28d473..e38afcad5 100644 --- a/libc/sysv/errfuns/edeadlk.S +++ b/libc/sysv/errfuns/edeadlk.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + edeadlk: .leafprologue - .profilable - mov EDEADLK(%rip),%eax - mov %eax,errno(%rip) + mov EDEADLK(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/edestaddrreq.S b/libc/sysv/errfuns/edestaddrreq.S index d395ecded..01db20eca 100644 --- a/libc/sysv/errfuns/edestaddrreq.S +++ b/libc/sysv/errfuns/edestaddrreq.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + edestaddrreq: .leafprologue - .profilable - mov EDESTADDRREQ(%rip),%eax - mov %eax,errno(%rip) + mov EDESTADDRREQ(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/edom.S b/libc/sysv/errfuns/edom.S index 2981c5002..97fdd0351 100644 --- a/libc/sysv/errfuns/edom.S +++ b/libc/sysv/errfuns/edom.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + edom: .leafprologue - .profilable - mov EDOM(%rip),%eax - mov %eax,errno(%rip) + mov EDOM(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/edotdot.S b/libc/sysv/errfuns/edotdot.S index 8995b7b27..cf9188238 100644 --- a/libc/sysv/errfuns/edotdot.S +++ b/libc/sysv/errfuns/edotdot.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + edotdot: .leafprologue - .profilable - mov EDOTDOT(%rip),%eax - mov %eax,errno(%rip) + mov EDOTDOT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/edquot.S b/libc/sysv/errfuns/edquot.S index f8952ead0..f41ed9d9a 100644 --- a/libc/sysv/errfuns/edquot.S +++ b/libc/sysv/errfuns/edquot.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + edquot: .leafprologue - .profilable - mov EDQUOT(%rip),%eax - mov %eax,errno(%rip) + mov EDQUOT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eexist.S b/libc/sysv/errfuns/eexist.S index 63d376c65..eb33d9a4a 100644 --- a/libc/sysv/errfuns/eexist.S +++ b/libc/sysv/errfuns/eexist.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eexist: .leafprologue - .profilable - mov EEXIST(%rip),%eax - mov %eax,errno(%rip) + mov EEXIST(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/efault.S b/libc/sysv/errfuns/efault.S index a96bb91bb..6f21320b0 100644 --- a/libc/sysv/errfuns/efault.S +++ b/libc/sysv/errfuns/efault.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + efault: .leafprologue - .profilable - mov EFAULT(%rip),%eax - mov %eax,errno(%rip) + mov EFAULT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/efbig.S b/libc/sysv/errfuns/efbig.S index b54c708e1..1c445d2e0 100644 --- a/libc/sysv/errfuns/efbig.S +++ b/libc/sysv/errfuns/efbig.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + efbig: .leafprologue - .profilable - mov EFBIG(%rip),%eax - mov %eax,errno(%rip) + mov EFBIG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ehostdown.S b/libc/sysv/errfuns/ehostdown.S index 353efb7d3..a33bf3d23 100644 --- a/libc/sysv/errfuns/ehostdown.S +++ b/libc/sysv/errfuns/ehostdown.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ehostdown: .leafprologue - .profilable - mov EHOSTDOWN(%rip),%eax - mov %eax,errno(%rip) + mov EHOSTDOWN(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ehostunreach.S b/libc/sysv/errfuns/ehostunreach.S index 822ebf203..9de92d917 100644 --- a/libc/sysv/errfuns/ehostunreach.S +++ b/libc/sysv/errfuns/ehostunreach.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ehostunreach: .leafprologue - .profilable - mov EHOSTUNREACH(%rip),%eax - mov %eax,errno(%rip) + mov EHOSTUNREACH(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ehwpoison.S b/libc/sysv/errfuns/ehwpoison.S index 4a802b07f..24103a255 100644 --- a/libc/sysv/errfuns/ehwpoison.S +++ b/libc/sysv/errfuns/ehwpoison.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ehwpoison: .leafprologue - .profilable - mov EHWPOISON(%rip),%eax - mov %eax,errno(%rip) + mov EHWPOISON(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eidrm.S b/libc/sysv/errfuns/eidrm.S index 7d8559b39..8b90827df 100644 --- a/libc/sysv/errfuns/eidrm.S +++ b/libc/sysv/errfuns/eidrm.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eidrm: .leafprologue - .profilable - mov EIDRM(%rip),%eax - mov %eax,errno(%rip) + mov EIDRM(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eilseq.S b/libc/sysv/errfuns/eilseq.S index ce61f2d5e..689becc06 100644 --- a/libc/sysv/errfuns/eilseq.S +++ b/libc/sysv/errfuns/eilseq.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eilseq: .leafprologue - .profilable - mov EILSEQ(%rip),%eax - mov %eax,errno(%rip) + mov EILSEQ(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/einprogress.S b/libc/sysv/errfuns/einprogress.S index 382cfdacd..b0d7549c6 100644 --- a/libc/sysv/errfuns/einprogress.S +++ b/libc/sysv/errfuns/einprogress.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + einprogress: .leafprologue - .profilable - mov EINPROGRESS(%rip),%eax - mov %eax,errno(%rip) + mov EINPROGRESS(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eintr.S b/libc/sysv/errfuns/eintr.S index cc85d0861..9836589f8 100644 --- a/libc/sysv/errfuns/eintr.S +++ b/libc/sysv/errfuns/eintr.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eintr: .leafprologue - .profilable - mov EINTR(%rip),%eax - mov %eax,errno(%rip) + mov EINTR(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/einval.S b/libc/sysv/errfuns/einval.S index 76c4c3cfa..83eb007d3 100644 --- a/libc/sysv/errfuns/einval.S +++ b/libc/sysv/errfuns/einval.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + einval: .leafprologue - .profilable - mov EINVAL(%rip),%eax - mov %eax,errno(%rip) + mov EINVAL(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eio.S b/libc/sysv/errfuns/eio.S index b1c6039f1..fcedc61d1 100644 --- a/libc/sysv/errfuns/eio.S +++ b/libc/sysv/errfuns/eio.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eio: .leafprologue - .profilable - mov EIO(%rip),%eax - mov %eax,errno(%rip) + mov EIO(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eisconn.S b/libc/sysv/errfuns/eisconn.S index 59ecc99fd..65ba958cf 100644 --- a/libc/sysv/errfuns/eisconn.S +++ b/libc/sysv/errfuns/eisconn.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eisconn: .leafprologue - .profilable - mov EISCONN(%rip),%eax - mov %eax,errno(%rip) + mov EISCONN(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eisdir.S b/libc/sysv/errfuns/eisdir.S index 6b98de9c1..514e60049 100644 --- a/libc/sysv/errfuns/eisdir.S +++ b/libc/sysv/errfuns/eisdir.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eisdir: .leafprologue - .profilable - mov EISDIR(%rip),%eax - mov %eax,errno(%rip) + mov EISDIR(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eisnam.S b/libc/sysv/errfuns/eisnam.S index 228efd6b6..b4d5af446 100644 --- a/libc/sysv/errfuns/eisnam.S +++ b/libc/sysv/errfuns/eisnam.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eisnam: .leafprologue - .profilable - mov EISNAM(%rip),%eax - mov %eax,errno(%rip) + mov EISNAM(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ekeyexpired.S b/libc/sysv/errfuns/ekeyexpired.S index f7c5eaf1d..4aa6dae18 100644 --- a/libc/sysv/errfuns/ekeyexpired.S +++ b/libc/sysv/errfuns/ekeyexpired.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ekeyexpired: .leafprologue - .profilable - mov EKEYEXPIRED(%rip),%eax - mov %eax,errno(%rip) + mov EKEYEXPIRED(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ekeyrejected.S b/libc/sysv/errfuns/ekeyrejected.S index e2fa25a9d..92f289082 100644 --- a/libc/sysv/errfuns/ekeyrejected.S +++ b/libc/sysv/errfuns/ekeyrejected.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ekeyrejected: .leafprologue - .profilable - mov EKEYREJECTED(%rip),%eax - mov %eax,errno(%rip) + mov EKEYREJECTED(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/ekeyrevoked.S b/libc/sysv/errfuns/ekeyrevoked.S index 86a6e1dfa..4d2afd375 100644 --- a/libc/sysv/errfuns/ekeyrevoked.S +++ b/libc/sysv/errfuns/ekeyrevoked.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + ekeyrevoked: .leafprologue - .profilable - mov EKEYREVOKED(%rip),%eax - mov %eax,errno(%rip) + mov EKEYREVOKED(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/el2hlt.S b/libc/sysv/errfuns/el2hlt.S index 73e8d895e..e804afa80 100644 --- a/libc/sysv/errfuns/el2hlt.S +++ b/libc/sysv/errfuns/el2hlt.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + el2hlt: .leafprologue - .profilable - mov EL2HLT(%rip),%eax - mov %eax,errno(%rip) + mov EL2HLT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/el2nsync.S b/libc/sysv/errfuns/el2nsync.S index dcf62b85e..a48b7b518 100644 --- a/libc/sysv/errfuns/el2nsync.S +++ b/libc/sysv/errfuns/el2nsync.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + el2nsync: .leafprologue - .profilable - mov EL2NSYNC(%rip),%eax - mov %eax,errno(%rip) + mov EL2NSYNC(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/el3hlt.S b/libc/sysv/errfuns/el3hlt.S index 103ab8ddb..0650f2e7d 100644 --- a/libc/sysv/errfuns/el3hlt.S +++ b/libc/sysv/errfuns/el3hlt.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + el3hlt: .leafprologue - .profilable - mov EL3HLT(%rip),%eax - mov %eax,errno(%rip) + mov EL3HLT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/el3rst.S b/libc/sysv/errfuns/el3rst.S index 7e51df535..a0e55575a 100644 --- a/libc/sysv/errfuns/el3rst.S +++ b/libc/sysv/errfuns/el3rst.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + el3rst: .leafprologue - .profilable - mov EL3RST(%rip),%eax - mov %eax,errno(%rip) + mov EL3RST(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/elibacc.S b/libc/sysv/errfuns/elibacc.S index d17542dce..efbd75f3c 100644 --- a/libc/sysv/errfuns/elibacc.S +++ b/libc/sysv/errfuns/elibacc.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + elibacc: .leafprologue - .profilable - mov ELIBACC(%rip),%eax - mov %eax,errno(%rip) + mov ELIBACC(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/elibbad.S b/libc/sysv/errfuns/elibbad.S index 8abe0bb51..19a7b596c 100644 --- a/libc/sysv/errfuns/elibbad.S +++ b/libc/sysv/errfuns/elibbad.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + elibbad: .leafprologue - .profilable - mov ELIBBAD(%rip),%eax - mov %eax,errno(%rip) + mov ELIBBAD(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/elibexec.S b/libc/sysv/errfuns/elibexec.S index f28be8fdd..4e28fa32b 100644 --- a/libc/sysv/errfuns/elibexec.S +++ b/libc/sysv/errfuns/elibexec.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + elibexec: .leafprologue - .profilable - mov ELIBEXEC(%rip),%eax - mov %eax,errno(%rip) + mov ELIBEXEC(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/elibmax.S b/libc/sysv/errfuns/elibmax.S index 607093b3a..b14515535 100644 --- a/libc/sysv/errfuns/elibmax.S +++ b/libc/sysv/errfuns/elibmax.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + elibmax: .leafprologue - .profilable - mov ELIBMAX(%rip),%eax - mov %eax,errno(%rip) + mov ELIBMAX(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/elibscn.S b/libc/sysv/errfuns/elibscn.S index c1b28eeb3..4781f239d 100644 --- a/libc/sysv/errfuns/elibscn.S +++ b/libc/sysv/errfuns/elibscn.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + elibscn: .leafprologue - .profilable - mov ELIBSCN(%rip),%eax - mov %eax,errno(%rip) + mov ELIBSCN(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/elnrng.S b/libc/sysv/errfuns/elnrng.S index b7693fb06..25cc0ef0d 100644 --- a/libc/sysv/errfuns/elnrng.S +++ b/libc/sysv/errfuns/elnrng.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + elnrng: .leafprologue - .profilable - mov ELNRNG(%rip),%eax - mov %eax,errno(%rip) + mov ELNRNG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eloop.S b/libc/sysv/errfuns/eloop.S index 6fdc0c4fa..3de12f39f 100644 --- a/libc/sysv/errfuns/eloop.S +++ b/libc/sysv/errfuns/eloop.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eloop: .leafprologue - .profilable - mov ELOOP(%rip),%eax - mov %eax,errno(%rip) + mov ELOOP(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/emediumtype.S b/libc/sysv/errfuns/emediumtype.S index 40db57330..a3d7048ce 100644 --- a/libc/sysv/errfuns/emediumtype.S +++ b/libc/sysv/errfuns/emediumtype.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + emediumtype: .leafprologue - .profilable - mov EMEDIUMTYPE(%rip),%eax - mov %eax,errno(%rip) + mov EMEDIUMTYPE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/emfile.S b/libc/sysv/errfuns/emfile.S index eff8409c3..f89eb0153 100644 --- a/libc/sysv/errfuns/emfile.S +++ b/libc/sysv/errfuns/emfile.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + emfile: .leafprologue - .profilable - mov EMFILE(%rip),%eax - mov %eax,errno(%rip) + mov EMFILE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/emlink.S b/libc/sysv/errfuns/emlink.S index 5b3b21d93..2921a6f31 100644 --- a/libc/sysv/errfuns/emlink.S +++ b/libc/sysv/errfuns/emlink.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + emlink: .leafprologue - .profilable - mov EMLINK(%rip),%eax - mov %eax,errno(%rip) + mov EMLINK(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/emsgsize.S b/libc/sysv/errfuns/emsgsize.S index 46231a27f..4553b3c89 100644 --- a/libc/sysv/errfuns/emsgsize.S +++ b/libc/sysv/errfuns/emsgsize.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + emsgsize: .leafprologue - .profilable - mov EMSGSIZE(%rip),%eax - mov %eax,errno(%rip) + mov EMSGSIZE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/emultihop.S b/libc/sysv/errfuns/emultihop.S index b91426f36..4b28d701b 100644 --- a/libc/sysv/errfuns/emultihop.S +++ b/libc/sysv/errfuns/emultihop.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + emultihop: .leafprologue - .profilable - mov EMULTIHOP(%rip),%eax - mov %eax,errno(%rip) + mov EMULTIHOP(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enametoolong.S b/libc/sysv/errfuns/enametoolong.S index a5829366d..2fc0821bb 100644 --- a/libc/sysv/errfuns/enametoolong.S +++ b/libc/sysv/errfuns/enametoolong.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enametoolong: .leafprologue - .profilable - mov ENAMETOOLONG(%rip),%eax - mov %eax,errno(%rip) + mov ENAMETOOLONG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enavail.S b/libc/sysv/errfuns/enavail.S index 521f690c5..130177053 100644 --- a/libc/sysv/errfuns/enavail.S +++ b/libc/sysv/errfuns/enavail.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enavail: .leafprologue - .profilable - mov ENAVAIL(%rip),%eax - mov %eax,errno(%rip) + mov ENAVAIL(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enetdown.S b/libc/sysv/errfuns/enetdown.S index 118aa6030..4876ef920 100644 --- a/libc/sysv/errfuns/enetdown.S +++ b/libc/sysv/errfuns/enetdown.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enetdown: .leafprologue - .profilable - mov ENETDOWN(%rip),%eax - mov %eax,errno(%rip) + mov ENETDOWN(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enetreset.S b/libc/sysv/errfuns/enetreset.S index 88ec850fd..33044fed7 100644 --- a/libc/sysv/errfuns/enetreset.S +++ b/libc/sysv/errfuns/enetreset.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enetreset: .leafprologue - .profilable - mov ENETRESET(%rip),%eax - mov %eax,errno(%rip) + mov ENETRESET(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enetunreach.S b/libc/sysv/errfuns/enetunreach.S index a9d905e16..ea2037da1 100644 --- a/libc/sysv/errfuns/enetunreach.S +++ b/libc/sysv/errfuns/enetunreach.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enetunreach: .leafprologue - .profilable - mov ENETUNREACH(%rip),%eax - mov %eax,errno(%rip) + mov ENETUNREACH(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enfile.S b/libc/sysv/errfuns/enfile.S index eb2acb5f5..df349914e 100644 --- a/libc/sysv/errfuns/enfile.S +++ b/libc/sysv/errfuns/enfile.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enfile: .leafprologue - .profilable - mov ENFILE(%rip),%eax - mov %eax,errno(%rip) + mov ENFILE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enoano.S b/libc/sysv/errfuns/enoano.S index f67174be0..ec86713b3 100644 --- a/libc/sysv/errfuns/enoano.S +++ b/libc/sysv/errfuns/enoano.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enoano: .leafprologue - .profilable - mov ENOANO(%rip),%eax - mov %eax,errno(%rip) + mov ENOANO(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enobufs.S b/libc/sysv/errfuns/enobufs.S index cf9fbab58..fba6728f3 100644 --- a/libc/sysv/errfuns/enobufs.S +++ b/libc/sysv/errfuns/enobufs.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enobufs: .leafprologue - .profilable - mov ENOBUFS(%rip),%eax - mov %eax,errno(%rip) + mov ENOBUFS(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enocsi.S b/libc/sysv/errfuns/enocsi.S index 62b180e9b..fdbd6614f 100644 --- a/libc/sysv/errfuns/enocsi.S +++ b/libc/sysv/errfuns/enocsi.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enocsi: .leafprologue - .profilable - mov ENOCSI(%rip),%eax - mov %eax,errno(%rip) + mov ENOCSI(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enodata.S b/libc/sysv/errfuns/enodata.S index ce83cd690..d41c30fad 100644 --- a/libc/sysv/errfuns/enodata.S +++ b/libc/sysv/errfuns/enodata.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enodata: .leafprologue - .profilable - mov ENODATA(%rip),%eax - mov %eax,errno(%rip) + mov ENODATA(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enodev.S b/libc/sysv/errfuns/enodev.S index 31cf7ea10..d2495a202 100644 --- a/libc/sysv/errfuns/enodev.S +++ b/libc/sysv/errfuns/enodev.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enodev: .leafprologue - .profilable - mov ENODEV(%rip),%eax - mov %eax,errno(%rip) + mov ENODEV(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enoent.S b/libc/sysv/errfuns/enoent.S index e454d29a5..5ffe65072 100644 --- a/libc/sysv/errfuns/enoent.S +++ b/libc/sysv/errfuns/enoent.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enoent: .leafprologue - .profilable - mov ENOENT(%rip),%eax - mov %eax,errno(%rip) + mov ENOENT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enoexec.S b/libc/sysv/errfuns/enoexec.S index f3ef662ba..582dc1061 100644 --- a/libc/sysv/errfuns/enoexec.S +++ b/libc/sysv/errfuns/enoexec.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enoexec: .leafprologue - .profilable - mov ENOEXEC(%rip),%eax - mov %eax,errno(%rip) + mov ENOEXEC(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enokey.S b/libc/sysv/errfuns/enokey.S index 2dee4cd3c..69d99ddaa 100644 --- a/libc/sysv/errfuns/enokey.S +++ b/libc/sysv/errfuns/enokey.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enokey: .leafprologue - .profilable - mov ENOKEY(%rip),%eax - mov %eax,errno(%rip) + mov ENOKEY(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enolck.S b/libc/sysv/errfuns/enolck.S index fc535dc1f..f4596bde2 100644 --- a/libc/sysv/errfuns/enolck.S +++ b/libc/sysv/errfuns/enolck.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enolck: .leafprologue - .profilable - mov ENOLCK(%rip),%eax - mov %eax,errno(%rip) + mov ENOLCK(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enolink.S b/libc/sysv/errfuns/enolink.S index 30d71fca4..4d42660e7 100644 --- a/libc/sysv/errfuns/enolink.S +++ b/libc/sysv/errfuns/enolink.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enolink: .leafprologue - .profilable - mov ENOLINK(%rip),%eax - mov %eax,errno(%rip) + mov ENOLINK(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enomedium.S b/libc/sysv/errfuns/enomedium.S index 6788bb69c..f83d3df1b 100644 --- a/libc/sysv/errfuns/enomedium.S +++ b/libc/sysv/errfuns/enomedium.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enomedium: .leafprologue - .profilable - mov ENOMEDIUM(%rip),%eax - mov %eax,errno(%rip) + mov ENOMEDIUM(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enomem.S b/libc/sysv/errfuns/enomem.S index 6830592d7..cacd2fa07 100644 --- a/libc/sysv/errfuns/enomem.S +++ b/libc/sysv/errfuns/enomem.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enomem: .leafprologue - .profilable - mov ENOMEM(%rip),%eax - mov %eax,errno(%rip) + mov ENOMEM(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enomsg.S b/libc/sysv/errfuns/enomsg.S index e20dbe123..a0efe0cea 100644 --- a/libc/sysv/errfuns/enomsg.S +++ b/libc/sysv/errfuns/enomsg.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enomsg: .leafprologue - .profilable - mov ENOMSG(%rip),%eax - mov %eax,errno(%rip) + mov ENOMSG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enonet.S b/libc/sysv/errfuns/enonet.S index 483b81c40..1a476bfb9 100644 --- a/libc/sysv/errfuns/enonet.S +++ b/libc/sysv/errfuns/enonet.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enonet: .leafprologue - .profilable - mov ENONET(%rip),%eax - mov %eax,errno(%rip) + mov ENONET(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enopkg.S b/libc/sysv/errfuns/enopkg.S index ab0a56c3e..f7eac5594 100644 --- a/libc/sysv/errfuns/enopkg.S +++ b/libc/sysv/errfuns/enopkg.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enopkg: .leafprologue - .profilable - mov ENOPKG(%rip),%eax - mov %eax,errno(%rip) + mov ENOPKG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enoprotoopt.S b/libc/sysv/errfuns/enoprotoopt.S index a10c0d1a3..4767e2858 100644 --- a/libc/sysv/errfuns/enoprotoopt.S +++ b/libc/sysv/errfuns/enoprotoopt.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enoprotoopt: .leafprologue - .profilable - mov ENOPROTOOPT(%rip),%eax - mov %eax,errno(%rip) + mov ENOPROTOOPT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enospc.S b/libc/sysv/errfuns/enospc.S index 226af4802..fdfd7b9bd 100644 --- a/libc/sysv/errfuns/enospc.S +++ b/libc/sysv/errfuns/enospc.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enospc: .leafprologue - .profilable - mov ENOSPC(%rip),%eax - mov %eax,errno(%rip) + mov ENOSPC(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enosr.S b/libc/sysv/errfuns/enosr.S index 6f81fa5db..a7c919c96 100644 --- a/libc/sysv/errfuns/enosr.S +++ b/libc/sysv/errfuns/enosr.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enosr: .leafprologue - .profilable - mov ENOSR(%rip),%eax - mov %eax,errno(%rip) + mov ENOSR(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enostr.S b/libc/sysv/errfuns/enostr.S index 56d80b562..3a8814f4c 100644 --- a/libc/sysv/errfuns/enostr.S +++ b/libc/sysv/errfuns/enostr.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enostr: .leafprologue - .profilable - mov ENOSTR(%rip),%eax - mov %eax,errno(%rip) + mov ENOSTR(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enosys.S b/libc/sysv/errfuns/enosys.S index 5b17c8dd0..09a1d2743 100644 --- a/libc/sysv/errfuns/enosys.S +++ b/libc/sysv/errfuns/enosys.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enosys: .leafprologue - .profilable - mov ENOSYS(%rip),%eax - mov %eax,errno(%rip) + mov ENOSYS(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotblk.S b/libc/sysv/errfuns/enotblk.S index 142230a34..54eef8c9e 100644 --- a/libc/sysv/errfuns/enotblk.S +++ b/libc/sysv/errfuns/enotblk.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotblk: .leafprologue - .profilable - mov ENOTBLK(%rip),%eax - mov %eax,errno(%rip) + mov ENOTBLK(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotconn.S b/libc/sysv/errfuns/enotconn.S index 9203834fa..7c7762630 100644 --- a/libc/sysv/errfuns/enotconn.S +++ b/libc/sysv/errfuns/enotconn.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotconn: .leafprologue - .profilable - mov ENOTCONN(%rip),%eax - mov %eax,errno(%rip) + mov ENOTCONN(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotdir.S b/libc/sysv/errfuns/enotdir.S index 7f81664ae..9dd8d0e6f 100644 --- a/libc/sysv/errfuns/enotdir.S +++ b/libc/sysv/errfuns/enotdir.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotdir: .leafprologue - .profilable - mov ENOTDIR(%rip),%eax - mov %eax,errno(%rip) + mov ENOTDIR(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotempty.S b/libc/sysv/errfuns/enotempty.S index 2bbbbe454..a686905b0 100644 --- a/libc/sysv/errfuns/enotempty.S +++ b/libc/sysv/errfuns/enotempty.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotempty: .leafprologue - .profilable - mov ENOTEMPTY(%rip),%eax - mov %eax,errno(%rip) + mov ENOTEMPTY(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotnam.S b/libc/sysv/errfuns/enotnam.S index 097f1520e..d96bb3c8e 100644 --- a/libc/sysv/errfuns/enotnam.S +++ b/libc/sysv/errfuns/enotnam.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotnam: .leafprologue - .profilable - mov ENOTNAM(%rip),%eax - mov %eax,errno(%rip) + mov ENOTNAM(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotrecoverable.S b/libc/sysv/errfuns/enotrecoverable.S index d50bd8ac8..e94e3571d 100644 --- a/libc/sysv/errfuns/enotrecoverable.S +++ b/libc/sysv/errfuns/enotrecoverable.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotrecoverable: .leafprologue - .profilable - mov ENOTRECOVERABLE(%rip),%eax - mov %eax,errno(%rip) + mov ENOTRECOVERABLE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotsock.S b/libc/sysv/errfuns/enotsock.S index cf6ce3b16..622795711 100644 --- a/libc/sysv/errfuns/enotsock.S +++ b/libc/sysv/errfuns/enotsock.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotsock: .leafprologue - .profilable - mov ENOTSOCK(%rip),%eax - mov %eax,errno(%rip) + mov ENOTSOCK(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotsup.S b/libc/sysv/errfuns/enotsup.S index 4ea31b101..2018c9d13 100644 --- a/libc/sysv/errfuns/enotsup.S +++ b/libc/sysv/errfuns/enotsup.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotsup: .leafprologue - .profilable - mov ENOTSUP(%rip),%eax - mov %eax,errno(%rip) + mov ENOTSUP(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotty.S b/libc/sysv/errfuns/enotty.S index 5710e3eba..47bef3c9f 100644 --- a/libc/sysv/errfuns/enotty.S +++ b/libc/sysv/errfuns/enotty.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotty: .leafprologue - .profilable - mov ENOTTY(%rip),%eax - mov %eax,errno(%rip) + mov ENOTTY(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enotuniq.S b/libc/sysv/errfuns/enotuniq.S index 212db238a..bf5d54242 100644 --- a/libc/sysv/errfuns/enotuniq.S +++ b/libc/sysv/errfuns/enotuniq.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enotuniq: .leafprologue - .profilable - mov ENOTUNIQ(%rip),%eax - mov %eax,errno(%rip) + mov ENOTUNIQ(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/enxio.S b/libc/sysv/errfuns/enxio.S index b6a1cd05c..03cb4d809 100644 --- a/libc/sysv/errfuns/enxio.S +++ b/libc/sysv/errfuns/enxio.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + enxio: .leafprologue - .profilable - mov ENXIO(%rip),%eax - mov %eax,errno(%rip) + mov ENXIO(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eopnotsupp.S b/libc/sysv/errfuns/eopnotsupp.S index 1cb69fbda..07cf5dbd2 100644 --- a/libc/sysv/errfuns/eopnotsupp.S +++ b/libc/sysv/errfuns/eopnotsupp.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eopnotsupp: .leafprologue - .profilable - mov EOPNOTSUPP(%rip),%eax - mov %eax,errno(%rip) + mov EOPNOTSUPP(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eoverflow.S b/libc/sysv/errfuns/eoverflow.S index 4f92fbd51..6408fe872 100644 --- a/libc/sysv/errfuns/eoverflow.S +++ b/libc/sysv/errfuns/eoverflow.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eoverflow: .leafprologue - .profilable - mov EOVERFLOW(%rip),%eax - mov %eax,errno(%rip) + mov EOVERFLOW(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eownerdead.S b/libc/sysv/errfuns/eownerdead.S index bd8841f19..cf7a3c63e 100644 --- a/libc/sysv/errfuns/eownerdead.S +++ b/libc/sysv/errfuns/eownerdead.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eownerdead: .leafprologue - .profilable - mov EOWNERDEAD(%rip),%eax - mov %eax,errno(%rip) + mov EOWNERDEAD(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eperm.S b/libc/sysv/errfuns/eperm.S index dd01b6f20..aded81083 100644 --- a/libc/sysv/errfuns/eperm.S +++ b/libc/sysv/errfuns/eperm.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eperm: .leafprologue - .profilable - mov EPERM(%rip),%eax - mov %eax,errno(%rip) + mov EPERM(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/epfnosupport.S b/libc/sysv/errfuns/epfnosupport.S index c3c8b53c4..105fbee68 100644 --- a/libc/sysv/errfuns/epfnosupport.S +++ b/libc/sysv/errfuns/epfnosupport.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + epfnosupport: .leafprologue - .profilable - mov EPFNOSUPPORT(%rip),%eax - mov %eax,errno(%rip) + mov EPFNOSUPPORT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/epipe.S b/libc/sysv/errfuns/epipe.S index 605075589..1fff95c8d 100644 --- a/libc/sysv/errfuns/epipe.S +++ b/libc/sysv/errfuns/epipe.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + epipe: .leafprologue - .profilable - mov EPIPE(%rip),%eax - mov %eax,errno(%rip) + mov EPIPE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eproto.S b/libc/sysv/errfuns/eproto.S index e92a3d627..4965378ae 100644 --- a/libc/sysv/errfuns/eproto.S +++ b/libc/sysv/errfuns/eproto.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eproto: .leafprologue - .profilable - mov EPROTO(%rip),%eax - mov %eax,errno(%rip) + mov EPROTO(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eprotonosupport.S b/libc/sysv/errfuns/eprotonosupport.S index 72eaf04ac..3b3fc92ec 100644 --- a/libc/sysv/errfuns/eprotonosupport.S +++ b/libc/sysv/errfuns/eprotonosupport.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eprotonosupport: .leafprologue - .profilable - mov EPROTONOSUPPORT(%rip),%eax - mov %eax,errno(%rip) + mov EPROTONOSUPPORT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eprototype.S b/libc/sysv/errfuns/eprototype.S index a5991f155..ad1471e01 100644 --- a/libc/sysv/errfuns/eprototype.S +++ b/libc/sysv/errfuns/eprototype.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eprototype: .leafprologue - .profilable - mov EPROTOTYPE(%rip),%eax - mov %eax,errno(%rip) + mov EPROTOTYPE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/erange.S b/libc/sysv/errfuns/erange.S index 2f4100027..d541322c9 100644 --- a/libc/sysv/errfuns/erange.S +++ b/libc/sysv/errfuns/erange.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + erange: .leafprologue - .profilable - mov ERANGE(%rip),%eax - mov %eax,errno(%rip) + mov ERANGE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eremchg.S b/libc/sysv/errfuns/eremchg.S index 3a32d3122..4366c696a 100644 --- a/libc/sysv/errfuns/eremchg.S +++ b/libc/sysv/errfuns/eremchg.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eremchg: .leafprologue - .profilable - mov EREMCHG(%rip),%eax - mov %eax,errno(%rip) + mov EREMCHG(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eremote.S b/libc/sysv/errfuns/eremote.S index e59f60d58..40b3595e0 100644 --- a/libc/sysv/errfuns/eremote.S +++ b/libc/sysv/errfuns/eremote.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eremote: .leafprologue - .profilable - mov EREMOTE(%rip),%eax - mov %eax,errno(%rip) + mov EREMOTE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eremoteio.S b/libc/sysv/errfuns/eremoteio.S index de0bae9ab..5631cfb58 100644 --- a/libc/sysv/errfuns/eremoteio.S +++ b/libc/sysv/errfuns/eremoteio.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eremoteio: .leafprologue - .profilable - mov EREMOTEIO(%rip),%eax - mov %eax,errno(%rip) + mov EREMOTEIO(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/erestart.S b/libc/sysv/errfuns/erestart.S index 86332af1f..668533c72 100644 --- a/libc/sysv/errfuns/erestart.S +++ b/libc/sysv/errfuns/erestart.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + erestart: .leafprologue - .profilable - mov ERESTART(%rip),%eax - mov %eax,errno(%rip) + mov ERESTART(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/erfkill.S b/libc/sysv/errfuns/erfkill.S index bed98ca59..4f509f686 100644 --- a/libc/sysv/errfuns/erfkill.S +++ b/libc/sysv/errfuns/erfkill.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + erfkill: .leafprologue - .profilable - mov ERFKILL(%rip),%eax - mov %eax,errno(%rip) + mov ERFKILL(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/erofs.S b/libc/sysv/errfuns/erofs.S index ddedebc92..0468b5c38 100644 --- a/libc/sysv/errfuns/erofs.S +++ b/libc/sysv/errfuns/erofs.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + erofs: .leafprologue - .profilable - mov EROFS(%rip),%eax - mov %eax,errno(%rip) + mov EROFS(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eshutdown.S b/libc/sysv/errfuns/eshutdown.S index 2cbe5943f..833f3f2c6 100644 --- a/libc/sysv/errfuns/eshutdown.S +++ b/libc/sysv/errfuns/eshutdown.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eshutdown: .leafprologue - .profilable - mov ESHUTDOWN(%rip),%eax - mov %eax,errno(%rip) + mov ESHUTDOWN(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/esocktnosupport.S b/libc/sysv/errfuns/esocktnosupport.S index 03d7e2c8d..d6d78a6c4 100644 --- a/libc/sysv/errfuns/esocktnosupport.S +++ b/libc/sysv/errfuns/esocktnosupport.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + esocktnosupport: .leafprologue - .profilable - mov ESOCKTNOSUPPORT(%rip),%eax - mov %eax,errno(%rip) + mov ESOCKTNOSUPPORT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/espipe.S b/libc/sysv/errfuns/espipe.S index 79fe0c90c..e23d80fca 100644 --- a/libc/sysv/errfuns/espipe.S +++ b/libc/sysv/errfuns/espipe.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + espipe: .leafprologue - .profilable - mov ESPIPE(%rip),%eax - mov %eax,errno(%rip) + mov ESPIPE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/esrch.S b/libc/sysv/errfuns/esrch.S index d4dd14a4f..a49b81a8a 100644 --- a/libc/sysv/errfuns/esrch.S +++ b/libc/sysv/errfuns/esrch.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + esrch: .leafprologue - .profilable - mov ESRCH(%rip),%eax - mov %eax,errno(%rip) + mov ESRCH(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/esrmnt.S b/libc/sysv/errfuns/esrmnt.S index 794a4e7f7..fb19cda90 100644 --- a/libc/sysv/errfuns/esrmnt.S +++ b/libc/sysv/errfuns/esrmnt.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + esrmnt: .leafprologue - .profilable - mov ESRMNT(%rip),%eax - mov %eax,errno(%rip) + mov ESRMNT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/estale.S b/libc/sysv/errfuns/estale.S index b89c58594..40e0e847a 100644 --- a/libc/sysv/errfuns/estale.S +++ b/libc/sysv/errfuns/estale.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + estale: .leafprologue - .profilable - mov ESTALE(%rip),%eax - mov %eax,errno(%rip) + mov ESTALE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/estrpipe.S b/libc/sysv/errfuns/estrpipe.S index 15156b25f..8051599dc 100644 --- a/libc/sysv/errfuns/estrpipe.S +++ b/libc/sysv/errfuns/estrpipe.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + estrpipe: .leafprologue - .profilable - mov ESTRPIPE(%rip),%eax - mov %eax,errno(%rip) + mov ESTRPIPE(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/etime.S b/libc/sysv/errfuns/etime.S index 4ab7872b4..551d86c09 100644 --- a/libc/sysv/errfuns/etime.S +++ b/libc/sysv/errfuns/etime.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + etime: .leafprologue - .profilable - mov ETIME(%rip),%eax - mov %eax,errno(%rip) + mov ETIME(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/etimedout.S b/libc/sysv/errfuns/etimedout.S index 10260ecaf..eff3c3292 100644 --- a/libc/sysv/errfuns/etimedout.S +++ b/libc/sysv/errfuns/etimedout.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + etimedout: .leafprologue - .profilable - mov ETIMEDOUT(%rip),%eax - mov %eax,errno(%rip) + mov ETIMEDOUT(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/etoomanyrefs.S b/libc/sysv/errfuns/etoomanyrefs.S index 28fd32b54..2fa0752a3 100644 --- a/libc/sysv/errfuns/etoomanyrefs.S +++ b/libc/sysv/errfuns/etoomanyrefs.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + etoomanyrefs: .leafprologue - .profilable - mov ETOOMANYREFS(%rip),%eax - mov %eax,errno(%rip) + mov ETOOMANYREFS(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/etxtbsy.S b/libc/sysv/errfuns/etxtbsy.S index 75ce6c84b..d3e390030 100644 --- a/libc/sysv/errfuns/etxtbsy.S +++ b/libc/sysv/errfuns/etxtbsy.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + etxtbsy: .leafprologue - .profilable - mov ETXTBSY(%rip),%eax - mov %eax,errno(%rip) + mov ETXTBSY(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/euclean.S b/libc/sysv/errfuns/euclean.S index 1f960a7e9..af9217e97 100644 --- a/libc/sysv/errfuns/euclean.S +++ b/libc/sysv/errfuns/euclean.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + euclean: .leafprologue - .profilable - mov EUCLEAN(%rip),%eax - mov %eax,errno(%rip) + mov EUCLEAN(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eunatch.S b/libc/sysv/errfuns/eunatch.S index a88f75f72..97b639674 100644 --- a/libc/sysv/errfuns/eunatch.S +++ b/libc/sysv/errfuns/eunatch.S @@ -1,11 +1,13 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eunatch: .leafprologue - .profilable - mov EUNATCH(%rip),%eax - mov %eax,errno(%rip) + mov EUNATCH(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/eusers.S b/libc/sysv/errfuns/eusers.S index 57c71de1a..41a1e5a7d 100644 --- a/libc/sysv/errfuns/eusers.S +++ b/libc/sysv/errfuns/eusers.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + eusers: .leafprologue - .profilable - mov EUSERS(%rip),%eax - mov %eax,errno(%rip) + mov EUSERS(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/exdev.S b/libc/sysv/errfuns/exdev.S index b0a43ec5c..2f6b33ba5 100644 --- a/libc/sysv/errfuns/exdev.S +++ b/libc/sysv/errfuns/exdev.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + exdev: .leafprologue - .profilable - mov EXDEV(%rip),%eax - mov %eax,errno(%rip) + mov EXDEV(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/sysv/errfuns/exfull.S b/libc/sysv/errfuns/exfull.S index aa552dec8..22d7f6a93 100644 --- a/libc/sysv/errfuns/exfull.S +++ b/libc/sysv/errfuns/exfull.S @@ -1,10 +1,12 @@ #include "libc/macros.internal.h" .text.unlikely +.section .privileged,"ax",@progbits + exfull: .leafprologue - .profilable - mov EXFULL(%rip),%eax - mov %eax,errno(%rip) + mov EXFULL(%rip),%ecx + .errno + mov %ecx,(%rax) push $-1 pop %rax .leafepilogue diff --git a/libc/nexgen32e/errno.c b/libc/sysv/errno.c similarity index 92% rename from libc/nexgen32e/errno.c rename to libc/sysv/errno.c index e0ac0743b..267e1e48a 100644 --- a/libc/nexgen32e/errno.c +++ b/libc/sysv/errno.c @@ -18,6 +18,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/errno.h" +asm(".weak\t__asan_init"); +asm(".weak\t__asan_register_globals"); +asm(".weak\t__asan_unregister_globals"); +asm(".weak\t__asan_version_mismatch_check_v8"); + /** * Global variable for last error. * @@ -30,13 +35,4 @@ * @see libc/sysv/errfuns.h * @see __errno_location() stable abi */ -int errno; - -/** - * Returns address of errno. - * - * @note this is needed by gdb - */ -int *__errno_location(void) { - return &errno; -} +errno_t __errno; diff --git a/libc/sysv/errno_location.greg.c b/libc/sysv/errno_location.greg.c new file mode 100644 index 000000000..d196b5ae7 --- /dev/null +++ b/libc/sysv/errno_location.greg.c @@ -0,0 +1,31 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/errno.h" +#include "libc/nexgen32e/threaded.h" + +/** + * Returns address of errno variable. + * + * @see __initialize_tls() + * @see __install_tls() + */ +privileged nocallersavedregisters errno_t *(__errno_location)(void) { + if (!__tls_enabled) return &__errno; + return (errno_t *)(__get_tls() + 0x3c); +} diff --git a/libc/sysv/gen.sh b/libc/sysv/gen.sh index b450111cd..b70ffdfd9 100644 --- a/libc/sysv/gen.sh +++ b/libc/sysv/gen.sh @@ -47,14 +47,15 @@ errfun() { ERRNO="$2" { printf '#include "libc/macros.internal.h"\n.text.unlikely\n\n' + printf '.section .privileged,"ax",@progbits\n\n' printf '%s:' "$NAME" if [ "${#NAME}" -gt 6 ]; then printf '\n' fi printf ' .leafprologue - .profilable - mov %s(%%rip),%%eax - mov %%eax,errno(%%rip) + mov %s(%%rip),%%ecx + .errno + mov %%ecx,(%%rax) push $-1 pop %%rax .leafepilogue diff --git a/libc/sysv/macros.internal.h b/libc/sysv/macros.internal.h index 88d1057c0..b6e564734 100644 --- a/libc/sysv/macros.internal.h +++ b/libc/sysv/macros.internal.h @@ -16,6 +16,7 @@ */ .macro .scall name:req num:req kw1 kw2 + .section .privileged,"ax",@progbits .ifnb \kw2 .align 16 \name: movabs $\num,%rax diff --git a/libc/sysv/strace.greg.c b/libc/sysv/strace.greg.c index cd75bfa5f..0822d65cb 100644 --- a/libc/sysv/strace.greg.c +++ b/libc/sysv/strace.greg.c @@ -16,6 +16,28 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/strace.internal.h" +#include "libc/runtime/runtime.h" -int __strace; +/** + * System call logging enabled state. + * + * If Cosmopolitan was compiled with the `SYSDEBUG` macro (this is the + * default behavior, except in tiny and release modes) then `__strace` + * shall control whether or not system calls are logged to fd 2. If it's + * greater than zero, syscalls are logged. Otherwise, they're aren't. + * + * By convention, functions wishing to disable syscall tracing for a + * short time period should say: + * + * void foo() { + * --__strace; + * bar(); + * ++__strace; + * } + * + * This way you still have some flexibility to force syscall tracing, by + * setting `__strace` to a higher number like `2` or `200`. Even though + * under normal circumstances, `__strace` should only be either zero or + * one. + */ +_Atomic(int) __strace; diff --git a/libc/sysv/g_syscount.S b/libc/sysv/syscount.S similarity index 91% rename from libc/sysv/g_syscount.S rename to libc/sysv/syscount.S index ff253c0cf..5e14eb44f 100644 --- a/libc/sysv/g_syscount.S +++ b/libc/sysv/syscount.S @@ -26,26 +26,26 @@ // wouldn't impact this counter. .bss .align 8 -g_syscount: +__syscount: .quad 0 - .endobj g_syscount,globl + .endobj __syscount,globl .previous - .initbss 701,_init_g_syscount -g_syscount_next: + .initbss 701,_init___syscount +__syscount_next: .quad 0 - .endobj g_syscount_next + .endobj __syscount_next .previous syscount: - incq g_syscount(%rip) - jmp *g_syscount_next(%rip) + incq __syscount(%rip) + jmp *__syscount_next(%rip) .endfn syscount .previous - .init.start 701,_init_g_syscount + .init.start 701,_init___syscount mov __systemfive(%rip),%rax stosq ezlea syscount,ax mov %rax,__systemfive(%rip) - .init.end 701,_init_g_syscount + .init.end 701,_init___syscount diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 81147c104..b32464dc3 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -126,7 +126,9 @@ systemfive_error: .endfn systemfive_error,globl,hidden #endif systemfive_errno: - mov %eax,errno(%rip) # normalize to c library convention + xchg %eax,%ecx + .errno + mov %ecx,(%rax) # normalize to c library convention push $-1 # negative one is only error result pop %rax # the push pop is to save code size ret diff --git a/libc/sysv/sysv.mk b/libc/sysv/sysv.mk index 42d389fc7..9bade5fc2 100644 --- a/libc/sysv/sysv.mk +++ b/libc/sysv/sysv.mk @@ -33,10 +33,12 @@ LIBC_SYSV_A_DIRECTDEPS = \ LIBC_SYSV_A_FILES := \ libc/sysv/macros.internal.h \ libc/sysv/errfuns.h \ - libc/sysv/g_syscount.S \ + libc/sysv/syscount.S \ libc/sysv/restorert.S \ libc/sysv/syscall.S \ libc/sysv/systemfive.S \ + libc/sysv/errno_location.greg.c \ + libc/sysv/errno.c \ libc/sysv/strace.greg.c \ libc/sysv/describeos.greg.c \ $(wildcard libc/sysv/consts/*) \ diff --git a/libc/testlib/quota.c b/libc/testlib/quota.c index 815e7e994..a9e452a66 100644 --- a/libc/testlib/quota.c +++ b/libc/testlib/quota.c @@ -32,7 +32,7 @@ #include "libc/testlib/testlib.h" #include "third_party/dlmalloc/dlmalloc.h" -static noasan relegated uint64_t CountMappedBytes(void) { +static noasan noubsan relegated uint64_t CountMappedBytes(void) { size_t i; uint64_t x, y; for (x = i = 0; i < _mmi.i; ++i) { @@ -77,7 +77,7 @@ relegated void __oom_hook(size_t request) { kprintf("FIX CODE OR TUNE QUOTA += -M%dm\n", newlim / (1024 * 1024)); } kprintf("\n"); - PrintMemoryIntervals(2, &_mmi); + __print_maps(); kprintf("\nTHE STRAW THAT BROKE THE CAMEL'S BACK\n"); PrintBacktraceUsingSymbols(2, 0, GetSymbolTable()); PrintSystemMappings(2); diff --git a/libc/testlib/testmain.c b/libc/testlib/testmain.c index 2893e06cf..c29258e57 100644 --- a/libc/testlib/testmain.c +++ b/libc/testlib/testmain.c @@ -20,12 +20,12 @@ #include "libc/bits/safemacros.internal.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/sigbits.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/rlimit.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigset.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/kprintf.h" @@ -67,6 +67,7 @@ Flags:\n\ STATIC_YOINK("__die"); STATIC_YOINK("__get_symbol_by_addr"); STATIC_YOINK("testlib_quota_handlers"); +STATIC_YOINK("stack_usage_logging"); static bool runbenchmarks_; @@ -153,6 +154,7 @@ noasan int main(int argc, char *argv[]) { __log_level = kLogInfo; GetOpts(argc, argv); setenv("GDB", "", true); + GetSymbolTable(); // normalize this process FixIrregularFds(); diff --git a/libc/testlib/testrunner.c b/libc/testlib/testrunner.c index b9fdfbfda..090f7e656 100644 --- a/libc/testlib/testrunner.c +++ b/libc/testlib/testrunner.c @@ -19,11 +19,11 @@ #include "libc/assert.h" #include "libc/bits/weaken.h" #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/sigbits.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigset.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" diff --git a/libc/testlib/ugly.h b/libc/testlib/ugly.h index e8c58e59f..c08baee03 100644 --- a/libc/testlib/ugly.h +++ b/libc/testlib/ugly.h @@ -9,9 +9,9 @@ #define __BENCH_ARRAY(S) \ _Section(".piro.relo.sort.bench.2." #S ",\"aw\",@init_array #") -#define __TEST_PROTOTYPE(S, N, A, K) \ - void S##_##N(void); \ - const void *const S##_##N##_ptr[] A(S##_##N) = {S##_##N}; \ +#define __TEST_PROTOTYPE(S, N, A, K) \ + void S##_##N(void); \ + testfn_t S##_##N##_ptr[] A(S##_##N) = {S##_##N}; \ testonly K void S##_##N(void) #define __TEST_SECTION(NAME, CONTENT) \ diff --git a/libc/thread/exit.c b/libc/thread/exit.c index 268514128..459b0f713 100644 --- a/libc/thread/exit.c +++ b/libc/thread/exit.c @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/intrin/lockxadd.h" #include "libc/runtime/runtime.h" #include "libc/thread/descriptor.h" diff --git a/libc/thread/join.c b/libc/thread/join.c index e816a0204..9dfaa0ed7 100644 --- a/libc/thread/join.c +++ b/libc/thread/join.c @@ -34,13 +34,15 @@ int cthread_join(cthread_t td, int* rc) { : "cc"); if (!(state & cthread_finished)) { + int ax; int flags = FUTEX_WAIT; // PRIVATE makes it hang - register struct timespec* timeout asm("r10") = NULL; - asm volatile("syscall" - : /* no outputs */ - : "a"(__NR_futex), "D"(&td->tid), "S"(flags), "d"(tid), - "r"(timeout) - : "rcx", "r11", "cc", "memory"); + struct timespec* timeout = NULL; + asm volatile("mov\t%5,%%r10\n\t" // timeout + "syscall" + : "=a"(ax) + : "0"(__NR_futex), "D"(&td->tid), "S"(flags), "d"(tid), + "g"(timeout) + : "rcx", "r10", "r11", "cc", "memory"); } *rc = td->rc; diff --git a/libc/thread/sem.c b/libc/thread/sem.c index e1b5bfa81..2355b8be4 100644 --- a/libc/thread/sem.c +++ b/libc/thread/sem.c @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/atomic.h" -#include "libc/intrin/atomic_load.h" #include "libc/thread/sem.h" #include "libc/thread/wait.h" #include "libc/thread/yield.h" @@ -74,7 +73,7 @@ int cthread_sem_wait_futex(cthread_sem_t* sem, const struct timespec* timeout) { while ((uint32_t)count > 0) { // without spin, we could miss a futex wake if (atomic_compare_exchange_weak( - &sem->linux.count, count, + &sem->linux.count, &count, count - 1 - ((uint64_t)1 << CTHREAD_THREAD_VAL_BITS))) { return 0; } @@ -97,7 +96,7 @@ int cthread_sem_wait_spin(cthread_sem_t* sem, uint64_t count, int spin, while ((uint32_t)count > 0) { // spin is useful if multiple waiters can acquire the semaphore at the // same time - if (atomic_compare_exchange_weak(&sem->linux.count, count, count - 1)) { + if (atomic_compare_exchange_weak(&sem->linux.count, &count, count - 1)) { return 0; } } @@ -115,7 +114,7 @@ int cthread_sem_wait(cthread_sem_t* sem, int spin, while ((uint32_t)count > 0) { // spin is useful if multiple waiters can acquire the semaphore at the same // time - if (atomic_compare_exchange_weak(&sem->linux.count, count, count - 1)) { + if (atomic_compare_exchange_weak(&sem->linux.count, &count, count - 1)) { return 0; } } diff --git a/libc/thread/wait.c b/libc/thread/wait.c index c0ecb7427..1d6565e14 100644 --- a/libc/thread/wait.c +++ b/libc/thread/wait.c @@ -25,12 +25,12 @@ int cthread_memory_wait32(uint32_t* addr, uint32_t val, if (__NR_futex != 0xfff) { int flags = FUTEX_WAIT; int rc; - register struct timespec* timeout_ asm("r10") = timeout; - asm volatile("syscall" + asm volatile("mov\t%5,%%r10\n\t" // timeout + "syscall" : "=a"(rc) : "0"(__NR_futex), "D"(addr), "S"(flags), "d"(val), - "r"(timeout_) - : "rcx", "r11", "cc", "memory"); + "g"(timeout) + : "rcx", "r10", "r11", "cc", "memory"); return rc; } return -1; diff --git a/libc/time/localtime.c b/libc/time/localtime.c index 50c68da0f..db409027a 100644 --- a/libc/time/localtime.c +++ b/libc/time/localtime.c @@ -5,6 +5,8 @@ #include "libc/bits/bits.h" #include "libc/calls/calls.h" #include "libc/intrin/spinlock.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.h" #include "libc/str/str.h" #include "libc/sysv/consts/o.h" #include "libc/time/time.h" @@ -40,7 +42,7 @@ STATIC_YOINK("usr/share/zoneinfo/UTC"); ** POSIX-style TZ environment variable handling from Guy Harris. */ -_Alignas(64) static char locallock; +_Alignas(64) static int locallock; static int lock(void) { _spinlock(&locallock); @@ -179,17 +181,8 @@ static struct tm *localtime_timesub(time_t const *, int_fast32_t, static bool localtime_typesequiv(struct state const *, int, int); static bool localtime_tzparse(char const *, struct state *, struct state *); -#ifdef ALL_STATE static struct state * lclptr; static struct state * gmtptr; -#endif /* defined ALL_STATE */ - -#ifndef ALL_STATE -static struct state lclmem; -static struct state gmtmem; -#define lclptr (&lclmem) -#define gmtptr (&gmtmem) -#endif /* State Farm */ #ifndef TZ_STRLEN_MAX #define TZ_STRLEN_MAX 255 @@ -736,7 +729,6 @@ localtime_tzloadbody(char const *name, struct state *sp, bool doextend, static int localtime_tzload(char const *name, struct state *sp, bool doextend) { -#ifdef ALL_STATE union local_storage *lsp = malloc(sizeof *lsp); if (!lsp) { return HAVE_MALLOC_ERRNO ? errno : ENOMEM; @@ -745,17 +737,6 @@ localtime_tzload(char const *name, struct state *sp, bool doextend) free(lsp); return err; } -#else - int i; - volatile char *p; - volatile unsigned x; - union local_storage ls; /* 70+ kilobytes */ - p = (char *)&ls; - for (x = i = 0; i < sizeof(ls); i += 4096) { - x += p[i]; /* make sure tzdata doesn't smash the stack */ - } - return localtime_tzloadbody(name, sp, doextend, &ls); -#endif } static bool @@ -1393,6 +1374,11 @@ zoneinit(struct state *sp, char const *name) } } +static void +FreeLocaltime(void *p) { + free(p); +} + static void localtime_tzset_unlocked(void) { @@ -1403,10 +1389,10 @@ localtime_tzset_unlocked(void) ? lcl_is_set < 0 : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0) return; -#ifdef ALL_STATE - if (! sp) + if (!sp) { lclptr = sp = malloc(sizeof *lclptr); -#endif /* defined ALL_STATE */ + __cxa_atexit(FreeLocaltime, sp, 0); + } if (sp) { if (zoneinit(sp, name) != 0) zoneinit(sp, ""); @@ -1426,6 +1412,11 @@ tzset(void) unlock(); } +static void +FreeGmt(void *p) { + free(p); +} + static void localtime_gmtcheck(void) { @@ -1433,9 +1424,8 @@ localtime_gmtcheck(void) if (lock() != 0) return; if (! gmt_is_set) { -#ifdef ALL_STATE gmtptr = malloc(sizeof *gmtptr); -#endif + __cxa_atexit(FreeGmt, gmtptr, 0); if (gmtptr) gmtload(gmtptr); gmt_is_set = true; diff --git a/libc/time/strftime.c b/libc/time/strftime.c index 8ab0ae2d1..ab673610a 100644 --- a/libc/time/strftime.c +++ b/libc/time/strftime.c @@ -569,6 +569,7 @@ label: * strftime(b, sizeof(b), "%a, %d %b %Y %H:%M:%S %Z", &tm); // RFC1123 * * @return bytes copied excluding nul, or 0 on error + * @see FormatHttpDateTime() */ size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *t) diff --git a/libc/time/time.mk b/libc/time/time.mk index da673d944..d3eed3777 100644 --- a/libc/time/time.mk +++ b/libc/time/time.mk @@ -53,10 +53,6 @@ $(LIBC_TIME_A).pkg: \ $(LIBC_TIME_A_OBJS) \ $(foreach x,$(LIBC_TIME_A_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/libc/time/localtime.o: \ - OVERRIDE_CFLAGS += \ - $(OLD_CODE) - o/$(MODE)/libc/time/strftime.o: \ OVERRIDE_CFLAGS += \ -fno-jump-tables @@ -66,10 +62,6 @@ o/$(MODE)/libc/time/localtime.o: \ -fdata-sections \ -ffunction-sections -o/$(MODE)/libc/time/localtime.o: \ - OVERRIDE_CPPFLAGS += \ - -DSTACK_FRAME_UNLIMITED - o/$(MODE)/libc/time/now.o: \ OVERRIDE_CFLAGS += \ -O3 diff --git a/libc/time/times.c b/libc/time/times.c index 2ff442c98..d31759135 100644 --- a/libc/time/times.c +++ b/libc/time/times.c @@ -17,10 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/rusage.h" #include "libc/calls/struct/timeval.h" #include "libc/calls/struct/tms.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/dce.h" #include "libc/fmt/conv.h" #include "libc/nt/accounting.h" diff --git a/libc/x/makedirs.c b/libc/x/makedirs.c index 1d3fd2eb8..6255bf9ff 100644 --- a/libc/x/makedirs.c +++ b/libc/x/makedirs.c @@ -29,11 +29,13 @@ static int MakeDirs(const char *path, unsigned mode, int e) { int rc; char *dir; - if (mkdir(path, mode) != -1) { + if (mkdir(path, mode) != -1 || errno == EEXIST) { errno = e; return 0; } - if (errno != ENOENT) return -1; + if (errno != ENOENT) { + return -1; + } dir = xdirname(path); if (strcmp(dir, path)) { rc = MakeDirs(dir, mode, e); @@ -49,6 +51,8 @@ static int MakeDirs(const char *path, unsigned mode, int e) { /** * Recursively creates directory a.k.a. folder. * + * This function won't fail if the directory already exists. + * * @param path is a UTF-8 string, preferably relative w/ forward slashes * @param mode can be, for example, 0755 * @return 0 on success or -1 w/ errno diff --git a/libc/x/x.h b/libc/x/x.h index a904caa93..c514b0e42 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -73,6 +73,7 @@ char *xdirname(const char *) paramsnonnull() _XMAL; char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL; char *xreadlink(const char *) paramsnonnull() _XMAL; char *xreadlinkat(int, const char *) paramsnonnull() _XMAL; +void xfixpath(void); /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § eXtended apis » time ─╬─│┼ diff --git a/libc/x/xfixpath.c b/libc/x/xfixpath.c new file mode 100644 index 000000000..237eeb80f --- /dev/null +++ b/libc/x/xfixpath.c @@ -0,0 +1,63 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/x/x.h" + +static inline int IsAlpha(int c) { + return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); +} + +/** + * Fixes $PATH environment variable on Windows. + */ +void xfixpath(void) { + size_t i; + char *p, *path; + path = strdup(getenv("PATH")); + if (strstr(path, "C:\\") && strstr(path, ";")) { + + // turn backslash into slash + for (p = path; *p; ++p) { + if (*p == '\\') *p = '/'; + } + + // turn c:/... into /c/... + if (IsAlpha(path[0]) && path[1] == ':' && path[2] == '/') { + path[1] = path[0]; + path[0] = '/'; + } + for (p = path, i = 0; p[i]; ++i) { + if (p[i + 0] == ';' && IsAlpha(p[i + 1]) && p[i + 2] == ':' && + p[i + 3] == '/') { + p[i + 2] = p[i + 1]; + p[i + 1] = '/'; + } + } + + // turn semicolon into colon + for (p = path; *p; ++p) { + if (*p == ';') *p = ':'; + } + + setenv("PATH", path, true); + } + free(path); +} diff --git a/libc/zipos/close.c b/libc/zipos/close.c index 98fb0b3c6..cbde1e7eb 100644 --- a/libc/zipos/close.c +++ b/libc/zipos/close.c @@ -18,6 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/mem/mem.h" #include "libc/nt/runtime.h" #include "libc/zip.h" diff --git a/libc/zipos/get.c b/libc/zipos/get.c index 93a067eeb..de5f4e14c 100644 --- a/libc/zipos/get.c +++ b/libc/zipos/get.c @@ -75,7 +75,7 @@ struct Zipos *__zipos_get(void) { const char *progpath; static struct Zipos zipos; uint8_t *map, *base, *cdir; - _Alignas(64) static char lock; + _Alignas(64) static int lock; _spinlock(&lock); if (!once) { sigfillset(&neu); diff --git a/libc/zipos/open.c b/libc/zipos/open.c index 9e8fcf4d9..70fe52fe9 100644 --- a/libc/zipos/open.c +++ b/libc/zipos/open.c @@ -21,10 +21,12 @@ #include "libc/bits/weaken.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/calls/struct/sigset.h" #include "libc/calls/struct/stat.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/crc32.h" @@ -126,11 +128,14 @@ static int __zipos_load(struct Zipos *zipos, size_t cf, unsigned flags, if (h->mem) { if ((fd = IsWindows() ? __reservefd(-1) : dup(2)) != -1) { if (__ensurefds(fd) != -1) { + _spinlock(&__fds_lock); h->handle = g_fds.p[fd].handle; g_fds.p[fd].kind = kFdZip; g_fds.p[fd].handle = (intptr_t)h; g_fds.p[fd].flags = flags | O_CLOEXEC; g_fds.p[fd].mode = mode; + g_fds.p[fd].extra = 0; + _spunlock(&__fds_lock); return fd; } close(fd); diff --git a/libc/zipos/read.c b/libc/zipos/read.c index 2767dd10c..00d595881 100644 --- a/libc/zipos/read.c +++ b/libc/zipos/read.c @@ -18,7 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/bits/safemacros.internal.h" -#include "libc/calls/internal.h" #include "libc/calls/struct/iovec.h" #include "libc/str/str.h" #include "libc/zip.h" diff --git a/net/http/formathttpdatetime.c b/net/http/formathttpdatetime.c index 9a5258fd5..bc9ebc808 100644 --- a/net/http/formathttpdatetime.c +++ b/net/http/formathttpdatetime.c @@ -27,6 +27,15 @@ * * Sun, 04 Oct 2020 19:50:10 GMT * + * This function is the same as: + * + * strftime(p, 30, "%a, %d %b %Y %H:%M:%S %Z", tm) + * + * Except this function goes 10x faster: + * + * FormatHttpDateTime l: 25𝑐 8𝑛𝑠 + * strftime l: 709𝑐 229𝑛𝑠 + * * @param tm must be zulu see gmtime_r() and nowl() * @see ParseHttpDateTime() */ diff --git a/test/dsp/core/test.mk b/test/dsp/core/test.mk index afa8171c6..60dbc21e8 100644 --- a/test/dsp/core/test.mk +++ b/test/dsp/core/test.mk @@ -43,7 +43,7 @@ o/$(MODE)/test/dsp/core/%.com.dbg: \ o/$(MODE)/test/dsp/core/%.o \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/dsp/core diff --git a/test/dsp/scale/test.mk b/test/dsp/scale/test.mk index 4b988b52a..87698b94b 100644 --- a/test/dsp/scale/test.mk +++ b/test/dsp/scale/test.mk @@ -50,7 +50,7 @@ o/$(MODE)/test/dsp/scale/%.com.dbg: \ o/$(MODE)/test/dsp/scale/scale.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/dsp/scale diff --git a/test/dsp/tty/test.mk b/test/dsp/tty/test.mk index c5b61ec0c..c8dd85733 100644 --- a/test/dsp/tty/test.mk +++ b/test/dsp/tty/test.mk @@ -45,7 +45,7 @@ o/$(MODE)/test/dsp/tty/%.com.dbg: \ o/$(MODE)/test/dsp/tty/tty.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/dsp/tty diff --git a/test/libc/alg/test.mk b/test/libc/alg/test.mk index 5ff888eff..8b3b5bfc2 100644 --- a/test/libc/alg/test.mk +++ b/test/libc/alg/test.mk @@ -50,7 +50,7 @@ o/$(MODE)/test/libc/alg/%.com.dbg: \ o/$(MODE)/test/libc/alg/alg.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_ALG_OBJS): test/libc/alg/test.mk diff --git a/test/libc/bits/test.mk b/test/libc/bits/test.mk index a588a980f..d4f59943e 100644 --- a/test/libc/bits/test.mk +++ b/test/libc/bits/test.mk @@ -46,7 +46,7 @@ o/$(MODE)/test/libc/bits/%.com.dbg: \ o/$(MODE)/test/libc/bits/bits.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_BITS_OBJS): \ diff --git a/test/libc/calls/clock_gettime_test.c b/test/libc/calls/clock_gettime_test.c index e67d61473..94d00d4bb 100644 --- a/test/libc/calls/clock_gettime_test.c +++ b/test/libc/calls/clock_gettime_test.c @@ -16,14 +16,40 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" +#include "libc/calls/clock_gettime.h" +#include "libc/calls/internal.h" #include "libc/calls/struct/timespec.h" -#include "libc/sysv/consts/clock.h" +#include "libc/calls/struct/timeval.h" +#include "libc/calls/syscall_support-sysv.internal.h" +#include "libc/nexgen32e/rdtsc.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/auxv.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" +#include "libc/time/time.h" + +TEST(clock_gettime, test) { + bool isfast; + struct timespec ts = {0}; + ASSERT_EQ(0, clock_gettime(0, &ts)); + ASSERT_NE(0, ts.tv_sec); + ASSERT_NE(0, ts.tv_nsec); + if (__is_linux_2_6_23()) { + ASSERT_GT((intptr_t)__clock_gettime_get(&isfast), + getauxval(AT_SYSINFO_EHDR)); + ASSERT_TRUE(isfast); + } +} BENCH(clock_gettime, bench) { + struct timeval tv; struct timespec ts; + gettimeofday(&tv, 0); // trigger init + clock_gettime(0, &ts); // trigger init EZBENCH2("nowl", donothing, nowl()); - EZBENCH2("clock_gettime", donothing, clock_gettime(CLOCK_REALTIME, &ts)); + EZBENCH2("rdtsc", donothing, rdtsc()); + EZBENCH2("gettimeofday", donothing, gettimeofday(&tv, 0)); + EZBENCH2("clock_gettime", donothing, clock_gettime(0, &ts)); + EZBENCH2("__clock_gettime", donothing, __clock_gettime(0, &ts)); + EZBENCH2("sys_clock_gettime", donothing, sys_clock_gettime(0, &ts)); } diff --git a/test/libc/calls/commandv_test.c b/test/libc/calls/commandv_test.c index 955d41266..6f3694a30 100644 --- a/test/libc/calls/commandv_test.c +++ b/test/libc/calls/commandv_test.c @@ -64,16 +64,16 @@ TEST(commandv, testPathSearch_appendsComExtension) { TEST(commandv, testSlashes_wontSearchPath_butChecksAccess) { EXPECT_NE(-1, touch("home/sh", 0755)); - i = g_syscount; + i = __syscount; EXPECT_STREQ("home/sh", commandv("home/sh", pathbuf, sizeof(pathbuf))); - if (!IsWindows()) EXPECT_EQ(i + 1, g_syscount); + if (!IsWindows()) EXPECT_EQ(i + 1, __syscount); } TEST(commandv, testSlashes_wontSearchPath_butStillAppendsComExtension) { EXPECT_NE(-1, touch("home/sh.com", 0755)); - i = g_syscount; + i = __syscount; EXPECT_STREQ("home/sh.com", commandv("home/sh", pathbuf, sizeof(pathbuf))); - if (!IsWindows()) EXPECT_EQ(i + 2, g_syscount); + if (!IsWindows()) EXPECT_EQ(i + 2, __syscount); } TEST(commandv, testSameDir_doesntHappenByDefaultUnlessItsWindows) { diff --git a/test/libc/calls/getcwd_test.c b/test/libc/calls/getcwd_test.c index 022ca22b6..77f65f5a7 100644 --- a/test/libc/calls/getcwd_test.c +++ b/test/libc/calls/getcwd_test.c @@ -30,14 +30,14 @@ char testlib_enable_tmp_setup_teardown; TEST(getcwd, test) { char buf[PATH_MAX]; - EXPECT_NE(-1, mkdir("subdir", 0755)); - EXPECT_NE(-1, chdir("subdir")); + EXPECT_SYS(0, 0, mkdir("subdir", 0755)); + EXPECT_SYS(0, 0, chdir("subdir")); EXPECT_STREQ("subdir", basename(getcwd(buf, ARRAYLEN(buf)))); } TEST(getcwd, testNullBuf_allocatesResult) { - EXPECT_NE(-1, mkdir("subdir", 0755)); - EXPECT_NE(-1, chdir("subdir")); + EXPECT_SYS(0, 0, mkdir("subdir", 0755)); + EXPECT_SYS(0, 0, chdir("subdir")); EXPECT_STREQ("subdir", basename(gc(getcwd(0, 0)))); } @@ -45,5 +45,5 @@ TEST(getcwd, testWindows_addsFunnyPrefix) { if (!IsWindows()) return; char path[PATH_MAX]; ASSERT_NE(0, getcwd(path, sizeof(path))); - EXPECT_STARTSWITH("//?/", path); + EXPECT_STARTSWITH("/C/", path); } diff --git a/test/libc/calls/mkdir_test.c b/test/libc/calls/mkdir_test.c index e0037d558..07aa908f2 100644 --- a/test/libc/calls/mkdir_test.c +++ b/test/libc/calls/mkdir_test.c @@ -34,30 +34,31 @@ void SetUp(void) { } TEST(mkdir, testNothingExists_ENOENT) { - EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(ENOENT, errno); + EXPECT_SYS(ENOENT, -1, mkdir("yo/yo/yo", 0755)); } TEST(mkdir, testDirectoryComponentIsFile_ENOTDIR) { - EXPECT_NE(-1, touch("yo", 0644)); - EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(ENOTDIR, errno); + EXPECT_SYS(0, 0, touch("yo", 0644)); + EXPECT_SYS(ENOTDIR, -1, mkdir("yo/yo/yo", 0755)); } TEST(mkdir, testPathIsFile_EEXIST) { - EXPECT_NE(-1, mkdir("yo", 0755)); - EXPECT_NE(-1, mkdir("yo/yo", 0755)); - EXPECT_NE(-1, touch("yo/yo/yo", 0644)); - EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(EEXIST, errno); + EXPECT_SYS(0, 0, mkdir("yo", 0755)); + EXPECT_SYS(0, 0, mkdir("yo/yo", 0755)); + EXPECT_SYS(0, 0, touch("yo/yo/yo", 0644)); + EXPECT_SYS(EEXIST, -1, mkdir("yo/yo/yo", 0755)); } TEST(mkdir, testPathIsDirectory_EEXIST) { - EXPECT_NE(-1, mkdir("yo", 0755)); - EXPECT_NE(-1, mkdir("yo/yo", 0755)); - EXPECT_NE(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(-1, mkdir("yo/yo/yo", 0755)); - EXPECT_EQ(EEXIST, errno); + EXPECT_SYS(0, 0, mkdir("yo", 0755)); + EXPECT_SYS(0, 0, mkdir("yo/yo", 0755)); + EXPECT_SYS(0, 0, mkdir("yo/yo/yo", 0755)); + EXPECT_SYS(EEXIST, -1, mkdir("yo/yo/yo", 0755)); +} + +TEST(makedirs, pathExists_isSuccess) { + EXPECT_SYS(0, 0, makedirs("foo/bar", 0755)); + EXPECT_SYS(0, 0, makedirs("foo/bar", 0755)); } TEST(mkdir, enametoolong) { @@ -69,19 +70,17 @@ TEST(mkdir, enametoolong) { EXPECT_SYS(ENAMETOOLONG, -1, mkdir(s, 0644)); } -TEST(makedirs, testEmptyString_EEXIST) { - EXPECT_EQ(-1, mkdir("", 0755)); - EXPECT_EQ(ENOENT, errno); +TEST(makedirs, testEmptyString_ENOENT) { + EXPECT_SYS(ENOENT, -1, mkdir("", 0755)); } TEST(mkdirat, testRelativePath_opensRelativeToDirFd) { int dirfd; - ASSERT_NE(-1, mkdir("foo", 0755)); - ASSERT_NE(-1, (dirfd = open("foo", O_RDONLY | O_DIRECTORY))); - EXPECT_NE(-1, mkdirat(dirfd, "bar", 0755)); + ASSERT_SYS(0, 0, mkdir("foo", 0755)); + ASSERT_SYS(0, 3, (dirfd = open("foo", O_RDONLY | O_DIRECTORY))); + EXPECT_SYS(0, 0, mkdirat(dirfd, "bar", 0755)); EXPECT_TRUE(isdirectory("foo/bar")); - EXPECT_EQ(-1, makedirs("", 0755)); - EXPECT_NE(-1, close(dirfd)); + EXPECT_SYS(0, 0, close(dirfd)); } TEST(mkdir, longname) { diff --git a/test/libc/calls/mkntenvblock_test.c b/test/libc/calls/mkntenvblock_test.c index 3c7c4bac2..505b789fb 100644 --- a/test/libc/calls/mkntenvblock_test.c +++ b/test/libc/calls/mkntenvblock_test.c @@ -20,17 +20,18 @@ #include "libc/runtime/gc.internal.h" #include "libc/testlib/testlib.h" +char tmp[ARG_MAX]; char16_t envvars[ARG_MAX / 2]; TEST(mkntenvblock, emptyList_onlyOutputsDoubleNulStringTerminator) { char *envp[] = {NULL}; - ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL)); + ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL, tmp)); ASSERT_BINEQ(u"  ", envvars); } TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) { char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL}; - ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL)); + ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL, tmp)); ASSERT_BINEQ(u"C = d   " u"H D U C = d   " u"U = b   " @@ -42,7 +43,7 @@ TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) { TEST(mkntenvblock, extraVar_getsAdded) { char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL}; - ASSERT_NE(-1, mkntenvblock(envvars, envp, "a=a")); + ASSERT_NE(-1, mkntenvblock(envvars, envp, "a=a", tmp)); ASSERT_BINEQ(u"A = a   " u"C = d   " u"H D U C = d   " @@ -52,3 +53,11 @@ TEST(mkntenvblock, extraVar_getsAdded) { u"  ", envvars); } + +TEST(mkntenvblock, pathvars_getUpdated) { + char *envp[] = {"PATH=/c/foo:/d/bar", NULL}; + ASSERT_NE(-1, mkntenvblock(envvars, envp, 0, tmp)); + ASSERT_BINEQ(u"P A T H = c : \\ f o o ; d : \\ b a r   " + u"  ", + envvars); +} diff --git a/test/libc/calls/mkntpath_test.c b/test/libc/calls/mkntpath_test.c index b051955b8..961e81ab1 100644 --- a/test/libc/calls/mkntpath_test.c +++ b/test/libc/calls/mkntpath_test.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/syscall_support-nt.internal.h" #include "libc/runtime/gc.internal.h" #include "libc/testlib/testlib.h" diff --git a/test/libc/calls/open_test.c b/test/libc/calls/open_test.c index ddfbae830..afec87b92 100644 --- a/test/libc/calls/open_test.c +++ b/test/libc/calls/open_test.c @@ -16,8 +16,10 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/internal.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/macros.internal.h" #include "libc/sysv/consts/o.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" @@ -53,6 +55,18 @@ TEST(open, enametoolong) { ASSERT_SYS(ENAMETOOLONG, -1, creat(s, 0644)); } +TEST(open, testSpaceInFilename) { + char buf[8] = {0}; + ASSERT_SYS(0, 0, xbarf("hello txt", "hello", -1)); + ASSERT_SYS(0, 3, open("hello txt", O_WRONLY)); + EXPECT_SYS(0, 1, write(3, "H", 1)); + EXPECT_SYS(0, 0, close(3)); + ASSERT_SYS(0, 3, open("hello txt", O_RDONLY)); + EXPECT_SYS(0, 5, read(3, buf, 7)); + EXPECT_STREQ("Hello", buf); + EXPECT_SYS(0, 0, close(3)); +} + TEST(open, testOpenExistingForWriteOnly_seeksToStart) { char buf[8] = {0}; ASSERT_SYS(0, 0, xbarf("hello.txt", "hello", -1)); @@ -88,3 +102,26 @@ TEST(open, testOpenExistingForAppendWriteOnly_seeksToEnd) { EXPECT_STREQ("hello", buf); EXPECT_SYS(0, 0, close(3)); } + +int CountFds(void) { + int i, count; + for (count = i = 0; i < g_fds.n; ++i) { + if (g_fds.p[i].kind) { + ++count; + } + } + return count; +} + +TEST(open, lotsOfFds) { + if (!IsWindows()) return; + int i, n = 200; + ASSERT_SYS(0, 0, xbarf("hello.txt", "hello", -1)); + for (i = 3; i < n; ++i) { + EXPECT_EQ(i, CountFds()); + EXPECT_SYS(0, i, open("hello.txt", O_RDONLY)); + } + for (i = 3; i < n; ++i) { + EXPECT_SYS(0, 0, close(i)); + } +} diff --git a/test/libc/calls/read_test.c b/test/libc/calls/read_test.c index 20db7ebb4..bbb5bb866 100644 --- a/test/libc/calls/read_test.c +++ b/test/libc/calls/read_test.c @@ -19,6 +19,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/sock/internal.h" #include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/o.h" diff --git a/test/libc/calls/readlinkat_test.c b/test/libc/calls/readlinkat_test.c index b178c07ee..86ecd4465 100644 --- a/test/libc/calls/readlinkat_test.c +++ b/test/libc/calls/readlinkat_test.c @@ -101,9 +101,10 @@ TEST(readlinkat, statReadsNameLength) { } TEST(readlinkat, realpathReturnsLongPath) { - if (!IsWindows()) return; struct stat st; char buf[PATH_MAX]; + if (!IsWindows()) return; + if (!startswith(getcwd(buf, PATH_MAX), "/c/")) return; ASSERT_SYS(0, 0, touch("froot", 0644)); - ASSERT_STARTSWITH("//?/", realpath("froot", buf)); + ASSERT_STARTSWITH("/c/", realpath("froot", buf)); } diff --git a/test/libc/calls/seccomp_test.c b/test/libc/calls/seccomp_test.c index 3fe4a74b8..3ca8f0566 100644 --- a/test/libc/calls/seccomp_test.c +++ b/test/libc/calls/seccomp_test.c @@ -22,6 +22,7 @@ #include "libc/calls/struct/filter.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/seccomp.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/errno.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" diff --git a/test/libc/calls/sigaction_test.c b/test/libc/calls/sigaction_test.c index fe4983c30..4f09954e0 100644 --- a/test/libc/calls/sigaction_test.c +++ b/test/libc/calls/sigaction_test.c @@ -23,6 +23,7 @@ #include "libc/calls/ucontext.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/nexgen32e/nexgen32e.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" @@ -34,6 +35,7 @@ struct sigaction oldsa; volatile bool gotsigint; void OnSigInt(int sig) { + CheckStackIsAligned(); gotsigint = true; } @@ -46,11 +48,11 @@ void SetUp(void) { TEST(sigaction, raise) { struct sigaction saint = {.sa_handler = OnSigInt}; - EXPECT_NE(-1, sigaction(SIGINT, &saint, &oldsa)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &saint, &oldsa)); ASSERT_FALSE(gotsigint); EXPECT_NE(-1, raise(SIGINT)); ASSERT_TRUE(gotsigint); - EXPECT_NE(-1, sigaction(SIGINT, &oldsa, NULL)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &oldsa, NULL)); } //////////////////////////////////////////////////////////////////////////////// @@ -68,37 +70,36 @@ TEST(sigaction, testPingPongParentChildWithSigint) { // kind of runner. todo(fixme!) return; } - EXPECT_NE(-1, sigemptyset(&blockint)); - EXPECT_NE(-1, sigaddset(&blockint, SIGINT)); - EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &blockint, &oldmask)); - EXPECT_NE(-1, sigaction(SIGINT, &catchint, &oldint)); + EXPECT_SYS(0, 0, sigemptyset(&blockint)); + EXPECT_SYS(0, 0, sigaddset(&blockint, SIGINT)); + EXPECT_SYS(0, 0, sigprocmask(SIG_BLOCK, &blockint, &oldmask)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, &oldint)); ASSERT_NE(-1, (pid = fork())); if (!pid) { // ping - EXPECT_NE(-1, kill(getppid(), SIGINT)); + EXPECT_SYS(0, 0, kill(getppid(), SIGINT)); EXPECT_FALSE(gotsigint); // pong - EXPECT_NE(-1, sigaction(SIGINT, &catchint, 0)); - EXPECT_EQ(-1, sigsuspend(0)); - EXPECT_EQ(EINTR, errno); + EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, 0)); + EXPECT_SYS(EINTR, -1, sigsuspend(0)); EXPECT_TRUE(gotsigint); _exit(0); } // pong EXPECT_FALSE(gotsigint); - EXPECT_NE(-1, sigaction(SIGINT, &catchint, 0)); - EXPECT_EQ(-1, sigsuspend(0)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &catchint, 0)); + EXPECT_SYS(EINTR, -1, sigsuspend(0)); EXPECT_TRUE(gotsigint); // ping - EXPECT_NE(-1, sigaction(SIGINT, &ignoreint, 0)); - EXPECT_NE(-1, kill(pid, SIGINT)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &ignoreint, 0)); + EXPECT_SYS(0, 0, kill(pid, SIGINT)); // cleanup EXPECT_NE(-1, wait4(pid, &status, 0, 0)); EXPECT_EQ(1, WIFEXITED(status)); EXPECT_EQ(0, WEXITSTATUS(status)); EXPECT_EQ(0, WTERMSIG(status)); - EXPECT_NE(-1, sigaction(SIGINT, &oldint, 0)); - EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &oldmask, 0)); + EXPECT_SYS(0, 0, sigaction(SIGINT, &oldint, 0)); + EXPECT_SYS(0, 0, sigprocmask(SIG_BLOCK, &oldmask, 0)); } //////////////////////////////////////////////////////////////////////////////// @@ -108,6 +109,7 @@ TEST(sigaction, testPingPongParentChildWithSigint) { volatile int trapeax; void OnTrap(int sig, struct siginfo *si, struct ucontext *ctx) { + CheckStackIsAligned(); trapeax = ctx->uc_mcontext.rax; } @@ -116,7 +118,7 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) { EXPECT_NE(-1, sigaction(SIGTRAP, &saint, &oldsa)); asm("int3" : /* no outputs */ : "a"(0x31337)); EXPECT_EQ(0x31337, trapeax); - EXPECT_NE(-1, sigaction(SIGTRAP, &oldsa, NULL)); + EXPECT_SYS(0, 0, sigaction(SIGTRAP, &oldsa, NULL)); } //////////////////////////////////////////////////////////////////////////////// @@ -124,6 +126,7 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) { // test signal handler can modify cpu registers (now it's recoverable!) void SkipOverFaultingInstruction(struct ucontext *ctx) { + CheckStackIsAligned(); struct XedDecodedInst xedd; xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); @@ -131,6 +134,7 @@ void SkipOverFaultingInstruction(struct ucontext *ctx) { } void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) { + CheckStackIsAligned(); SkipOverFaultingInstruction(ctx); ctx->uc_mcontext.rax = 42; ctx->uc_mcontext.rdx = 0; @@ -138,10 +142,10 @@ void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) { noubsan void ubsanTrumpsSystemsEngineering(void) { struct sigaction saint = {.sa_sigaction = OnFpe, .sa_flags = SA_SIGINFO}; - EXPECT_NE(-1, sigaction(SIGFPE, &saint, &oldsa)); + EXPECT_SYS(0, 0, sigaction(SIGFPE, &saint, &oldsa)); volatile long x = 0; EXPECT_EQ(42, 666 / x); /* systems engineering trumps math */ - EXPECT_NE(-1, sigaction(SIGFPE, &oldsa, NULL)); + EXPECT_SYS(0, 0, sigaction(SIGFPE, &oldsa, NULL)); } TEST(sigaction, sigFpe_handlerCanEditProcessStateAndRecoverExecution) { diff --git a/test/libc/calls/test.mk b/test/libc/calls/test.mk index bb21502ce..eaf0b18e1 100644 --- a/test/libc/calls/test.mk +++ b/test/libc/calls/test.mk @@ -61,7 +61,7 @@ o/$(MODE)/test/libc/calls/%.com.dbg: \ o/$(MODE)/test/libc/calls/calls.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/libc/calls diff --git a/test/libc/calls/vfork_test.c b/test/libc/calls/vfork_test.c index 1c5bc6155..11444ba68 100644 --- a/test/libc/calls/vfork_test.c +++ b/test/libc/calls/vfork_test.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/state.internal.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/o.h" #include "libc/testlib/testlib.h" diff --git a/test/libc/calls/write_test.c b/test/libc/calls/write_test.c index 39e068529..dc443ad00 100644 --- a/test/libc/calls/write_test.c +++ b/test/libc/calls/write_test.c @@ -19,6 +19,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/iovec.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/sock/internal.h" #include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/o.h" diff --git a/test/libc/dns/test.mk b/test/libc/dns/test.mk index 4fe280243..c29aab197 100644 --- a/test/libc/dns/test.mk +++ b/test/libc/dns/test.mk @@ -53,7 +53,7 @@ o/$(MODE)/test/libc/dns/%.com.dbg: \ o/$(MODE)/test/libc/dns/dns.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/libc/dns diff --git a/test/libc/fmt/fmt_test.c b/test/libc/fmt/fmt_test.c index 9a3851dfb..3300ee9eb 100644 --- a/test/libc/fmt/fmt_test.c +++ b/test/libc/fmt/fmt_test.c @@ -278,6 +278,11 @@ TEST(fmt, p) { gc(xasprintf("% 10p", 0xffff800000031337))); } +TEST(fmt, quoted) { + ASSERT_STREQ(" \"hello\"", gc(xasprintf("%`*.*s", 10, 5, "hello"))); + ASSERT_STREQ("\"hello\" ", gc(xasprintf("%-`*.*s", 10, 5, "hello"))); +} + TEST(fmt, regress) { char buf[512]; const char *meth = "GET"; diff --git a/test/libc/fmt/lengthuint64_test.c b/test/libc/fmt/lengthuint64_test.c index f0ddbd48f..7c4b2cee9 100644 --- a/test/libc/fmt/lengthuint64_test.c +++ b/test/libc/fmt/lengthuint64_test.c @@ -94,9 +94,13 @@ TEST(LengthInt64Thousands, test) { } BENCH(LengthInt64, bench) { - EZBENCH2("LengthInt64", donothing, LengthInt64(INT64_MIN)); - EZBENCH2("LengthUint64", donothing, LengthUint64(UINT64_MAX)); - EZBENCH2("LengthInt64Thousands", donothing, LengthInt64Thousands(INT64_MIN)); + unsigned LengthInt64_(int64_t) asm("LengthInt64"); + unsigned LengthUint64_(uint64_t) asm("LengthUint64"); + unsigned LengthInt64Thousands_(int64_t) asm("LengthInt64Thousands"); + unsigned LengthUint64Thousands_(uint64_t) asm("LengthUint64Thousands"); + EZBENCH2("LengthInt64", donothing, LengthInt64_(INT64_MIN)); + EZBENCH2("LengthUint64", donothing, LengthUint64_(UINT64_MAX)); + EZBENCH2("LengthInt64Thousands", donothing, LengthInt64Thousands_(INT64_MIN)); EZBENCH2("LengthUint64Thousands", donothing, - LengthUint64Thousands(UINT64_MAX)); + LengthUint64Thousands_(UINT64_MAX)); } diff --git a/test/libc/fmt/test.mk b/test/libc/fmt/test.mk index 57c9c3262..ccc8603a5 100644 --- a/test/libc/fmt/test.mk +++ b/test/libc/fmt/test.mk @@ -49,7 +49,7 @@ o/$(MODE)/test/libc/fmt/%.com.dbg: \ o/$(MODE)/test/libc/fmt/fmt.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_FMT_OBJS): test/libc/fmt/test.mk diff --git a/libc/intrin/atomic_load.c b/test/libc/fmt/uleb64_test.c similarity index 58% rename from libc/intrin/atomic_load.c rename to test/libc/fmt/uleb64_test.c index a384ce053..e88fa40ee 100644 --- a/libc/intrin/atomic_load.c +++ b/test/libc/fmt/uleb64_test.c @@ -16,38 +16,57 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/atomic_load.h" +#include "libc/fmt/leb128.h" +#include "libc/limits.h" +#include "libc/stdio/stdio.h" +#include "libc/testlib/testlib.h" -/** - * Reads scalar from memory w/ one operation. - * - * This macro is intended to prevent things like compiler load tearing - * optimizations. - * - * @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64} - * @return *(MEM) - * @note defeats compiler load tearing optimizations - * @note alignas(𝑘) is implied if compiler knows type - * @note alignas(𝑘) only avoids multi-core / cross-page edge cases - * @see Intel's Six-Thousand Page Manual V.3A §8.2.3.1 - * @see atomic_store() - */ -intptr_t(atomic_load)(void *p, size_t n) { - intptr_t x = 0; - switch (n) { - case 1: - __builtin_memcpy(&x, p, 1); - return x; - case 2: - __builtin_memcpy(&x, p, 2); - return x; - case 4: - __builtin_memcpy(&x, p, 4); - return x; - case 8: - __builtin_memcpy(&x, p, 8); - return x; - default: - return 0; - } +char p[10]; +uint64_t x; + +TEST(uleb64, testZero) { + EXPECT_EQ(1, uleb64(p, 0) - p); + EXPECT_EQ(0, p[0]); + EXPECT_EQ(1, unuleb64(p, 10, &x)); + EXPECT_EQ(0, x); + EXPECT_EQ(-1, unuleb64(p, 0, &x)); +} + +TEST(uleb64, testOne) { + EXPECT_EQ(1, uleb64(p, 1) - p); + EXPECT_EQ(1, p[0]); + EXPECT_EQ(1, unuleb64(p, 10, &x)); + EXPECT_EQ(1, x); +} + +TEST(uleb64, test255) { + EXPECT_EQ(2, uleb64(p, 255) - p); + EXPECT_EQ(255, p[0] & 255); + EXPECT_EQ(1, p[1]); + EXPECT_EQ(2, unuleb64(p, 10, &x)); + EXPECT_EQ(255, x); +} + +TEST(uleb64, testFFFF) { + EXPECT_EQ(3, uleb64(p, 0xFFFF) - p); + EXPECT_EQ(255, p[0] & 255); + EXPECT_EQ(255, p[1] & 255); + EXPECT_EQ(3, p[2] & 255); +} + +TEST(uleb64, testMax) { + EXPECT_EQ(10, uleb64(p, UINT64_MAX) - p); + EXPECT_EQ(255, p[0x00] & 255); + EXPECT_EQ(255, p[0x01] & 255); + EXPECT_EQ(255, p[0x02] & 255); + EXPECT_EQ(255, p[0x03] & 255); + EXPECT_EQ(255, p[0x04] & 255); + EXPECT_EQ(255, p[0x05] & 255); + EXPECT_EQ(255, p[0x06] & 255); + EXPECT_EQ(255, p[0x07] & 255); + EXPECT_EQ(255, p[0x08] & 255); + EXPECT_EQ(001, p[0x09] & 255); + EXPECT_EQ(10, unuleb64(p, 10, &x)); + EXPECT_EQ(UINT64_MAX, x); + EXPECT_EQ(-1, unuleb64(p, 7, &x)); } diff --git a/test/libc/intrin/asan_test.c b/test/libc/intrin/asan_test.c index 46bb2c0ea..1caf76766 100644 --- a/test/libc/intrin/asan_test.c +++ b/test/libc/intrin/asan_test.c @@ -46,6 +46,27 @@ TEST(asan, test) { EXPECT_FALSE(__asan_is_valid(p, 64 + 4)); EXPECT_TRUE(__asan_is_valid(p + 1, 64 + 2)); EXPECT_FALSE(__asan_is_valid(p + 1, 64 + 3)); + EXPECT_FALSE(__asan_is_valid(p - 1, 64)); +} + +TEST(asan, test2) { + char *p; + if (!IsAsan()) return; + p = gc(memalign(16, 64)); + // asan design precludes this kind of poisoning + __asan_poison(p + 1, 1, kAsanProtected); + EXPECT_TRUE(__asan_is_valid(p, 2)); + EXPECT_TRUE(__asan_is_valid(p + 1, 2)); + // but we can do this + __asan_poison(p + 7, 1, kAsanProtected); + EXPECT_TRUE(__asan_is_valid(p + 6, 1)); + EXPECT_FALSE(__asan_is_valid(p + 7, 1)); + EXPECT_TRUE(__asan_is_valid(p + 8, 1)); + EXPECT_FALSE(__asan_is_valid(p + 6, 2)); + EXPECT_FALSE(__asan_is_valid(p + 7, 2)); + EXPECT_FALSE(__asan_is_valid(p + 6, 3)); + __asan_unpoison(p + 7, 1); + EXPECT_TRUE(__asan_is_valid(p + 6, 3)); } TEST(asan, testEmptySize_isAlwaysValid) { diff --git a/test/libc/intrin/gettid_test.c b/test/libc/intrin/gettid_test.c index e69de29bb..5f7bde5b8 100644 --- a/test/libc/intrin/gettid_test.c +++ b/test/libc/intrin/gettid_test.c @@ -0,0 +1,37 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/dce.h" +#include "libc/nexgen32e/threaded.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/testlib.h" + +char tib[64]; + +TEST(gettid, test) { + if (IsLinux()) EXPECT_EQ(getpid(), gettid()); + if (IsNetbsd()) EXPECT_EQ(1, gettid()); +} + +BENCH(gettid, bench) { + int gettid_(void) asm("gettid"); + EZBENCH2("gettid (single threaded)", donothing, gettid()); + __install_tls(__initialize_tls(tib)); + EZBENCH2("gettid (tls enabled)", donothing, gettid()); +} diff --git a/test/libc/intrin/kprintf_test.c b/test/libc/intrin/kprintf_test.c index 071c15f5d..7618d68da 100644 --- a/test/libc/intrin/kprintf_test.c +++ b/test/libc/intrin/kprintf_test.c @@ -43,8 +43,7 @@ */ static uint64_t Rando(void) { uint64_t x; - do - x = lemur64(); + do x = lemur64(); while (((x ^ READ64LE("!!!!!!!!")) - 0x0101010101010101) & ~(x ^ READ64LE("!!!!!!!!")) & 0x8080808080808080); return x; @@ -249,9 +248,9 @@ TEST(kprintf, testFailure_wontClobberErrnoAndBypassesSystemCallSupport) { ASSERT_EQ(0, errno); EXPECT_SYS(0, 3, dup(2)); EXPECT_SYS(0, 0, close(2)); - n = g_syscount; + n = __syscount; kprintf("hello%n"); - EXPECT_EQ(n, g_syscount); + EXPECT_EQ(n, __syscount); EXPECT_EQ(0, errno); EXPECT_SYS(0, 2, dup2(3, 2)); EXPECT_SYS(0, 0, close(3)); diff --git a/test/libc/intrin/test.mk b/test/libc/intrin/test.mk index c29c57784..77e858ccd 100644 --- a/test/libc/intrin/test.mk +++ b/test/libc/intrin/test.mk @@ -54,7 +54,7 @@ o/$(MODE)/test/libc/intrin/%.com.dbg: \ o/$(MODE)/test/libc/intrin/intrin.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_INTRIN_OBJS): \ diff --git a/test/libc/intrin/tls_test.c b/test/libc/intrin/tls_test.c new file mode 100644 index 000000000..00d64c73a --- /dev/null +++ b/test/libc/intrin/tls_test.c @@ -0,0 +1,37 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/errno.h" +#include "libc/nexgen32e/threaded.h" +#include "libc/runtime/runtime.h" +#include "libc/testlib/testlib.h" + +static char tib[64]; + +TEST(tls, test) { + errno = 31337; + EXPECT_EQ(31337, errno); + EXPECT_EQ(&__errno, __errno_location()); + __initialize_tls(tib); + *(int *)((char *)tib + 0x38) = gettid(); + *(int *)((char *)tib + 0x3c) = __errno; + __install_tls(tib); + EXPECT_EQ(31337, errno); + EXPECT_EQ(tib, __get_tls()); + EXPECT_EQ(tib + 0x3c, (char *)__errno_location()); +} diff --git a/test/libc/log/backtrace.c b/test/libc/log/backtrace.c new file mode 100644 index 000000000..857e7d8dd --- /dev/null +++ b/test/libc/log/backtrace.c @@ -0,0 +1,132 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/fmt/conv.h" +#include "libc/limits.h" +#include "libc/log/log.h" +#include "libc/runtime/symbols.internal.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" + +int StackOverflow(int f(), int n) { + if (n < INT_MAX) { + return f(f, n + 1) - 1; + } else { + return INT_MAX; + } +} + +void FpuCrash(void) { + typedef char xmm_t __attribute__((__vector_size__(16))); + xmm_t v = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; + volatile int x = 0; + asm volatile("fldpi"); + asm volatile("mov\t%0,%%r15" : /* no outputs */ : "g"(0x3133731337)); + asm volatile("movaps\t%0,%%xmm15" : /* no outputs */ : "x"(v)); + fputc(7 / x, stdout); +} + +char bss[10]; +void BssOverrunCrash(int n) { + int i; + for (i = 0; i < n; ++i) { + bss[i] = i; + } +} + +char data[10] = "abcdeabcde"; +void DataOverrunCrash(int n) { + int i; + for (i = 0; i < n; ++i) { + data[i] = i; + } +} + +const char rodata[10] = "abcdeabcde"; +int RodataOverrunCrash(int i) { + return rodata[i]; +} + +char *StackOverrunCrash(int n) { + int i; + char stack[10]; + bzero(stack, sizeof(stack)); + for (i = 0; i < n; ++i) { + stack[i] = i; + } + return strdup(stack); +} + +char *MemoryLeakCrash(void) { + char *p = strdup("doge"); + CheckForMemoryLeaks(); + return p; +} + +int NpeCrash(char *p) { + asm("nop"); // xxx: due to backtrace addr-1 thing + return *p; +} + +void (*pFpuCrash)(void) = FpuCrash; +void (*pBssOverrunCrash)(int) = BssOverrunCrash; +void (*pDataOverrunCrash)(int) = DataOverrunCrash; +int (*pRodataOverrunCrash)(int) = RodataOverrunCrash; +char *(*pStackOverrunCrash)(int) = StackOverrunCrash; +char *(*pMemoryLeakCrash)(void) = MemoryLeakCrash; +int (*pNpeCrash)(char *) = NpeCrash; +int (*pStackOverflow)(int (*)(), int) = StackOverflow; + +int main(int argc, char *argv[]) { + ShowCrashReports(); + if (argc > 1) { + switch (atoi(argv[1])) { + case 0: + break; + case 1: + pFpuCrash(); + exit(0); + case 2: + pBssOverrunCrash(10 + 1); + exit(0); + case 3: + exit(pRodataOverrunCrash(10 + 1)); + case 4: + pDataOverrunCrash(10 + 1); + exit(0); + case 5: + exit((intptr_t)pStackOverrunCrash(10 + 1)); + case 6: + exit((intptr_t)pMemoryLeakCrash()); + case 7: + exit(pNpeCrash(0)); + case 8: + __cxa_finalize(0); + exit(pNpeCrash(0)); + case 9: + exit(pStackOverflow(pStackOverflow, 0)); + default: + fputs("error: unrecognized argument\n", stderr); + exit(1); + } + } else { + fputs("error: too few args\n", stderr); + exit(1); + } +} diff --git a/test/libc/log/backtrace_test.c b/test/libc/log/backtrace_test.c index e283d19cc..e313fae7e 100644 --- a/test/libc/log/backtrace_test.c +++ b/test/libc/log/backtrace_test.c @@ -23,8 +23,10 @@ #include "libc/fmt/conv.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/kprintf.h" +#include "libc/limits.h" #include "libc/log/libfatal.internal.h" #include "libc/log/log.h" +#include "libc/mem/io.h" #include "libc/mem/mem.h" #include "libc/runtime/gc.internal.h" #include "libc/runtime/internal.h" @@ -39,104 +41,30 @@ #include "libc/x/x.h" #include "net/http/escape.h" +STATIC_YOINK("zip_uri_support"); +STATIC_YOINK("backtrace.com"); +STATIC_YOINK("backtrace.com.dbg"); + +char testlib_enable_tmp_setup_teardown_once; + +void Extract(const char *from, const char *to, int mode) { + ASSERT_SYS(0, 3, open(from, O_RDONLY)); + ASSERT_SYS(0, 4, creat(to, mode)); + ASSERT_NE(-1, _copyfd(3, 4, -1)); + EXPECT_SYS(0, 0, close(4)); + EXPECT_SYS(0, 0, close(3)); +} + +void SetUpOnce(void) { + ASSERT_NE(-1, mkdir("bin", 0755)); + Extract("/zip/backtrace.com", "bin/backtrace.com", 0755); + Extract("/zip/backtrace.com.dbg", "bin/backtrace.com.dbg", 0755); +} + static bool OutputHasSymbol(const char *output, const char *s) { return strstr(output, s) || (!FindDebugBinary() && strstr(output, "NULL")); } -void FpuCrash(void) { - typedef char xmm_t __attribute__((__vector_size__(16))); - xmm_t v = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, - 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; - volatile int x = 0; - asm volatile("fldpi"); - asm volatile("mov\t%0,%%r15" : /* no outputs */ : "g"(0x3133731337)); - asm volatile("movaps\t%0,%%xmm15" : /* no outputs */ : "x"(v)); - fputc(7 / x, stdout); -} - -char bss[10]; -void BssOverrunCrash(int n) { - int i; - for (i = 0; i < n; ++i) { - bss[i] = i; - } -} - -char data[10] = "abcdeabcde"; -void DataOverrunCrash(int n) { - int i; - for (i = 0; i < n; ++i) { - data[i] = i; - } -} - -const char rodata[10] = "abcdeabcde"; -int RodataOverrunCrash(int i) { - return rodata[i]; -} - -char *StackOverrunCrash(int n) { - int i; - char stack[10]; - bzero(stack, sizeof(stack)); - for (i = 0; i < n; ++i) { - stack[i] = i; - } - return strdup(stack); -} - -char *MemoryLeakCrash(void) { - char *p = strdup("doge"); - CheckForMemoryLeaks(); - return p; -} - -int NpeCrash(char *p) { - asm("nop"); // xxx: due to backtrace addr-1 thing - return *p; -} - -void (*pFpuCrash)(void) = FpuCrash; -void (*pBssOverrunCrash)(int) = BssOverrunCrash; -void (*pDataOverrunCrash)(int) = DataOverrunCrash; -int (*pRodataOverrunCrash)(int) = RodataOverrunCrash; -char *(*pStackOverrunCrash)(int) = StackOverrunCrash; -char *(*pMemoryLeakCrash)(void) = MemoryLeakCrash; -int (*pNpeCrash)(char *) = NpeCrash; - -void SetUp(void) { - ShowCrashReports(); - if (__argc == 2) { - switch (atoi(__argv[1])) { - case 0: - break; - case 1: - pFpuCrash(); - exit(0); - case 2: - pBssOverrunCrash(10 + 1); - exit(0); - case 3: - exit(pRodataOverrunCrash(10 + 1)); - case 4: - pDataOverrunCrash(10 + 1); - exit(0); - case 5: - exit((intptr_t)pStackOverrunCrash(10 + 1)); - case 6: - exit((intptr_t)pMemoryLeakCrash()); - case 7: - exit(pNpeCrash(0)); - case 8: - __cxa_finalize(0); - exit(pNpeCrash(0)); - default: - printf("preventing fork recursion: %s\n", __argv[1]); - exit(1); - } - } -} - // UNFREED MEMORY // o/dbg/test/libc/log/backtrace_test.com // max allocated space 655,360 @@ -177,9 +105,8 @@ TEST(ShowCrashReports, testMemoryLeakCrash) { if (!pid) { dup2(fds[1], 1); dup2(fds[1], 2); - execv(GetProgramExecutableName(), - (char *const[]){GetProgramExecutableName(), "6", 0}); - _exit(127); + execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "6", 0}); + _Exit(127); } close(fds[1]); output = 0; @@ -255,9 +182,8 @@ TEST(ShowCrashReports, testStackOverrunCrash) { if (!pid) { dup2(fds[1], 1); dup2(fds[1], 2); - execv(GetProgramExecutableName(), - (char *const[]){GetProgramExecutableName(), "5", 0}); - _exit(127); + execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "5", 0}); + _Exit(127); } close(fds[1]); output = 0; @@ -364,9 +290,8 @@ TEST(ShowCrashReports, testDivideByZero) { if (!pid) { dup2(fds[1], 1); dup2(fds[1], 2); - execv(GetProgramExecutableName(), - (char *const[]){GetProgramExecutableName(), "1", 0}); - _exit(127); + execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "1", 0}); + _Exit(127); } close(fds[1]); output = 0; @@ -428,6 +353,78 @@ TEST(ShowCrashReports, testDivideByZero) { free(output); } +TEST(ShowCrashReports, testStackOverflow) { + if (IsXnu()) return; // TODO(jart): fix me + if (IsWindows()) return; // TODO(jart): fix me + if (IsFreebsd()) return; // TODO(jart): fix me + if (IsOpenbsd()) return; // TODO(jart): fix me + size_t got; + ssize_t rc; + int ws, pid, fds[2]; + char *output, buf[512]; + ASSERT_NE(-1, pipe2(fds, O_CLOEXEC)); + ASSERT_NE(-1, (pid = vfork())); + if (!pid) { + dup2(fds[1], 1); + dup2(fds[1], 2); + execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "9", 0}); + _Exit(127); + } + close(fds[1]); + output = 0; + appends(&output, ""); + for (;;) { + rc = read(fds[0], buf, sizeof(buf)); + if (rc == -1) { + ASSERT_EQ(EINTR, errno); + continue; + } + if ((got = rc)) { + appendd(&output, buf, got); + } else { + break; + } + } + close(fds[0]); + ASSERT_NE(-1, wait(&ws)); + EXPECT_TRUE(WIFEXITED(ws)); + // kprintf("exit status %d\n", WEXITSTATUS(ws)); + assert(128 + SIGSEGV == WEXITSTATUS(ws) || 77 == WEXITSTATUS(ws)); + /* NULL is stopgap until we can copy symbol tablces into binary */ +#ifdef __FNO_OMIT_FRAME_POINTER__ + if (!OutputHasSymbol(output, "StackOverflow")) { + fprintf(stderr, "ERROR: crash report didn't have backtrace\n%s\n", + gc(IndentLines(output, -1, 0, 4))); + __die(); + } +#endif + // ShowCrashReports() handled it + if (!strstr(output, gc(xasprintf("%d", pid)))) { + fprintf(stderr, "ERROR: crash report didn't have pid\n%s\n", + gc(IndentLines(output, -1, 0, 4))); + __die(); + } + if (!strstr(output, "SIGSEGV")) { + fprintf(stderr, "ERROR: crash report didn't have signal name\n%s\n", + gc(IndentLines(output, -1, 0, 4))); + __die(); + } + if (!IsTiny()) { + if (!strstr(output, "Stack Overflow")) { + fprintf(stderr, "ERROR: crash report didn't have 'Stack Overflow'\n%s\n", + gc(IndentLines(output, -1, 0, 4))); + __die(); + } + } else { + if (!strstr(output, "SEGV_MAPERR")) { + fprintf(stderr, "ERROR: crash report didn't have 'SEGV_MAPERR'\n%s\n", + gc(IndentLines(output, -1, 0, 4))); + __die(); + } + } + free(output); +} + // clang-format off // // test/libc/log/backtrace_test.c:59: ubsan error: 'int' index 10 into 'char [10]' out of bounds @@ -486,9 +483,8 @@ TEST(ShowCrashReports, testBssOverrunCrash) { if (!pid) { dup2(fds[1], 1); dup2(fds[1], 2); - execv(GetProgramExecutableName(), - (char *const[]){GetProgramExecutableName(), "2", 0}); - _exit(127); + execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "2", 0}); + _Exit(127); } close(fds[1]); output = 0; @@ -565,9 +561,8 @@ TEST(ShowCrashReports, testNpeCrash) { if (!pid) { dup2(fds[1], 1); dup2(fds[1], 2); - execv(GetProgramExecutableName(), - (char *const[]){GetProgramExecutableName(), "7", 0}); - _exit(127); + execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "7", 0}); + _Exit(127); } close(fds[1]); output = 0; @@ -625,9 +620,8 @@ TEST(ShowCrashReports, testDataOverrunCrash) { if (!pid) { dup2(fds[1], 1); dup2(fds[1], 2); - execv(GetProgramExecutableName(), - (char *const[]){GetProgramExecutableName(), "4", 0}); - _exit(127); + execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "4", 0}); + _Exit(127); } close(fds[1]); output = 0; @@ -680,9 +674,8 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) { if (!pid) { dup2(fds[1], 1); dup2(fds[1], 2); - execv(GetProgramExecutableName(), - (char *const[]){GetProgramExecutableName(), "8", 0}); - _exit(127); + execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "8", 0}); + _Exit(127); } close(fds[1]); output = 0; @@ -702,6 +695,7 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) { close(fds[0]); ASSERT_NE(-1, wait(&ws)); EXPECT_TRUE(WIFEXITED(ws)); + EXPECT_EQ(0, WTERMSIG(ws)); EXPECT_EQ(IsAsan() ? 77 : 128 + SIGSEGV, WEXITSTATUS(ws)); /* NULL is stopgap until we can copy symbol tables into binary */ if (!strstr(output, IsAsan() ? "null pointer" : "Uncaught SIGSEGV (SEGV_")) { diff --git a/test/libc/log/test.mk b/test/libc/log/test.mk index 6a05cf495..34d81864f 100644 --- a/test/libc/log/test.mk +++ b/test/libc/log/test.mk @@ -6,56 +6,82 @@ PKGS += TEST_LIBC_LOG TEST_LIBC_LOG_SRCS := $(wildcard test/libc/log/*.c) TEST_LIBC_LOG_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_LOG_SRCS)) -TEST_LIBC_LOG_OBJS = \ - $(TEST_LIBC_LOG_SRCS:%.c=o/$(MODE)/%.o) +TEST_LIBC_LOG_OBJS = \ + $(TEST_LIBC_LOG_SRCS:%.c=o/$(MODE)/%.o) \ + o/$(MODE)/test/libc/log/backtrace.com.zip.o \ + o/$(MODE)/test/libc/log/backtrace.com.dbg.zip.o -TEST_LIBC_LOG_COMS = \ +TEST_LIBC_LOG_COMS = \ $(TEST_LIBC_LOG_SRCS:%.c=o/$(MODE)/%.com) -TEST_LIBC_LOG_BINS = \ - $(TEST_LIBC_LOG_COMS) \ +TEST_LIBC_LOG_BINS = \ + $(TEST_LIBC_LOG_COMS) \ $(TEST_LIBC_LOG_COMS:%=%.dbg) -TEST_LIBC_LOG_TESTS = \ +TEST_LIBC_LOG_TESTS = \ $(TEST_LIBC_LOG_SRCS_TEST:%.c=o/$(MODE)/%.com.ok) -TEST_LIBC_LOG_CHECKS = \ +TEST_LIBC_LOG_CHECKS = \ $(TEST_LIBC_LOG_SRCS_TEST:%.c=o/$(MODE)/%.com.runs) -TEST_LIBC_LOG_DIRECTDEPS = \ - LIBC_CALLS \ - LIBC_RUNTIME \ - NET_HTTP \ - LIBC_STDIO \ - LIBC_X \ - LIBC_INTRIN \ - LIBC_FMT \ - LIBC_MEM \ - LIBC_NEXGEN32E \ - LIBC_LOG \ - LIBC_STR \ - LIBC_STUBS \ - LIBC_TESTLIB \ - LIBC_SYSV \ - LIBC_LOG +TEST_LIBC_LOG_DIRECTDEPS = \ + LIBC_CALLS \ + LIBC_RUNTIME \ + NET_HTTP \ + LIBC_STDIO \ + LIBC_X \ + LIBC_INTRIN \ + LIBC_FMT \ + LIBC_MEM \ + LIBC_NEXGEN32E \ + LIBC_LOG \ + LIBC_STR \ + LIBC_STUBS \ + LIBC_TESTLIB \ + LIBC_SYSV \ + LIBC_LOG \ + LIBC_ZIPOS -TEST_LIBC_LOG_DEPS := \ +TEST_LIBC_LOG_DEPS := \ $(call uniq,$(foreach x,$(TEST_LIBC_LOG_DIRECTDEPS),$($(x)))) -o/$(MODE)/test/libc/log/log.pkg: \ - $(TEST_LIBC_LOG_OBJS) \ +o/$(MODE)/test/libc/log/log.pkg: \ + $(TEST_LIBC_LOG_OBJS) \ $(foreach x,$(TEST_LIBC_LOG_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/test/libc/log/%.com.dbg: \ - $(TEST_LIBC_LOG_DEPS) \ - o/$(MODE)/test/libc/log/%.o \ - o/$(MODE)/test/libc/log/log.pkg \ - $(LIBC_TESTMAIN) \ - $(CRT) \ - $(APE) +o/$(MODE)/test/libc/log/%.com.dbg: \ + $(TEST_LIBC_LOG_DEPS) \ + o/$(MODE)/test/libc/log/%.o \ + o/$(MODE)/test/libc/log/log.pkg \ + $(LIBC_TESTMAIN) \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) @$(APELINK) +o/$(MODE)/test/libc/log/backtrace_test.com.dbg: \ + $(TEST_LIBC_LOG_DEPS) \ + o/$(MODE)/test/libc/log/backtrace.com.zip.o \ + o/$(MODE)/test/libc/log/backtrace.com.dbg.zip.o \ + o/$(MODE)/test/libc/log/backtrace_test.o \ + o/$(MODE)/test/libc/log/log.pkg \ + $(LIBC_TESTMAIN) \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) + @$(APELINK) + +o/$(MODE)/test/libc/log/backtrace.com.dbg: \ + $(TEST_LIBC_LOG_DEPS) \ + o/$(MODE)/test/libc/log/backtrace.o \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) + @$(APELINK) + +o/$(MODE)/test/libc/log/backtrace.com.zip.o \ +o/$(MODE)/test/libc/log/backtrace.com.dbg.zip.o: \ + ZIPOBJ_FLAGS += \ + -B + .PHONY: o/$(MODE)/test/libc/log -o/$(MODE)/test/libc/log: \ - $(TEST_LIBC_LOG_BINS) \ +o/$(MODE)/test/libc/log: \ + $(TEST_LIBC_LOG_BINS) \ $(TEST_LIBC_LOG_CHECKS) diff --git a/test/libc/mem/pledge_test.c b/test/libc/mem/pledge_test.c index 808141f41..10fb53463 100644 --- a/test/libc/mem/pledge_test.c +++ b/test/libc/mem/pledge_test.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/mem/mem.h" diff --git a/test/libc/mem/test.mk b/test/libc/mem/test.mk index cdb4dc420..ced1e6174 100644 --- a/test/libc/mem/test.mk +++ b/test/libc/mem/test.mk @@ -58,7 +58,7 @@ o/$(MODE)/test/libc/mem/%.com.dbg: \ o/$(MODE)/test/libc/mem/mem.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_MEM_OBJS): \ diff --git a/test/libc/nexgen32e/test.mk b/test/libc/nexgen32e/test.mk index c86b2ad2d..5cc459028 100644 --- a/test/libc/nexgen32e/test.mk +++ b/test/libc/nexgen32e/test.mk @@ -55,7 +55,7 @@ o/$(MODE)/test/libc/nexgen32e/%.com.dbg: \ o/$(MODE)/test/libc/nexgen32e/nexgen32e.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_NEXGEN32E_OBJS): \ diff --git a/test/libc/rand/rand64_test.c b/test/libc/rand/rand64_test.c index 4957f91ae..d406a6abc 100644 --- a/test/libc/rand/rand64_test.c +++ b/test/libc/rand/rand64_test.c @@ -22,8 +22,10 @@ #include "libc/calls/struct/sigset.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" +#include "libc/nexgen32e/threaded.h" #include "libc/rand/rand.h" #include "libc/runtime/stack.h" #include "libc/str/str.h" @@ -36,25 +38,29 @@ #include "libc/time/time.h" #define THREADS 8 -#define ENTRIES 256 +#define ENTRIES 1024 -char locks[THREADS]; -volatile bool ready; +_Atomic(bool) ready; volatile uint64_t A[THREADS * ENTRIES]; void OnChld(int sig) { // do nothing } +dontinline void Pause(void) { + // when ftrace is enabled +} + +dontinline void Generate(int i) { + A[i] = rand64(); +} + int Thrasher(void *arg) { int i, id = (intptr_t)arg; - while (!ready) { - __builtin_ia32_pause(); - } + while (!ready) Pause(); for (i = 0; i < ENTRIES; ++i) { - A[id * ENTRIES + i] = rand64(); + Generate(id * ENTRIES + i); } - _spunlock(locks + id); return 0; } @@ -74,9 +80,10 @@ TEST(rand64, testLcg_doesntProduceIdenticalValues) { } TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) { + int i, j, rc, ws; sigset_t ss, oldss; + char *tls[THREADS]; void *stacks[THREADS]; - int i, j, rc, ws, tid[THREADS]; struct sigaction oldsa; struct sigaction sa = {.sa_handler = OnChld, .sa_flags = SA_RESTART}; EXPECT_NE(-1, sigaction(SIGCHLD, &sa, &oldsa)); @@ -84,22 +91,23 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) { sigemptyset(&ss); sigaddset(&ss, SIGCHLD); EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &ss, &oldss)); - for (i = 0; i < THREADS; ++i) { - locks[i] = 1; - } ready = false; for (i = 0; i < THREADS; ++i) { + tls[i] = __initialize_tls(calloc(1, 64)); stacks[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, MAP_STACK | MAP_ANONYMOUS, -1, 0); - tid[i] = + ASSERT_NE( + -1, clone(Thrasher, stacks[i], GetStackSize(), - CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(intptr_t)i, 0, 0, 0, 0); - ASSERT_NE(-1, tid[i]); + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, + (void *)(intptr_t)i, 0, tls[i], 64, (int *)(tls[i] + 0x38))); } ready = true; for (i = 0; i < THREADS; ++i) { - _spinlock(locks + i); + _spinlock((int *)(tls[i] + 0x38)); + EXPECT_SYS(0, 0, munmap(stacks[i], GetStackSize())); + free(tls[i]); } sigaction(SIGCHLD, &oldsa, 0); sigprocmask(SIG_BLOCK, &oldss, 0); @@ -110,7 +118,4 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) { EXPECT_NE(A[i], A[j], "i=%d j=%d", i, j); } } - for (i = 0; i < THREADS; ++i) { - EXPECT_SYS(0, 0, munmap(stacks[i], GetStackSize())); - } } diff --git a/test/libc/rand/test.mk b/test/libc/rand/test.mk index a26a99a32..9195d233b 100644 --- a/test/libc/rand/test.mk +++ b/test/libc/rand/test.mk @@ -52,7 +52,7 @@ o/$(MODE)/test/libc/rand/%.com.dbg: \ o/$(MODE)/test/libc/rand/rand.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_RAND_OBJS): test/libc/rand/test.mk diff --git a/test/libc/release/metal.sh b/test/libc/release/metal.sh index 250fcc76c..29c0bae0a 100755 --- a/test/libc/release/metal.sh +++ b/test/libc/release/metal.sh @@ -10,7 +10,7 @@ if [ "$MODE" = opt ] || [ "$MODE" = optlinux ]; then exit fi -mkdir -p o/$MODE/test/libc/release/ +$MKDIR o/$MODE/test/libc/release/ # smoke test booting on bare metal and printing data to serial uart CMD="o/$MODE/tool/build/blinkenlights.com.dbg -r o/$MODE/examples/hello.com" diff --git a/test/libc/release/test.mk b/test/libc/release/test.mk index ec61a09a3..b1edcb485 100644 --- a/test/libc/release/test.mk +++ b/test/libc/release/test.mk @@ -9,7 +9,15 @@ o/$(MODE)/test/libc/release/cosmopolitan.zip: \ o/$(MODE)/ape/ape-no-modify-self.o \ o/$(MODE)/cosmopolitan.a \ o/$(MODE)/third_party/zip/zip.com - @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -qj $@ o/cosmopolitan.h o/$(MODE)/ape/ape.lds o/$(MODE)/libc/crt/crt.o o/$(MODE)/ape/ape.o o/$(MODE)/ape/ape-no-modify-self.o o/$(MODE)/cosmopolitan.a + @$(COMPILE) -AZIP -T$@ \ + o/$(MODE)/third_party/zip/zip.com \ + -qj $@ \ + o/cosmopolitan.h \ + o/$(MODE)/ape/ape.lds \ + o/$(MODE)/libc/crt/crt.o \ + o/$(MODE)/ape/ape.o \ + o/$(MODE)/ape/ape-no-modify-self.o \ + o/$(MODE)/cosmopolitan.a o/$(MODE)/test/libc/release/smoke.com: \ o/$(MODE)/test/libc/release/smoke.com.dbg @@ -116,17 +124,17 @@ o/$(MODE)/test/libc/release/smokeansi.com.dbg: \ o/$(MODE)/ape/ape.o \ o/$(MODE)/cosmopolitan.a -o/$(MODE)/test/libc/release/metal.ok: \ - test/libc/release/metal.sh \ - o/$(MODE)/examples/hello.com \ - o/$(MODE)/tool/build/blinkenlights.com.dbg - @$(COMPILE) -ASHTEST -tT$@ $< - -o/$(MODE)/test/libc/release/emulate.ok: \ - test/libc/release/emulate.sh \ - o/$(MODE)/examples/hello.com \ - o/$(MODE)/tool/build/blinkenlights.com.dbg - @$(COMPILE) -ASHTEST -tT$@ $< +# TODO(jart): Rewrite these shell scripts as C code. +# o/$(MODE)/test/libc/release/metal.ok: \ +# test/libc/release/metal.sh \ +# o/$(MODE)/examples/hello.com \ +# o/$(MODE)/tool/build/blinkenlights.com.dbg +# @$(COMPILE) -ASHTEST -tT$@ $< +# o/$(MODE)/test/libc/release/emulate.ok: \ +# test/libc/release/emulate.sh \ +# o/$(MODE)/examples/hello.com \ +# o/$(MODE)/tool/build/blinkenlights.com.dbg +# @$(COMPILE) -ASHTEST -tT$@ $< .PHONY: o/$(MODE)/test/libc/release o/$(MODE)/test/libc/release: \ @@ -137,6 +145,4 @@ o/$(MODE)/test/libc/release: \ o/$(MODE)/test/libc/release/smokecxx.com \ o/$(MODE)/test/libc/release/smokecxx.com.runs \ o/$(MODE)/test/libc/release/smokeansi.com \ - o/$(MODE)/test/libc/release/smokeansi.com.runs \ - o/$(MODE)/test/libc/release/emulate.ok \ - o/$(MODE)/test/libc/release/metal.ok + o/$(MODE)/test/libc/release/smokeansi.com.runs diff --git a/test/libc/runtime/ape_test.c b/test/libc/runtime/ape_test.c new file mode 100644 index 000000000..bfee9dd8c --- /dev/null +++ b/test/libc/runtime/ape_test.c @@ -0,0 +1,128 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/sigbits.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/errno.h" +#include "libc/intrin/kprintf.h" +#include "libc/mem/io.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/sig.h" +#include "libc/testlib/testlib.h" + +STATIC_YOINK("zip_uri_support"); +STATIC_YOINK("apetest.com"); +STATIC_YOINK("apetest2.com"); + +char testlib_enable_tmp_setup_teardown_once; + +void Extract(const char *from, const char *to, int mode) { + ASSERT_SYS(0, 3, open(from, O_RDONLY)); + ASSERT_SYS(0, 4, creat(to, mode)); + ASSERT_NE(-1, _copyfd(3, 4, -1)); + EXPECT_SYS(0, 0, close(4)); + EXPECT_SYS(0, 0, close(3)); +} + +void SetUpOnce(void) { + + // nothing to do if we're using elf + if (~SUPPORT_VECTOR & (WINDOWS | XNU)) { + exit(0); + } + + ASSERT_SYS(0, 0, mkdir("bin", 0755)); + Extract("/zip/apetest.com", "bin/apetest.com", 0755); + Extract("/zip/apetest2.com", "bin/apetest2.com", 0755); + + // force the extraction of ape payload + // if system does not have binfmt_misc + ASSERT_SYS(0, 0, mkdir("tmp", 0755)); + setenv("TMPDIR", "tmp", true); +} + +void RunApeTest(const char *path) { + size_t n; + ssize_t rc, got; + char buf[512] = {0}; + sigset_t chldmask, savemask; + int i, pid, fdin, wstatus, pfds[2]; + struct sigaction ignore, saveint, savequit, savepipe; + ignore.sa_flags = 0; + ignore.sa_handler = SIG_IGN; + sigemptyset(&ignore.sa_mask); + sigaction(SIGINT, &ignore, &saveint); + sigaction(SIGQUIT, &ignore, &savequit); + sigaction(SIGPIPE, &ignore, &savepipe); + sigemptyset(&chldmask); + sigaddset(&chldmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &chldmask, &savemask); + ASSERT_SYS(0, 0, pipe2(pfds, O_CLOEXEC)); + ASSERT_NE(-1, (pid = fork())); + if (!pid) { + __strace = 0; + __ftrace = 0; + close(1); + dup(pfds[1]); + sigaction(SIGINT, &saveint, 0); + sigaction(SIGQUIT, &savequit, 0); + sigaction(SIGPIPE, &savepipe, 0); + sigprocmask(SIG_SETMASK, &savemask, 0); + execv(path, (char *const[]){path, 0}); + _Exit(127); + } + close(pfds[1]); + EXPECT_SYS(0, 8, read(pfds[0], buf, sizeof(buf))); + EXPECT_STREQ("success\n", buf); + close(pfds[0]); + EXPECT_NE(-1, wait(&wstatus)); + EXPECT_TRUE(WIFEXITED(wstatus)); + EXPECT_EQ(0, WEXITSTATUS(wstatus)); + sigaction(SIGINT, &saveint, 0); + sigaction(SIGQUIT, &savequit, 0); + sigaction(SIGPIPE, &savepipe, 0); + sigprocmask(SIG_SETMASK, &savemask, 0); + EXPECT_SYS(0, 3, open(path, O_RDONLY)); + EXPECT_SYS(0, 6, read(3, buf, 6)); + EXPECT_SYS(0, 0, close(3)); + EXPECT_STREQN("MZqFpD", buf, 6); +} + +TEST(ape, noAccidentalQuotesInMasterBootRecord) { + int i, quotes = 0; + char buf[512] = {0}; + EXPECT_SYS(0, 3, open("bin/apetest.com", O_RDONLY)); + EXPECT_SYS(0, 512, read(3, buf, 512)); + EXPECT_SYS(0, 0, close(3)); + for (i = 0; i < 512; ++i) { + if (buf[i] == '\'') { + ++quotes; + } + } + EXPECT_EQ(1, quotes); +} + +TEST(apeNoModifySelf, runsWithoutModifyingSelf) { + RunApeTest("bin/apetest.com"); +} + +TEST(apeCopySelf, runsWithoutModifyingSelf) { + RunApeTest("bin/apetest2.com"); +} diff --git a/test/libc/runtime/clone_test.c b/test/libc/runtime/clone_test.c index 6ce94214b..8c92f9ec6 100644 --- a/test/libc/runtime/clone_test.c +++ b/test/libc/runtime/clone_test.c @@ -19,52 +19,118 @@ #include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" +#include "libc/log/backtrace.internal.h" +#include "libc/mem/mem.h" +#include "libc/nexgen32e/nexgen32e.h" +#include "libc/nexgen32e/threaded.h" #include "libc/runtime/stack.h" +#include "libc/runtime/symbols.internal.h" #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/sig.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "libc/time/time.h" -char *stack; -int x, me, thechilde; -_Alignas(64) volatile char lock; +char *stack, *tls; +int x, me, tid, *childetid; +_Atomic(int) thechilde; void SetUp(void) { x = 0; - lock = 0; me = gettid(); - thechilde = 0; + tls = calloc(1, 64); + __initialize_tls(tls); + *(int *)(tls + 0x3c) = 31337; + childetid = (int *)(tls + 0x38); ASSERT_NE(MAP_FAILED, (stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, MAP_STACK | MAP_ANONYMOUS, -1, 0))); } void TearDown(void) { - tkill(thechilde, SIGKILL), errno = 0; - sched_yield(); EXPECT_SYS(0, 0, munmap(stack, GetStackSize())); + free(tls); +} + +int DoNothing(void *arg) { + CheckStackIsAligned(); + return 0; } int CloneTest1(void *arg) { + intptr_t rsp, top, bot; + CheckStackIsAligned(); + rsp = (intptr_t)__builtin_frame_address(0); + bot = (intptr_t)stack; + top = bot + GetStackSize(); + ASSERT_GT(rsp, bot); // check we're on stack + ASSERT_LT(rsp, top); // check we're on stack + ASSERT_GT(rsp, top - 256); // check we're near top of stack + ASSERT_TRUE(IS2POW(GetStackSize())); + ASSERT_EQ(0, bot & (GetStackSize() - 1)); x = 42; + if (!IsWindows()) { + ASSERT_EQ(31337, errno); + } else { + errno = 31337; + ASSERT_EQ(31337, errno); + } ASSERT_EQ(23, (intptr_t)arg); - thechilde = gettid(); ASSERT_NE(gettid(), getpid()); - _spunlock(&lock); + ASSERT_EQ(gettid(), *childetid); // CLONE_CHILD_SETTID return 0; } TEST(clone, test1) { - int tid; - _spinlock(&lock); + int ptid = 0; + *childetid = -1; + _seizelock(childetid); ASSERT_NE(-1, (tid = clone(CloneTest1, stack, GetStackSize(), CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | - CLONE_SIGHAND, - (void *)23, 0, 0, 0, 0))); - _spinlock(&lock); + CLONE_SIGHAND | CLONE_PARENT_SETTID | + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | + CLONE_SETTLS, + (void *)23, &ptid, tls, 64, childetid))); + _spinlock(childetid); // CLONE_CHILD_CLEARTID + ASSERT_NE(gettid(), tid); + ASSERT_EQ(tid, ptid); ASSERT_EQ(42, x); ASSERT_NE(me, tid); - ASSERT_EQ(tid, thechilde); + ASSERT_EQ(0, errno); + errno = 31337; + ASSERT_EQ(31337, errno); + errno = 0; +} + +int CloneTestSys(void *arg) { + CheckStackIsAligned(); + thechilde = gettid(); + ASSERT_EQ(31337, errno); + open(0, 0); + ASSERT_EQ(EFAULT, errno); + return 0; +} + +TEST(clone, tlsSystemCallsErrno_wontClobberMainThreadBecauseTls) { + ASSERT_EQ(0, errno); + ASSERT_EQ(31337, *(int *)(tls + 0x3c)); + _seizelock(childetid); + ASSERT_NE(-1, (tid = clone(CloneTestSys, stack, GetStackSize(), + CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_CHILD_SETTID | + CLONE_CHILD_CLEARTID | CLONE_SETTLS, + (void *)23, 0, tls, 64, childetid))); + _spinlock(childetid); // CLONE_CHILD_CLEARTID + ASSERT_EQ(0, errno); + ASSERT_EQ(EFAULT, *(int *)(tls + 0x3c)); +} + +BENCH(clone, bench) { + errno_t *volatile ep; + char *volatile tp; + EZBENCH2("__errno_location", donothing, (ep = __errno_location())); + EZBENCH2("__get_tls", donothing, (tp = __get_tls())); } diff --git a/test/libc/runtime/memtrack_test.c b/test/libc/runtime/memtrack_test.c index 200ec8a2e..a9c9a4888 100644 --- a/test/libc/runtime/memtrack_test.c +++ b/test/libc/runtime/memtrack_test.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/errno.h" +#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/log/check.h" #include "libc/mem/mem.h" @@ -26,6 +27,9 @@ #include "libc/str/str.h" #include "libc/testlib/testlib.h" +#define I(x, y) \ + { x, y, 0, (y - x) * FRAMESIZE + FRAMESIZE } + static bool AreMemoryIntervalsEqual(const struct MemoryIntervals *mm1, const struct MemoryIntervals *mm2) { if (mm1->i != mm2->i) return false; @@ -45,8 +49,10 @@ static void PrintMemoryInterval(const struct MemoryIntervals *mm) { static void CheckMemoryIntervalsEqual(const struct MemoryIntervals *mm1, const struct MemoryIntervals *mm2) { if (!AreMemoryIntervalsEqual(mm1, mm2)) { - PrintMemoryInterval(mm1); - PrintMemoryInterval(mm2); + kprintf("got:\n"); + PrintMemoryIntervals(2, mm1); + kprintf("want:\n"); + PrintMemoryIntervals(2, mm2); CHECK(!"memory intervals not equal"); exit(1); } @@ -65,7 +71,8 @@ static void RunTrackMemoryIntervalTest(const struct MemoryIntervals t[2], int x, struct MemoryIntervals *mm; mm = memcpy(memalign(64, sizeof(*t)), t, sizeof(*t)); CheckMemoryIntervalsAreOk(mm); - CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0, 0, 0)); + CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0, 0, + (y - x) * FRAMESIZE + FRAMESIZE)); CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsEqual(mm, t + 1); free(mm); @@ -88,7 +95,7 @@ static int RunReleaseMemoryIntervalsTest(const struct MemoryIntervals t[2], TEST(TrackMemoryInterval, TestEmpty) { static struct MemoryIntervals mm[2] = { {0, OPEN_MAX, 0, {}}, - {1, OPEN_MAX, 0, {{2, 2, 0}}}, + {1, OPEN_MAX, 0, {{2, 2, 0, FRAMESIZE}}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -114,8 +121,8 @@ TEST(TrackMemoryInterval, TestFull) { TEST(TrackMemoryInterval, TestAppend) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{2, 2}}}, - {1, OPEN_MAX, 0, {{2, 3}}}, + {1, OPEN_MAX, 0, {I(2, 2)}}, + {1, OPEN_MAX, 0, {I(2, 3)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -124,8 +131,8 @@ TEST(TrackMemoryInterval, TestAppend) { TEST(TrackMemoryInterval, TestPrepend) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{2, 2}}}, - {1, OPEN_MAX, 0, {{1, 2}}}, + {1, OPEN_MAX, 0, {I(2, 2)}}, + {1, OPEN_MAX, 0, {I(1, 2)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -134,8 +141,8 @@ TEST(TrackMemoryInterval, TestPrepend) { TEST(TrackMemoryInterval, TestFillHole) { static struct MemoryIntervals mm[2] = { - {4, OPEN_MAX, 0, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, - {3, OPEN_MAX, 0, {{1, 4}, {5, 5, 1}, {6, 8}}}, + {4, OPEN_MAX, 0, {I(1, 1), I(3, 4), {5, 5, 1, FRAMESIZE}, I(6, 8)}}, + {3, OPEN_MAX, 0, {I(1, 4), {5, 5, 1, FRAMESIZE}, I(6, 8)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -144,8 +151,8 @@ TEST(TrackMemoryInterval, TestFillHole) { TEST(TrackMemoryInterval, TestAppend2) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{2, 2}}}, - {2, OPEN_MAX, 0, {{2, 2}, {3, 3, 1}}}, + {1, OPEN_MAX, 0, {I(2, 2)}}, + {2, OPEN_MAX, 0, {I(2, 2), {3, 3, 1, FRAMESIZE}}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -154,8 +161,8 @@ TEST(TrackMemoryInterval, TestAppend2) { TEST(TrackMemoryInterval, TestPrepend2) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{2, 2}}}, - {2, OPEN_MAX, 0, {{1, 1, 1}, {2, 2}}}, + {1, OPEN_MAX, 0, {I(2, 2)}}, + {2, OPEN_MAX, 0, {{1, 1, 1, FRAMESIZE}, I(2, 2)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -164,8 +171,25 @@ TEST(TrackMemoryInterval, TestPrepend2) { TEST(TrackMemoryInterval, TestFillHole2) { static struct MemoryIntervals mm[2] = { - {4, OPEN_MAX, 0, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, - {5, OPEN_MAX, 0, {{1, 1}, {2, 2, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, + {4, + OPEN_MAX, + 0, + { + I(1, 1), + I(3, 4), + {5, 5, 1, FRAMESIZE}, + I(6, 8), + }}, + {5, + OPEN_MAX, + 0, + { + I(1, 1), + {2, 2, 1, FRAMESIZE}, + {3, 4, 0, FRAMESIZE * 2}, + {5, 5, 1, FRAMESIZE}, + {6, 8, 0, FRAMESIZE * 3}, + }}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -211,8 +235,8 @@ TEST(ReleaseMemoryIntervals, TestEmpty) { TEST(ReleaseMemoryIntervals, TestRemoveElement_UsesInclusiveRange) { static struct MemoryIntervals mm[2] = { - {3, OPEN_MAX, 0, {{0, 0}, {2, 2}, {4, 4}}}, - {2, OPEN_MAX, 0, {{0, 0}, {4, 4}}}, + {3, OPEN_MAX, 0, {I(0, 0), I(2, 2), I(4, 4)}}, + {2, OPEN_MAX, 0, {I(0, 0), I(4, 4)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -221,8 +245,8 @@ TEST(ReleaseMemoryIntervals, TestRemoveElement_UsesInclusiveRange) { TEST(ReleaseMemoryIntervals, TestPunchHole) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {2, OPEN_MAX, 0, {{0, 3}, {6, 9}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {2, OPEN_MAX, 0, {I(0, 3), I(6, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -232,8 +256,8 @@ TEST(ReleaseMemoryIntervals, TestPunchHole) { TEST(ReleaseMemoryIntervals, TestShortenLeft) { if (IsWindows()) return; static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {1, OPEN_MAX, 0, {{0, 7}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {1, OPEN_MAX, 0, {I(0, 7)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -243,8 +267,8 @@ TEST(ReleaseMemoryIntervals, TestShortenLeft) { TEST(ReleaseMemoryIntervals, TestShortenRight) { if (IsWindows()) return; static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -254,8 +278,8 @@ TEST(ReleaseMemoryIntervals, TestShortenRight) { TEST(ReleaseMemoryIntervals, TestShortenLeft2) { if (IsWindows()) return; static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {1, OPEN_MAX, 0, {{0, 7}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {1, OPEN_MAX, 0, {I(0, 7)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -265,8 +289,8 @@ TEST(ReleaseMemoryIntervals, TestShortenLeft2) { TEST(ReleaseMemoryIntervals, TestShortenRight2) { if (IsWindows()) return; static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{0, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(0, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -275,8 +299,8 @@ TEST(ReleaseMemoryIntervals, TestShortenRight2) { TEST(ReleaseMemoryIntervals, TestZeroZero) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{3, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -285,8 +309,8 @@ TEST(ReleaseMemoryIntervals, TestZeroZero) { TEST(ReleaseMemoryIntervals, TestNoopLeft) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{3, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -295,8 +319,8 @@ TEST(ReleaseMemoryIntervals, TestNoopLeft) { TEST(ReleaseMemoryIntervals, TestNoopRight) { static struct MemoryIntervals mm[2] = { - {1, OPEN_MAX, 0, {{3, 9}}}, - {1, OPEN_MAX, 0, {{3, 9}}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, + {1, OPEN_MAX, 0, {I(3, 9)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; @@ -305,7 +329,7 @@ TEST(ReleaseMemoryIntervals, TestNoopRight) { TEST(ReleaseMemoryIntervals, TestBigFree) { static struct MemoryIntervals mm[2] = { - {2, OPEN_MAX, 0, {{0, 3}, {6, 9}}}, + {2, OPEN_MAX, 0, {I(0, 3), I(6, 9)}}, {0, OPEN_MAX, 0, {}}, }; mm[0].p = mm[0].s; @@ -315,8 +339,8 @@ TEST(ReleaseMemoryIntervals, TestBigFree) { TEST(ReleaseMemoryIntervals, TestWeirdGap) { static struct MemoryIntervals mm[2] = { - {3, OPEN_MAX, 0, {{10, 10}, {20, 20}, {30, 30}}}, - {2, OPEN_MAX, 0, {{10, 10}, {30, 30}}}, + {3, OPEN_MAX, 0, {I(10, 10), I(20, 20), I(30, 30)}}, + {2, OPEN_MAX, 0, {I(10, 10), I(30, 30)}}, }; mm[0].p = mm[0].s; mm[1].p = mm[1].s; diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index a777fdcc2..15e5da374 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -16,10 +16,13 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" #include "libc/bits/bits.h" #include "libc/bits/xchg.internal.h" #include "libc/calls/calls.h" +#include "libc/calls/ucontext.h" #include "libc/dce.h" +#include "libc/errno.h" #include "libc/fmt/fmt.h" #include "libc/intrin/kprintf.h" #include "libc/linux/mmap.h" @@ -36,12 +39,51 @@ #include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" +#include "third_party/xed/x86.h" char testlib_enable_tmp_setup_teardown; +TEST(mmap, zeroSize) { + ASSERT_SYS(EINVAL, MAP_FAILED, + mmap(NULL, 0, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); +} + +TEST(mmap, overflow) { + ASSERT_SYS(EINVAL, MAP_FAILED, + mmap(NULL, 0x800000000000, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0)); + ASSERT_SYS(EINVAL, MAP_FAILED, + mmap(NULL, 0x7fffffffffff, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0)); +} + +TEST(mmap, outOfAutomapRange) { + ASSERT_SYS( + ENOMEM, MAP_FAILED, + mmap(NULL, kAutomapSize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); +} + +TEST(mmap, noreplaceImage) { + ASSERT_SYS(EEXIST, MAP_FAILED, + mmap(_base, FRAMESIZE, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0)); +} + +TEST(mmap, noreplaceExistingMap) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + ASSERT_SYS(EEXIST, MAP_FAILED, + mmap(p, FRAMESIZE, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); +} + TEST(mmap, testMapFile) { int fd; char *p; @@ -143,6 +185,25 @@ TEST(mmap, mapPrivate_writesDontChangeFile) { EXPECT_NE(-1, close(fd)); } +TEST(mmap, twoPowerSize_automapsAddressWithThatAlignment) { + char *q, *p; + // increase the likelihood automap is unaligned w.r.t. following call + ASSERT_NE(MAP_FAILED, (q = mmap(NULL, 0x00010000, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0))); + // ask for a nice big round size + ASSERT_NE(MAP_FAILED, (p = mmap(NULL, 0x00080000, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0))); + // verify it's aligned + ASSERT_EQ(0, (intptr_t)p & 0x0007ffff); + EXPECT_SYS(0, 0, munmap(p, 0x00080000)); + // now try again with a big size that isn't a two power + ASSERT_NE(MAP_FAILED, (p = mmap(NULL, 0x00070000, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0))); + // automap doesn't bother aligning it + ASSERT_NE(0, (intptr_t)p & 0x0007ffff); + EXPECT_SYS(0, 0, munmap(q, 0x00010000)); +} + TEST(isheap, nullPtr) { ASSERT_FALSE(_isheap(NULL)); } @@ -168,6 +229,7 @@ TEST(mmap, cow) { char *p; char path[PATH_MAX]; sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64()); + kprintf("path = %#s\n", path); ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644))); EXPECT_EQ(5, write(fd, "hello", 5)); EXPECT_NE(-1, fdatasync(fd)); diff --git a/test/libc/runtime/munmap_test.c b/test/libc/runtime/munmap_test.c new file mode 100644 index 000000000..3cbbafa68 --- /dev/null +++ b/test/libc/runtime/munmap_test.c @@ -0,0 +1,253 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/atomic.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" +#include "libc/intrin/kprintf.h" +#include "libc/runtime/memtrack.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sa.h" +#include "libc/testlib/testlib.h" +#include "third_party/xed/x86.h" + +volatile int gotsignal; +char testlib_enable_tmp_setup_teardown; + +void ContinueOnError(int sig, siginfo_t *si, ucontext_t *ctx) { + struct XedDecodedInst xedd; + xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); + xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); + ctx->uc_mcontext.rip += xedd.length; + gotsignal = sig; +} + +noasan bool MemoryExists(char *p) { + volatile char c; + struct sigaction old[2]; + struct sigaction sa = { + .sa_sigaction = ContinueOnError, + .sa_flags = SA_SIGINFO, + }; + gotsignal = 0; + sigaction(SIGSEGV, &sa, old + 0); + sigaction(SIGBUS, &sa, old + 1); + c = atomic_load(p); + sigaction(SIGSEGV, old + 0, 0); + sigaction(SIGBUS, old + 1, 0); + return !gotsignal; +} + +TEST(munmap, doesntExist_doesntCare) { + EXPECT_SYS(0, 0, munmap(0, FRAMESIZE * 8)); + if (IsAsan()) { + // make sure it didn't unmap the null pointer shadow memory + EXPECT_TRUE(MemoryExists((char *)0x7fff8000)); + } +} + +TEST(munmap, test) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p)); +} + +TEST(munmap, invalidParams) { + EXPECT_SYS(EINVAL, -1, munmap(0, 0)); + EXPECT_SYS(EINVAL, -1, munmap((void *)0x100080000000, 0)); + EXPECT_SYS(EINVAL, -1, munmap((void *)0x100080000001, FRAMESIZE)); +} + +TEST(munmap, punchHoleInMemory) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 2, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 2)); +} + +TEST(munmap, memoryHasHole) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 3)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 2)); +} + +TEST(munmap, blanketFree) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 3, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 0, FRAMESIZE)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE * 2, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 2)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 3)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 2)); +} + +TEST(munmap, trimLeft) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 2, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 2)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); +} + +TEST(munmap, trimRight) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE * 2, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_SYS(0, 0, munmap(p + FRAMESIZE, FRAMESIZE)); + EXPECT_TRUE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE * 2)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 0)); + EXPECT_FALSE(MemoryExists(p + FRAMESIZE * 1)); +} + +TEST(munmap, memoryGone) { + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); +} + +TEST(munmap, testTooSmallToUnmapAsan) { + if (!IsAsan()) return; + char *p; + ASSERT_NE(MAP_FAILED, (p = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_TRUE(MemoryExists((char *)(((intptr_t)p >> 3) + 0x7fff8000))); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_TRUE(MemoryExists((char *)(((intptr_t)p >> 3) + 0x7fff8000))); +} + +TEST(munmap, testLargeEnoughToUnmapAsan) { + if (!IsAsan()) return; + if (IsWindows()) { + // we're unfortunately never able to unmap asan pages on windows + // because the memtrack array items always have to be 64kb so we + // we're able to store a handle for each + return; + } + char *p; + size_t n; + n = FRAMESIZE * 8 * 2; + ASSERT_NE(MAP_FAILED, (p = mmap(0, n, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + EXPECT_SYS(0, 0, munmap(p, n)); +#if 0 + EXPECT_FALSE( + MemoryExists((char *)(((intptr_t)(p + n / 2) >> 3) + 0x7fff8000))); +#endif +} + +TEST(munmap, tinyFile_roundupUnmapSize) { + char *p; + ASSERT_SYS(0, 3, open("doge", O_WRONLY | O_CREAT | O_TRUNC, 0644)); + ASSERT_SYS(0, 5, write(3, "hello", 5)); + ASSERT_SYS(0, 0, close(3)); + ASSERT_SYS(0, 3, open("doge", O_RDONLY)); + ASSERT_NE(MAP_FAILED, (p = mmap(0, 5, PROT_READ, MAP_PRIVATE, 3, 0))); + ASSERT_SYS(0, 0, close(3)); + EXPECT_TRUE(MemoryExists(p)); + // some kernels/versions support this, some don't + EXPECT_FALSE(MemoryExists(p + PAGESIZE)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE)); + EXPECT_FALSE(MemoryExists(p)); + EXPECT_FALSE(MemoryExists(p + 5)); +} + +TEST(munmap, tinyFile_preciseUnmapSize) { + char *p, *q; + ASSERT_SYS(0, 3, open("doge", O_WRONLY | O_CREAT | O_TRUNC, 0644)); + ASSERT_SYS(0, 5, write(3, "hello", 5)); + ASSERT_SYS(0, 0, close(3)); + ASSERT_SYS(0, 3, open("doge", O_RDONLY)); + ASSERT_NE(MAP_FAILED, (p = mmap(0, 5, PROT_READ, MAP_PRIVATE, 3, 0))); + ASSERT_NE(MAP_FAILED, (q = mmap(0, 5, PROT_READ, MAP_PRIVATE, 3, 0))); + ASSERT_SYS(0, 0, close(3)); + EXPECT_TRUE(MemoryExists(p)); + EXPECT_TRUE(MemoryExists(q)); + EXPECT_SYS(0, 0, munmap(p, 5)); + EXPECT_FALSE(MemoryExists(p)); + EXPECT_TRUE(MemoryExists(q)); + EXPECT_SYS(0, 0, munmap(q, 5)); + EXPECT_FALSE(MemoryExists(q)); +} + +// clang-format off +TEST(munmap, tinyFile_mapThriceUnmapOnce) { + char *p = (char *)0x02000000; + ASSERT_SYS(0, 3, open("doge", O_RDWR | O_CREAT | O_TRUNC, 0644)); + ASSERT_SYS (0, 5, write(3, "hello", 5)); + ASSERT_NE(MAP_FAILED, mmap(p+FRAMESIZE*0, FRAMESIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0)); + ASSERT_NE(MAP_FAILED, mmap(p+FRAMESIZE*1, 5, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0)); + ASSERT_NE(MAP_FAILED, mmap(p+FRAMESIZE*3, 5, PROT_READ, MAP_PRIVATE|MAP_FIXED, 3, 0)); + ASSERT_SYS(0, 0, close(3)); + EXPECT_TRUE(MemoryExists(p+FRAMESIZE*0)); + EXPECT_TRUE(MemoryExists(p+FRAMESIZE*1)); + EXPECT_FALSE(MemoryExists(p+FRAMESIZE*2)); + EXPECT_TRUE(MemoryExists(p+FRAMESIZE*3)); + EXPECT_SYS(0, 0, munmap(p, FRAMESIZE*5)); + EXPECT_FALSE(MemoryExists(p+FRAMESIZE*0)); + EXPECT_FALSE(MemoryExists(p+FRAMESIZE*1)); + EXPECT_FALSE(MemoryExists(p+FRAMESIZE*2)); + EXPECT_FALSE(MemoryExists(p+FRAMESIZE*3)); +} +// clang-format on diff --git a/test/libc/runtime/test.mk b/test/libc/runtime/test.mk index 2b1b75b95..05c56c00f 100644 --- a/test/libc/runtime/test.mk +++ b/test/libc/runtime/test.mk @@ -41,6 +41,8 @@ TEST_LIBC_RUNTIME_DIRECTDEPS = \ LIBC_TINYMATH \ LIBC_UNICODE \ LIBC_X \ + LIBC_ZIPOS \ + TOOL_BUILD_LIB \ THIRD_PARTY_XED TEST_LIBC_RUNTIME_DEPS := \ @@ -56,7 +58,16 @@ o/$(MODE)/test/libc/runtime/%.com.dbg: \ o/$(MODE)/test/libc/runtime/runtime.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) + @$(APELINK) + +o/$(MODE)/test/libc/runtime/ape_test.com.dbg: \ + $(TEST_LIBC_RUNTIME_DEPS) \ + o/$(MODE)/test/libc/runtime/ape_test.o \ + o/$(MODE)/test/libc/runtime/runtime.pkg \ + $(LIBC_TESTMAIN) \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_RUNTIME_OBJS): \ @@ -67,7 +78,6 @@ o/$(MODE)/test/libc/runtime/getenv_test.com.runs: \ o/$(MODE)/test/libc/runtime/getenv_test.com @HELLO=THERE build/runit $@ $< -o/$(MODE)/test/libc/runtime/fun_test.o \ o/$(MODE)/test/libc/runtime/itsatrap_test.o: \ OVERRIDE_CFLAGS += \ -fno-sanitize=all \ diff --git a/test/libc/sock/sendfile_test.c b/test/libc/sock/sendfile_test.c new file mode 100644 index 000000000..9b202364a --- /dev/null +++ b/test/libc/sock/sendfile_test.c @@ -0,0 +1,71 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/sock/sock.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/ipproto.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/sock.h" +#include "libc/testlib/hyperion.h" +#include "libc/testlib/testlib.h" + +char testlib_enable_tmp_setup_teardown; + +TEST(sendfile, test) { + int ws; + char *buf; + int64_t inoffset; + uint32_t addrsize = sizeof(struct sockaddr_in); + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(0x7f000001), + }; + ASSERT_SYS(0, 3, creat("hyperion.txt", 0644)); + ASSERT_SYS(0, 512, write(3, kHyperion, 512)); + ASSERT_SYS(0, 0, close(3)); + ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); + ASSERT_SYS(0, 0, bind(3, &addr, sizeof(addr))); + ASSERT_SYS(0, 0, getsockname(3, &addr, &addrsize)); + ASSERT_SYS(0, 0, listen(3, 1)); + if (!fork()) { + inoffset = 0; + ASSERT_SYS(0, 4, accept(3, &addr, &addrsize)); + ASSERT_SYS(0, 5, open("hyperion.txt", O_RDONLY)); + ASSERT_SYS(0, 512, sendfile(4, 5, &inoffset, 512)); + EXPECT_EQ(512, inoffset); + ASSERT_SYS(0, 0, close(5)); + ASSERT_SYS(0, 0, close(4)); + ASSERT_SYS(0, 0, close(3)); + _Exit(0); + } + buf = gc(malloc(512)); + EXPECT_SYS(0, 0, close(3)); + EXPECT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); + EXPECT_SYS(0, 0, connect(3, &addr, sizeof(addr))); + EXPECT_SYS(0, 512, read(3, buf, 512)); + EXPECT_EQ(0, memcmp(buf, kHyperion, 512)); + EXPECT_SYS(0, 0, close(3)); + EXPECT_NE(-1, wait(&ws)); + ASSERT_TRUE(WIFEXITED(ws)); + ASSERT_EQ(0, WEXITSTATUS(ws)); +} diff --git a/test/libc/sock/test.mk b/test/libc/sock/test.mk index 961a53c4a..375d3e4fc 100644 --- a/test/libc/sock/test.mk +++ b/test/libc/sock/test.mk @@ -51,7 +51,7 @@ o/$(MODE)/test/libc/sock/%.com.dbg: \ o/$(MODE)/test/libc/sock/sock.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk diff --git a/test/libc/stdio/fgetln_test.c b/test/libc/stdio/fgetln_test.c new file mode 100644 index 000000000..7cba463c6 --- /dev/null +++ b/test/libc/stdio/fgetln_test.c @@ -0,0 +1,87 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/hyperion.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +TEST(fgetln, test) { + FILE *f; + f = fmemopen(gc(strdup(kHyperion)), kHyperionSize, "r+"); + EXPECT_STREQ("The fall of Hyperion - a Dream\n", fgetln(f, 0)); + EXPECT_STREQ("John Keats\n", fgetln(f, 0)); + EXPECT_STREQ("\n", fgetln(f, 0)); + fclose(f); +} + +TEST(fgetln, testGoodLastLine) { + FILE *f; + size_t n; + f = fmemopen("foo\nbar\n", 8, "r"); + EXPECT_STREQ("foo\n", fgetln(f, &n)); + EXPECT_EQ(4, n); + EXPECT_STREQ("bar\n", fgetln(f, &n)); + EXPECT_EQ(4, n); + EXPECT_EQ(NULL, fgetln(f, 0)); + EXPECT_FALSE(ferror(f)); + EXPECT_TRUE(feof(f)); + fclose(f); +} + +TEST(fgetln, testEvilLastLine) { + FILE *f; + f = fmemopen("foo\nbar", 7, "r"); + EXPECT_STREQ("foo\n", fgetln(f, 0)); + EXPECT_STREQ("bar", fgetln(f, 0)); + EXPECT_EQ(NULL, fgetln(f, 0)); + EXPECT_FALSE(ferror(f)); + EXPECT_TRUE(feof(f)); + fclose(f); +} + +TEST(fgetln, testReadingFromStdin_doesntLeakMemory) { + FILE *f; + int oldstdin, pfds[2]; + oldstdin = dup(0); + EXPECT_SYS(0, 0, pipe(pfds)); + EXPECT_SYS(0, 8, write(pfds[1], "foo\nbar\n", 8)); + EXPECT_SYS(0, 0, close(pfds[1])); + EXPECT_SYS(0, 0, close(0)); + EXPECT_SYS(0, 0, dup(pfds[0])); + EXPECT_SYS(0, 0, close(pfds[0])); + EXPECT_STREQ("foo\n", fgetln(stdin, 0)); + EXPECT_STREQ("bar\n", fgetln(stdin, 0)); + EXPECT_EQ(NULL, fgetln(stdin, 0)); + EXPECT_FALSE(ferror(stdin)); + EXPECT_TRUE(feof(stdin)); + EXPECT_SYS(0, 0, close(0)); + EXPECT_SYS(0, 0, dup(oldstdin)); + clearerr(stdin); +} + +BENCH(fgetln, bench) { + FILE *f = fmemopen(gc(strdup(kHyperion)), kHyperionSize, "r+"); + EZBENCH2("fgetln", donothing, fgetln(f, 0)); + EZBENCH2("xgetline", donothing, free(xgetline(f))); + fclose(f); +} diff --git a/test/libc/stdio/fputc_test.c b/test/libc/stdio/fputc_test.c index 9c2d47888..98253452b 100644 --- a/test/libc/stdio/fputc_test.c +++ b/test/libc/stdio/fputc_test.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/stdio/stdio.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" FILE *f; @@ -60,3 +61,13 @@ TEST(fgetc, testUnbuffered) { EXPECT_TRUE(feof(f)); EXPECT_NE(-1, fclose(f)); } + +BENCH(fputc, bench) { + FILE *f; + ASSERT_NE(NULL, (f = fopen("/dev/null", "w"))); + EZBENCH2("fputc", donothing, fputc('E', f)); + flockfile(f); + EZBENCH2("fputc_unlocked", donothing, fputc_unlocked('E', f)); + funlockfile(f); + fclose(f); +} diff --git a/test/libc/stdio/test.mk b/test/libc/stdio/test.mk index 468f42497..8eb805252 100644 --- a/test/libc/stdio/test.mk +++ b/test/libc/stdio/test.mk @@ -57,7 +57,7 @@ o/$(MODE)/test/libc/stdio/%.com.dbg: \ o/$(MODE)/test/libc/stdio/stdio.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_STDIO_OBJS): \ diff --git a/test/libc/str/classifypath_test.c b/test/libc/str/classifypath_test.c index 174ae9172..666ab280a 100644 --- a/test/libc/str/classifypath_test.c +++ b/test/libc/str/classifypath_test.c @@ -50,72 +50,72 @@ TEST(_classifypath, test) { if (!SupportsWindows()) return; EXPECT_EQ(0, _classifypath("")); EXPECT_EQ(0, _classifypath("xyz")); - EXPECT_EQ(_PATH_DOS | _PATH_DEV, _classifypath("CON")); - EXPECT_EQ(_PATH_DOS | _PATH_DEV, _classifypath("NUL")); + EXPECT_EQ(_kPathDos | _kPathDev, _classifypath("CON")); + EXPECT_EQ(_kPathDos | _kPathDev, _classifypath("NUL")); EXPECT_EQ(0, _classifypath(":")); - EXPECT_EQ(_PATH_DOS, _classifypath("::")); - EXPECT_EQ(_PATH_DOS, _classifypath(":::")); - EXPECT_EQ(_PATH_DOS, _classifypath("::::")); - EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("::\\")); - EXPECT_EQ(_PATH_ABS, _classifypath("\\")); - EXPECT_EQ(_PATH_ABS, _classifypath("\\:")); - EXPECT_EQ(_PATH_ABS, _classifypath("\\C:")); - EXPECT_EQ(_PATH_ABS, _classifypath("\\C:\\")); - EXPECT_EQ(_PATH_ABS, _classifypath("/")); - EXPECT_EQ(_PATH_ABS, _classifypath("/:")); - EXPECT_EQ(_PATH_ABS, _classifypath("/C:")); - EXPECT_EQ(_PATH_ABS, _classifypath("/C:/")); + EXPECT_EQ(_kPathDos, _classifypath("::")); + EXPECT_EQ(_kPathDos, _classifypath(":::")); + EXPECT_EQ(_kPathDos, _classifypath("::::")); + EXPECT_EQ(_kPathAbs | _kPathDos, _classifypath("::\\")); + EXPECT_EQ(_kPathAbs, _classifypath("\\")); + EXPECT_EQ(_kPathAbs, _classifypath("\\:")); + EXPECT_EQ(_kPathAbs, _classifypath("\\C:")); + EXPECT_EQ(_kPathAbs, _classifypath("\\C:\\")); + EXPECT_EQ(_kPathAbs, _classifypath("/")); + EXPECT_EQ(_kPathAbs, _classifypath("/:")); + EXPECT_EQ(_kPathAbs, _classifypath("/C:")); + EXPECT_EQ(_kPathAbs, _classifypath("/C:/")); EXPECT_EQ(0, _classifypath("C")); - EXPECT_EQ(_PATH_DOS, _classifypath("C:")); - EXPECT_EQ(_PATH_DOS, _classifypath("C:a")); - EXPECT_EQ(_PATH_DOS, _classifypath("C:a\\")); - EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:\\")); - EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:/")); - EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:\\a")); - EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:/a")); - EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:\\\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\;")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\f\\b\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\f\\b")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\f\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\f")); - EXPECT_EQ(_PATH_ABS | _PATH_NT, _classifypath("\\??\\")); - EXPECT_EQ(_PATH_ABS | _PATH_NT, _classifypath("\\??\\UNC")); - EXPECT_EQ(_PATH_ABS | _PATH_NT, _classifypath("\\??\\UNC\\")); - EXPECT_EQ(_PATH_ABS, _classifypath("\\?")); - EXPECT_EQ(_PATH_ABS, _classifypath("\\?\\")); - EXPECT_EQ(_PATH_ABS, _classifypath("\\?\\UNC")); - EXPECT_EQ(_PATH_ABS, _classifypath("\\?\\UNC\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("\\\\?\\UNC\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT, + EXPECT_EQ(_kPathDos, _classifypath("C:")); + EXPECT_EQ(_kPathDos, _classifypath("C:a")); + EXPECT_EQ(_kPathDos, _classifypath("C:a\\")); + EXPECT_EQ(_kPathAbs | _kPathDos, _classifypath("C:\\")); + EXPECT_EQ(_kPathAbs | _kPathDos, _classifypath("C:/")); + EXPECT_EQ(_kPathAbs | _kPathDos, _classifypath("C:\\a")); + EXPECT_EQ(_kPathAbs | _kPathDos, _classifypath("C:/a")); + EXPECT_EQ(_kPathAbs | _kPathDos, _classifypath("C:\\\\")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\\\")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\;")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\f\\b\\")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\f\\b")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\f\\")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\f")); + EXPECT_EQ(_kPathAbs | _kPathNt, _classifypath("\\??\\")); + EXPECT_EQ(_kPathAbs | _kPathNt, _classifypath("\\??\\UNC")); + EXPECT_EQ(_kPathAbs | _kPathNt, _classifypath("\\??\\UNC\\")); + EXPECT_EQ(_kPathAbs, _classifypath("\\?")); + EXPECT_EQ(_kPathAbs, _classifypath("\\?\\")); + EXPECT_EQ(_kPathAbs, _classifypath("\\?\\UNC")); + EXPECT_EQ(_kPathAbs, _classifypath("\\?\\UNC\\")); + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev, _classifypath("\\\\?\\UNC\\")); + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev | _kPathRoot, _classifypath("\\\\?")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\??")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\??\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\??\\C:\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT, + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\??")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\??\\")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\\\??\\C:\\")); + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev | _kPathRoot, _classifypath("\\\\.")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("\\\\.\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("\\\\.\\C:\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\/")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("/\\")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("//")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("///")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("//;")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT, + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev, _classifypath("\\\\.\\")); + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev, _classifypath("\\\\.\\C:\\")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("\\/")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("/\\")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("//")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("///")); + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("//;")); + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev | _kPathRoot, _classifypath("//?")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT, + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev | _kPathRoot, _classifypath("/\\?")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT, + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev | _kPathRoot, _classifypath("\\/?")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("//??")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT, + EXPECT_EQ(_kPathAbs | _kPathWin, _classifypath("//??")); + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev | _kPathRoot, _classifypath("//.")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT, + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev | _kPathRoot, _classifypath("\\/.")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT, + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev | _kPathRoot, _classifypath("/\\.")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("//./")); - EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("//./C:/")); + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev, _classifypath("//./")); + EXPECT_EQ(_kPathAbs | _kPathWin | _kPathDev, _classifypath("//./C:/")); } diff --git a/test/libc/str/test.mk b/test/libc/str/test.mk index 6efecbbf3..1bcd04d7e 100644 --- a/test/libc/str/test.mk +++ b/test/libc/str/test.mk @@ -3,24 +3,32 @@ PKGS += TEST_LIBC_STR -TEST_LIBC_STR_SRCS := $(wildcard test/libc/str/*.c) -TEST_LIBC_STR_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_STR_SRCS)) +TEST_LIBC_STR_FILES := $(wildcard test/libc/str/*) +TEST_LIBC_STR_SRCS_C = $(filter %.c,$(TEST_LIBC_STR_FILES)) +TEST_LIBC_STR_SRCS_CC = $(filter %.cc,$(TEST_LIBC_STR_FILES)) +TEST_LIBC_STR_SRCS = $(TEST_LIBC_STR_SRCS_C) $(TEST_LIBC_STR_SRCS_CC) +TEST_LIBC_STR_SRCS_TEST_C = $(filter %_test.c,$(TEST_LIBC_STR_FILES)) +TEST_LIBC_STR_SRCS_TEST_CC = $(filter %_test.cc,$(TEST_LIBC_STR_FILES)) TEST_LIBC_STR_OBJS = \ - $(TEST_LIBC_STR_SRCS:%.c=o/$(MODE)/%.o) + $(TEST_LIBC_STR_SRCS_C:%.c=o/$(MODE)/%.o) \ + $(TEST_LIBC_STR_SRCS_CC:%.cc=o/$(MODE)/%.o) TEST_LIBC_STR_COMS = \ - $(TEST_LIBC_STR_SRCS:%.c=o/$(MODE)/%.com) + $(TEST_LIBC_STR_SRCS_TEST_C:%.c=o/$(MODE)/%.com) \ + $(TEST_LIBC_STR_SRCS_TEST_CC:%.cc=o/$(MODE)/%.com) TEST_LIBC_STR_BINS = \ $(TEST_LIBC_STR_COMS) \ $(TEST_LIBC_STR_COMS:%=%.dbg) TEST_LIBC_STR_TESTS = \ - $(TEST_LIBC_STR_SRCS_TEST:%.c=o/$(MODE)/%.com.ok) + $(TEST_LIBC_STR_SRCS_TEST_C:%.c=o/$(MODE)/%.com.ok) \ + $(TEST_LIBC_STR_SRCS_TEST_CC:%.cc=o/$(MODE)/%.com.ok) TEST_LIBC_STR_CHECKS = \ - $(TEST_LIBC_STR_SRCS_TEST:%.c=o/$(MODE)/%.com.runs) + $(TEST_LIBC_STR_SRCS_TEST_C:%.c=o/$(MODE)/%.com.runs) \ + $(TEST_LIBC_STR_SRCS_TEST_CC:%.cc=o/$(MODE)/%.com.runs) TEST_LIBC_STR_DIRECTDEPS = \ LIBC_ALG \ @@ -43,7 +51,9 @@ TEST_LIBC_STR_DIRECTDEPS = \ LIBC_ZIPOS \ THIRD_PARTY_MBEDTLS \ THIRD_PARTY_REGEX \ - THIRD_PARTY_ZLIB + THIRD_PARTY_ZLIB \ + THIRD_PARTY_LIBCXX \ + THIRD_PARTY_SMALLZ4 TEST_LIBC_STR_DEPS := \ $(call uniq,$(foreach x,$(TEST_LIBC_STR_DIRECTDEPS),$($(x)))) @@ -62,7 +72,7 @@ o/$(MODE)/test/libc/str/%.com.dbg: \ o/$(MODE)/test/libc/str/str.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/test/libc/str/blake2.com.dbg: \ @@ -72,7 +82,7 @@ o/$(MODE)/test/libc/str/blake2.com.dbg: \ o/$(MODE)/test/libc/str/str.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_STR_OBJS): \ diff --git a/test/libc/str/undeflate_test.c b/test/libc/str/undeflate_test.c index 2b2c0c9a1..742e34083 100644 --- a/test/libc/str/undeflate_test.c +++ b/test/libc/str/undeflate_test.c @@ -53,20 +53,20 @@ TEST(undeflate, testStatCentralDirectory_notFound_noSysCalls) { uint64_t c; struct stat st; stat("/zip/doge.txt", &st); /* warmup */ - c = g_syscount; + c = __syscount; ASSERT_EQ(-1, stat("/zip/doge.txt", &st)); - ASSERT_EQ(0, g_syscount - c); + ASSERT_EQ(0, __syscount - c); ASSERT_EQ(ENOENT, errno); } TEST(undeflate, testStatCentralDirectory_isFound_noSysCalls) { uint64_t c; struct stat st = {0}; - c = g_syscount; + c = __syscount; ASSERT_NE(-1, stat("/zip/libc/testlib/hyperion.txt", &st)); ASSERT_TRUE(S_ISREG(st.st_mode)); ASSERT_EQ(kHyperionSize, st.st_size); - ASSERT_EQ(0, g_syscount - c); + ASSERT_EQ(0, __syscount - c); } TEST(undeflate, testOpenReadCloseEmbeddedZip) { diff --git a/test/libc/thread/test.mk b/test/libc/thread/test.mk index 33a46bc08..c62a0429a 100644 --- a/test/libc/thread/test.mk +++ b/test/libc/thread/test.mk @@ -48,7 +48,7 @@ o/$(MODE)/test/libc/thread/%.com.dbg: \ o/$(MODE)/test/libc/thread/thread.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_THREAD_OBJS): \ diff --git a/test/libc/time/test.mk b/test/libc/time/test.mk index 4744b92d2..caa61cba9 100644 --- a/test/libc/time/test.mk +++ b/test/libc/time/test.mk @@ -43,7 +43,7 @@ o/$(MODE)/test/libc/time/%.com.dbg: \ o/$(MODE)/test/libc/time/time.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/libc/time diff --git a/test/libc/tinymath/test.mk b/test/libc/tinymath/test.mk index 4feea7a30..931e7e706 100644 --- a/test/libc/tinymath/test.mk +++ b/test/libc/tinymath/test.mk @@ -53,7 +53,7 @@ o/$(MODE)/test/libc/tinymath/%.com.dbg: \ o/$(MODE)/test/libc/tinymath/tinymath.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TEST_LIBC_TINYMATH_OBJS): \ diff --git a/test/libc/unicode/test.mk b/test/libc/unicode/test.mk index 2b49b9c52..85ecba50c 100644 --- a/test/libc/unicode/test.mk +++ b/test/libc/unicode/test.mk @@ -47,7 +47,7 @@ o/$(MODE)/test/libc/unicode/%.com.dbg: \ o/$(MODE)/test/libc/unicode/unicode.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/libc/unicode diff --git a/test/libc/x/test.mk b/test/libc/x/test.mk index 025c759c0..ef812823c 100644 --- a/test/libc/x/test.mk +++ b/test/libc/x/test.mk @@ -53,7 +53,7 @@ o/$(MODE)/test/libc/x/%.com.dbg: \ o/$(MODE)/test/libc/x/x.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/libc/x diff --git a/test/libc/x/xfixpath_test.c b/test/libc/x/xfixpath_test.c new file mode 100644 index 000000000..63a5a6b2d --- /dev/null +++ b/test/libc/x/xfixpath_test.c @@ -0,0 +1,27 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/runtime.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +TEST(xfixpath, test) { + setenv("PATH", "C:\\bin;C:\\usr\\bin;C:\\usr\\local\\bin", true); + xfixpath(); + ASSERT_STREQ("/C/bin:/C/usr/bin:/C/usr/local/bin", getenv("PATH")); +} diff --git a/test/libc/xed/test.mk b/test/libc/xed/test.mk index e51d88fd3..440f93ec9 100644 --- a/test/libc/xed/test.mk +++ b/test/libc/xed/test.mk @@ -93,7 +93,7 @@ o/$(MODE)/test/libc/xed/%.com.dbg: \ o/$(MODE)/test/libc/xed/xed.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) #─────────────────────────────────────────────────────────────────────────────── diff --git a/test/net/http/formathttpdatetime_test.c b/test/net/http/formathttpdatetime_test.c new file mode 100644 index 000000000..71b4b441d --- /dev/null +++ b/test/net/http/formathttpdatetime_test.c @@ -0,0 +1,51 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/testlib/ezbench.h" +#include "libc/testlib/testlib.h" +#include "libc/time/struct/tm.h" +#include "libc/time/time.h" +#include "net/http/http.h" + +TEST(FormatHttpDateTime, test) { + char p[30]; + struct tm *tm; + int64_t t = 0x62820bcd; + tm = gmtime(&t); + FormatHttpDateTime(p, tm); + ASSERT_STREQ("Mon, 16 May 2022 08:31:09 GMT", p); +} + +TEST(FormatHttpDateTime, testStrftime) { + char p[30]; + struct tm *tm; + int64_t t = 0x62820bcd; + tm = gmtime(&t); + strftime(p, sizeof(p), "%a, %d %b %Y %H:%M:%S %Z", tm); + ASSERT_STREQ("Mon, 16 May 2022 08:31:09 GMT", p); +} + +BENCH(FormatHttpDateTime, bench) { + char p[30]; + struct tm *tm; + int64_t t = 0x62820bcd; + tm = gmtime(&t); + EZBENCH2("FormatHttpDateTime", donothing, FormatHttpDateTime(p, tm)); + EZBENCH2("strftime", donothing, + strftime(p, sizeof(p), "%a, %d %b %Y %H:%M:%S %Z", tm)); +} diff --git a/test/net/http/test.mk b/test/net/http/test.mk index c07da4234..e9d4b54db 100644 --- a/test/net/http/test.mk +++ b/test/net/http/test.mk @@ -37,7 +37,7 @@ o/$(MODE)/test/net/http/%.com.dbg: \ o/$(MODE)/test/net/http/%.o \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/net/http diff --git a/test/net/https/test.mk b/test/net/https/test.mk index be8db89a6..0970a3577 100644 --- a/test/net/https/test.mk +++ b/test/net/https/test.mk @@ -38,7 +38,7 @@ o/$(MODE)/test/net/https/%.com.dbg: \ o/$(MODE)/test/net/https/%.o \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/net/https diff --git a/test/tool/args/test.mk b/test/tool/args/test.mk index ff9019a44..91bd5eca5 100644 --- a/test/tool/args/test.mk +++ b/test/tool/args/test.mk @@ -66,7 +66,7 @@ o/$(MODE)/test/tool/args/%.com.dbg: \ $(TEST_TOOL_ARGS_A).pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/tool/args diff --git a/test/tool/build/lib/test.mk b/test/tool/build/lib/test.mk index dda3332c2..28ffd7bee 100644 --- a/test/tool/build/lib/test.mk +++ b/test/tool/build/lib/test.mk @@ -66,7 +66,7 @@ o/$(MODE)/test/tool/build/lib/%.com.dbg: \ $(TEST_TOOL_BUILD_LIB_A).pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/tool/build/lib diff --git a/test/tool/net/test.mk b/test/tool/net/test.mk index 3445d799b..c652a90a0 100644 --- a/test/tool/net/test.mk +++ b/test/tool/net/test.mk @@ -68,7 +68,7 @@ o/$(MODE)/test/tool/net/%.com.dbg: \ $(TEST_TOOL_NET_A).pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/tool/net diff --git a/test/tool/plinko/plinko_test.c b/test/tool/plinko/plinko_test.c index 4b95011b0..b4349fd1b 100644 --- a/test/tool/plinko/plinko_test.c +++ b/test/tool/plinko/plinko_test.c @@ -70,33 +70,34 @@ TEST(plinko, worksOrPrintsNiceError) { sigset_t chldmask, savemask; int i, pid, fdin, wstatus, pfds[2][2]; struct sigaction ignore, saveint, savequit, savepipe; - bzero(buf, sizeof(buf)); ignore.sa_flags = 0; ignore.sa_handler = SIG_IGN; - EXPECT_EQ(0, sigemptyset(&ignore.sa_mask)); - EXPECT_EQ(0, sigaction(SIGINT, &ignore, &saveint)); - EXPECT_EQ(0, sigaction(SIGQUIT, &ignore, &savequit)); - EXPECT_EQ(0, sigaction(SIGPIPE, &ignore, &savepipe)); - EXPECT_EQ(0, sigemptyset(&chldmask)); - EXPECT_EQ(0, sigaddset(&chldmask, SIGCHLD)); - EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &chldmask, &savemask)); + sigemptyset(&ignore.sa_mask); + sigaction(SIGINT, &ignore, &saveint); + sigaction(SIGQUIT, &ignore, &savequit); + sigaction(SIGPIPE, &ignore, &savepipe); + sigemptyset(&chldmask); + sigaddset(&chldmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &chldmask, &savemask); ASSERT_NE(-1, pipe2(pfds[0], O_CLOEXEC)); ASSERT_NE(-1, pipe2(pfds[1], O_CLOEXEC)); - ASSERT_NE(-1, (pid = vfork())); + ASSERT_NE(-1, (pid = fork())); if (!pid) { + __strace = 0; + __ftrace = 0; close(0), dup(pfds[0][0]); close(1), dup(pfds[1][1]); close(2), dup(pfds[1][1]); sigaction(SIGINT, &saveint, 0); sigaction(SIGQUIT, &savequit, 0); - sigaction(SIGQUIT, &savepipe, 0); + sigaction(SIGPIPE, &savepipe, 0); sigprocmask(SIG_SETMASK, &savemask, 0); execve("bin/plinko.com", (char *const[]){"bin/plinko.com", 0}, (char *const[]){0}); _exit(127); } - EXPECT_NE(-1, close(pfds[0][0])); - EXPECT_NE(-1, close(pfds[1][1])); + close(pfds[0][0]); + close(pfds[1][1]); for (i = 0; i < ARRAYLEN(kSauces); ++i) { EXPECT_NE(-1, (fdin = open(kSauces[i], O_RDONLY))); rc = _copyfd(fdin, pfds[0][1], -1); @@ -104,7 +105,8 @@ TEST(plinko, worksOrPrintsNiceError) { EXPECT_NE(-1, close(fdin)); } EXPECT_NE(-1, close(pfds[0][1])); - EXPECT_NE(-1, (got = read(pfds[1][0], buf, sizeof(buf) - 1))); + bzero(buf, sizeof(buf)); + ASSERT_NE(-1, (got = read(pfds[1][0], buf, sizeof(buf) - 1))); EXPECT_NE(0, got); while (read(pfds[1][0], drain, sizeof(drain)) > 0) donothing; EXPECT_NE(-1, close(pfds[1][0])); @@ -116,10 +118,10 @@ TEST(plinko, worksOrPrintsNiceError) { } else { EXPECT_EQ(1, WEXITSTATUS(wstatus)); } - EXPECT_EQ(0, sigaction(SIGINT, &saveint, 0)); - EXPECT_EQ(0, sigaction(SIGQUIT, &savequit, 0)); - EXPECT_EQ(0, sigaction(SIGPIPE, &savepipe, 0)); - EXPECT_EQ(0, sigprocmask(SIG_SETMASK, &savemask, 0)); + sigaction(SIGINT, &saveint, 0); + sigaction(SIGQUIT, &savequit, 0); + sigaction(SIGPIPE, &savepipe, 0); + sigprocmask(SIG_SETMASK, &savemask, 0); if (g_testlib_failed) { kprintf("note: got the following in pipe: %s%n", buf); } diff --git a/test/tool/plinko/test.mk b/test/tool/plinko/test.mk index c247d780a..f93b5a9e2 100644 --- a/test/tool/plinko/test.mk +++ b/test/tool/plinko/test.mk @@ -74,7 +74,7 @@ o/$(MODE)/test/tool/plinko/%.com.dbg: \ $(TEST_TOOL_PLINKO_A).pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/test/tool/plinko/plinko_test.com.runs: \ diff --git a/test/tool/viz/lib/test.mk b/test/tool/viz/lib/test.mk index 8aa21f4fd..ca85dda17 100644 --- a/test/tool/viz/lib/test.mk +++ b/test/tool/viz/lib/test.mk @@ -55,7 +55,7 @@ o/$(MODE)/test/tool/viz/lib/%.com.dbg: \ o/$(MODE)/test/tool/viz/lib/vizlib.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PHONY: o/$(MODE)/test/tool/viz/lib diff --git a/third_party/bzip2/bzip2.mk b/third_party/bzip2/bzip2.mk index c387dfd95..cc5e8a3ba 100644 --- a/third_party/bzip2/bzip2.mk +++ b/third_party/bzip2/bzip2.mk @@ -51,7 +51,7 @@ o/$(MODE)/third_party/bzip2/bzip2.com.dbg: \ o/$(MODE)/third_party/bzip2/bzip2.o \ o/$(MODE)/third_party/bzip2/bzip2.a.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/bzip2/bzip2recover.com.dbg: \ @@ -59,7 +59,7 @@ o/$(MODE)/third_party/bzip2/bzip2recover.com.dbg: \ o/$(MODE)/third_party/bzip2/bzip2recover.o \ o/$(MODE)/third_party/bzip2/bzip2.a.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(THIRD_PARTY_BZIP2_A_OBJS): \ diff --git a/third_party/chibicc/as.c b/third_party/chibicc/as.c index 42883b804..17a21cdb0 100644 --- a/third_party/chibicc/as.c +++ b/third_party/chibicc/as.c @@ -2921,6 +2921,7 @@ static void OnMaxpd(struct As *a, struct Slice s) { OpSse(a, 0x660F5F); } static void OnMaxps(struct As *a, struct Slice s) { OpSse(a, 0x0F5F); } static void OnMaxsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F5F); } static void OnMaxss(struct As *a, struct Slice s) { OpSse(a, 0xF30F5F); } +static void OnMfence(struct As *a, struct Slice s) { EmitVarword(a, 0x0faef0); } static void OnMinpd(struct As *a, struct Slice s) { OpSse(a, 0x660F5D); } static void OnMinps(struct As *a, struct Slice s) { OpSse(a, 0x0F5D); } static void OnMinsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F5D); } @@ -3370,6 +3371,7 @@ static const struct Directive8 { {"maxps", OnMaxps}, // {"maxsd", OnMaxsd}, // {"maxss", OnMaxss}, // + {"mfence", OnMfence}, // {"minpd", OnMinpd}, // {"minps", OnMinps}, // {"minsd", OnMinsd}, // diff --git a/third_party/chibicc/chibicc.c b/third_party/chibicc/chibicc.c index e1fff9230..c189381d5 100644 --- a/third_party/chibicc/chibicc.c +++ b/third_party/chibicc/chibicc.c @@ -80,7 +80,7 @@ static void chibicc_usage(int status) { char *p; size_t n; p = xslurp("/zip/third_party/chibicc/help.txt", &n); - xwrite(1, p, n); + __paginate(1, p); _Exit(status); } @@ -447,7 +447,8 @@ static bool run_subprocess(char **argv) { _Exit(1); } // Wait for the child process to finish. - do rc = wait(&ws); + do + rc = wait(&ws); while (rc == -1 && errno == EINTR); return WIFEXITED(ws) && WEXITSTATUS(ws) == 0; } diff --git a/third_party/chibicc/chibicc.h b/third_party/chibicc/chibicc.h index 75eb581af..171f1c8fa 100644 --- a/third_party/chibicc/chibicc.h +++ b/third_party/chibicc/chibicc.h @@ -297,62 +297,65 @@ struct Relocation { }; typedef enum { - ND_NULL_EXPR, // Do nothing - ND_ADD, // + - ND_SUB, // - - ND_MUL, // * - ND_DIV, // / - ND_NEG, // unary - - ND_REM, // % - ND_BINAND, // & - ND_BINOR, // | - ND_BINXOR, // ^ - ND_SHL, // << - ND_SHR, // >> - ND_EQ, // == - ND_NE, // != - ND_LT, // < - ND_LE, // <= - ND_ASSIGN, // = - ND_COND, // ?: - ND_COMMA, // , - ND_MEMBER, // . (struct member access) - ND_ADDR, // unary & - ND_DEREF, // unary * - ND_NOT, // ! - ND_BITNOT, // ~ - ND_LOGAND, // && - ND_LOGOR, // || - ND_RETURN, // "return" - ND_IF, // "if" - ND_FOR, // "for" or "while" - ND_DO, // "do" - ND_SWITCH, // "switch" - ND_CASE, // "case" - ND_BLOCK, // { ... } - ND_GOTO, // "goto" - ND_GOTO_EXPR, // "goto" labels-as-values - ND_LABEL, // Labeled statement - ND_LABEL_VAL, // [GNU] Labels-as-values - ND_FUNCALL, // Function call - ND_EXPR_STMT, // Expression statement - ND_STMT_EXPR, // Statement expression - ND_VAR, // Variable - ND_VLA_PTR, // VLA designator - ND_NUM, // Integer - ND_CAST, // Type cast - ND_MEMZERO, // Zero-clear a stack variable - ND_ASM, // "asm" - ND_CAS, // Atomic compare-and-swap - ND_EXCH, // Atomic exchange - ND_LOAD, // Atomic load - ND_TESTANDSET, // Atomic lock test and set - ND_RELEASE, // Atomic lock release - ND_FETCHADD, // Atomic fetch and add - ND_SUBFETCH, // Atomic sub and fetch - ND_FPCLASSIFY, // floating point classify - ND_MOVNTDQ, // Intel MOVNTDQ - ND_PMOVMSKB, // Intel PMOVMSKB + ND_NULL_EXPR, // Do nothing + ND_ADD, // + + ND_SUB, // - + ND_MUL, // * + ND_DIV, // / + ND_NEG, // unary - + ND_REM, // % + ND_BINAND, // & + ND_BINOR, // | + ND_BINXOR, // ^ + ND_SHL, // << + ND_SHR, // >> + ND_EQ, // == + ND_NE, // != + ND_LT, // < + ND_LE, // <= + ND_ASSIGN, // = + ND_COND, // ?: + ND_COMMA, // , + ND_MEMBER, // . (struct member access) + ND_ADDR, // unary & + ND_DEREF, // unary * + ND_NOT, // ! + ND_BITNOT, // ~ + ND_LOGAND, // && + ND_LOGOR, // || + ND_RETURN, // "return" + ND_IF, // "if" + ND_FOR, // "for" or "while" + ND_DO, // "do" + ND_SWITCH, // "switch" + ND_CASE, // "case" + ND_BLOCK, // { ... } + ND_GOTO, // "goto" + ND_GOTO_EXPR, // "goto" labels-as-values + ND_LABEL, // Labeled statement + ND_LABEL_VAL, // [GNU] Labels-as-values + ND_FUNCALL, // Function call + ND_EXPR_STMT, // Expression statement + ND_STMT_EXPR, // Statement expression + ND_VAR, // Variable + ND_VLA_PTR, // VLA designator + ND_NUM, // Integer + ND_CAST, // Type cast + ND_MEMZERO, // Zero-clear a stack variable + ND_ASM, // "asm" + ND_CAS, // Atomic compare-and-swap + ND_EXCH, // Atomic exchange + ND_LOAD, // Atomic load + ND_STORE, // Atomic store + ND_TESTANDSET, // Sync lock test and set + ND_TESTANDSETA, // Atomic lock test and set + ND_CLEAR, // Atomic clear + ND_RELEASE, // Atomic lock release + ND_FETCHADD, // Atomic fetch and add + ND_SUBFETCH, // Atomic sub and fetch + ND_FPCLASSIFY, // floating point classify + ND_MOVNTDQ, // Intel MOVNTDQ + ND_PMOVMSKB, // Intel PMOVMSKB } NodeKind; struct Node { @@ -394,6 +397,7 @@ struct Node { // Assembly Asm *azm; // Atomic compare-and-swap + char memorder; Node *cas_addr; Node *cas_old; Node *cas_new; diff --git a/third_party/chibicc/chibicc.main.c b/third_party/chibicc/chibicc.main.c index 6c218fcb6..537a9a4c7 100644 --- a/third_party/chibicc/chibicc.main.c +++ b/third_party/chibicc/chibicc.main.c @@ -1,7 +1,22 @@ #include "libc/mem/arena.h" #include "libc/runtime/internal.h" +#include "libc/x/x.h" #include "third_party/chibicc/chibicc.h" +#include "tool/build/lib/getargs.h" int main(int argc, char **argv) { - return chibicc(argc, argv); + int n; + char **p; + const char *arg; + struct GetArgs ga; + n = 0; + p = xcalloc(n + 1, sizeof(*p)); + getargs_init(&ga, argv); + while ((arg = getargs_next(&ga))) { + p = xrealloc(p, (++n + 1) * sizeof(*p)); + p[n - 1] = xstrdup(arg); + p[n - 0] = 0; + } + getargs_destroy(&ga); + return chibicc(n, p); } diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index ec387ba89..4f2e9d449 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -10,8 +10,8 @@ # This makefile compiles and runs each test twice. The first with # GCC-built chibicc, and a second time with chibicc-built chibicc -CHIBICC = o/$(MODE)/third_party/chibicc/chibicc.com.dbg -CHIBICC2 = o/$(MODE)/third_party/chibicc/chibicc2.com.dbg +CHIBICC = o/$(MODE)/third_party/chibicc/chibicc.com +CHIBICC2 = o/$(MODE)/third_party/chibicc/chibicc2.com CHIBICC_FLAGS = \ -fno-common \ -include libc/integral/normalize.inc \ @@ -93,7 +93,7 @@ $(THIRD_PARTY_CHIBICC2_A).pkg: \ o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \ $(THIRD_PARTY_CHIBICC_A_DEPS) \ $(THIRD_PARTY_CHIBICC_A) \ - $(APE) \ + $(APE_NO_MODIFY_SELF) \ $(CRT) \ o/$(MODE)/third_party/chibicc/help.txt.zip.o \ o/$(MODE)/third_party/chibicc/chibicc.main.o \ @@ -102,7 +102,7 @@ o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \ o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \ $(THIRD_PARTY_CHIBICC_A_DEPS) \ $(THIRD_PARTY_CHIBICC2_A) \ - $(APE) \ + $(APE_NO_MODIFY_SELF) \ $(CRT) \ o/$(MODE)/third_party/chibicc/help.txt.zip.o \ o/$(MODE)/third_party/chibicc/chibicc.main.chibicc.o \ @@ -122,7 +122,7 @@ o/$(MODE)/third_party/chibicc/chibicc.com: \ o/$(MODE)/third_party/chibicc/as.com.dbg: \ $(THIRD_PARTY_CHIBICC_A_DEPS) \ $(THIRD_PARTY_CHIBICC_A) \ - $(APE) \ + $(APE_NO_MODIFY_SELF) \ $(CRT) \ o/$(MODE)/third_party/chibicc/as.main.o \ $(THIRD_PARTY_CHIBICC_A).pkg @@ -134,11 +134,11 @@ o/$(MODE)/third_party/chibicc/chibicc.o: \ o/$(MODE)/third_party/chibicc/chibicc.chibicc.o: \ CHIBICC_FLAGS += $(THIRD_PARTY_CHIBICC_DEFINES) -o/$(MODE)/%.chibicc.o: %.s o/$(MODE)/third_party/chibicc/chibicc.com.dbg +o/$(MODE)/%.chibicc.o: %.s $(CHIBICC) @$(COMPILE) -ACHIBICC -T$@ $(CHIBICC) $(CHIBICC_FLAGS) -c -o $@ $< -o/$(MODE)/%.chibicc.o: %.c o/$(MODE)/third_party/chibicc/chibicc.com.dbg +o/$(MODE)/%.chibicc.o: %.c $(CHIBICC) @$(COMPILE) -ACHIBICC -T$@ $(CHIBICC) $(CHIBICC_FLAGS) -c -o $@ $< -o/$(MODE)/%.chibicc2.o: %.c o/$(MODE)/third_party/chibicc/chibicc2.com.dbg +o/$(MODE)/%.chibicc2.o: %.c $(CHIBICC2) @$(COMPILE) -ACHIBICC2 -T$@ $(CHIBICC2) $(CHIBICC_FLAGS) -c -o $@ $< THIRD_PARTY_CHIBICC_LIBS = $(foreach x,$(THIRD_PARTY_CHIBICC_ARTIFACTS),$($(x))) diff --git a/third_party/chibicc/codegen.c b/third_party/chibicc/codegen.c index 21727cf4b..da74d080e 100644 --- a/third_party/chibicc/codegen.c +++ b/third_party/chibicc/codegen.c @@ -1547,6 +1547,14 @@ void gen_expr(Node *node) { println("\txchg\t%s,(%%rdi)", reg_ax(node->ty->size)); return; } + case ND_TESTANDSETA: { + gen_expr(node->lhs); + push(); + println("\tmov\t$1,%%eax"); + pop("%rdi"); + println("\txchg\t%s,(%%rdi)", reg_ax(node->ty->size)); + return; + } case ND_LOAD: { gen_expr(node->rhs); push(); @@ -1556,6 +1564,28 @@ void gen_expr(Node *node) { println("\tmov\t%s,(%%rdi)", reg_ax(node->ty->size)); return; } + case ND_STORE: { + gen_expr(node->lhs); + push(); + gen_expr(node->rhs); + pop("%rdi"); + println("\tmov\t(%%rax),%s", reg_ax(node->ty->size)); + println("\tmov\t%s,(%%rdi)", reg_ax(node->ty->size)); + if (node->memorder) { + println("\tmfence"); + } + return; + } + case ND_CLEAR: { + gen_expr(node->lhs); + println("\tmov\t%%rax,%%rdi"); + println("\txor\t%%eax,%%eax"); + println("\tmov\t%s,(%%rdi)", reg_ax(node->ty->size)); + if (node->memorder) { + println("\tmfence"); + } + return; + } case ND_FETCHADD: { gen_expr(node->lhs); push(); diff --git a/third_party/chibicc/help.txt b/third_party/chibicc/help.txt index 2d5bba64b..1e2730726 100644 --- a/third_party/chibicc/help.txt +++ b/third_party/chibicc/help.txt @@ -259,6 +259,15 @@ BUILTIN FUNCTIONS double __builtin_copysign(double, double) float __builtin_copysignf(float, float) long double __builtin_copysignl(long double, long double) + void __builtin_ia32_movntq(di *, di) + int __builtin_ia32_pmovmskb128(v16qi) + T __atomic_load(T *addr, int memorder) + void __atomic_clear(_Bool *addr, int memorder) + _Bool __atomic_test_and_set(void *addr, int memorder) + T __atomic_sub_fetch(T *addr, T amt, int memorder) + T __atomic_fetch_add(T *addr, T amt, int memorder) + T __sync_lock_test_and_set(T *addr, T value, ...) + void __sync_lock_release(T *addr, ...) BUILTIN OBJECTS diff --git a/third_party/chibicc/kw.gperf b/third_party/chibicc/kw.gperf index 0f1c7777b..220da7e6e 100644 --- a/third_party/chibicc/kw.gperf +++ b/third_party/chibicc/kw.gperf @@ -119,8 +119,11 @@ __builtin_types_compatible_p, KW___BUILTIN_TYPES_COMPATIBLE_P "->", KW_ARROW ".", KW_DOT __atomic_load, KW___ATOMIC_LOAD -__atomic_fetch_add, KW___ATOMIC_FETCH_ADD +__atomic_store, KW___ATOMIC_STORE +__atomic_clear, KW___ATOMIC_CLEAR __atomic_sub_fetch, KW___ATOMIC_SUB_FETCH +__atomic_fetch_add, KW___ATOMIC_FETCH_ADD +__atomic_test_and_set, KW___ATOMIC_TEST_AND_SET __sync_lock_test_and_set, KW___SYNC_LOCK_TEST_AND_SET __sync_lock_release, KW___SYNC_LOCK_RELEASE __builtin_ia32_movntdq, KW___BUILTIN_IA32_MOVNTDQ diff --git a/third_party/chibicc/kw.h b/third_party/chibicc/kw.h index 62d8194eb..79aa5f796 100644 --- a/third_party/chibicc/kw.h +++ b/third_party/chibicc/kw.h @@ -112,6 +112,9 @@ #define KW___BUILTIN_IA32_MOVNTDQ 128 #define KW___ATOMIC_FETCH_ADD 129 #define KW___ATOMIC_SUB_FETCH 130 +#define KW___ATOMIC_TEST_AND_SET 131 +#define KW___ATOMIC_CLEAR 132 +#define KW___ATOMIC_STORE 133 #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ diff --git a/third_party/chibicc/kw.inc b/third_party/chibicc/kw.inc index f570e2e53..9238b0dba 100644 --- a/third_party/chibicc/kw.inc +++ b/third_party/chibicc/kw.inc @@ -37,44 +37,44 @@ #line 10 "kw.gperf" struct thatispacked KwSlot { char *name; unsigned char code; }; -#define TOTAL_KEYWORDS 116 +#define TOTAL_KEYWORDS 119 #define MIN_WORD_LENGTH 1 #define MAX_WORD_LENGTH 28 #define MIN_HASH_VALUE 1 -#define MAX_HASH_VALUE 201 -/* maximum key range = 201, duplicates = 0 */ +#define MAX_HASH_VALUE 238 +/* maximum key range = 238, duplicates = 0 */ static inline unsigned int hash (register const char *str, register size_t len) { static const unsigned char asso_values[] = { - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 100, 202, 202, 202, 202, 65, 202, - 95, 90, 85, 15, 202, 0, 75, 202, 202, 202, - 0, 202, 202, 202, 202, 202, 10, 202, 202, 202, - 202, 202, 55, 202, 202, 202, 0, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 5, 202, 0, 50, 0, - 5, 15, 0, 40, 45, 115, 60, 5, 20, 15, - 90, 85, 0, 0, 55, 10, 0, 65, 5, 0, - 0, 10, 25, 70, 35, 30, 5, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, - 202, 202, 202, 202, 202, 202, 202 + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 115, 239, 239, 239, 239, 50, 239, + 110, 105, 100, 5, 239, 0, 95, 239, 239, 239, + 10, 239, 239, 239, 239, 239, 0, 239, 239, 239, + 239, 239, 45, 239, 239, 239, 0, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 5, 239, 0, 90, 5, + 55, 10, 0, 25, 75, 105, 15, 10, 20, 15, + 125, 60, 15, 10, 10, 10, 0, 70, 5, 5, + 10, 0, 45, 85, 10, 30, 15, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239 }; register unsigned int hval = len; @@ -116,19 +116,21 @@ LookupKw (register const char *str, register size_t len) {"-", KW_MINUS}, #line 116 "kw.gperf" {"--", KW_DECREMENT}, - {""}, {""}, -#line 29 "kw.gperf" - {"const", KW_CONST}, + {""}, {""}, {""}, #line 63 "kw.gperf" {"typeof", KW_TYPEOF}, #line 62 "kw.gperf" {"typedef", KW_TYPEDEF}, - {""}, {""}, {""}, -#line 114 "kw.gperf" - {"~", KW_TILDE}, -#line 68 "kw.gperf" - {"_Atomic", KW__ATOMIC}, {""}, {""}, +#line 29 "kw.gperf" + {"const", KW_CONST}, +#line 109 "kw.gperf" + {"+", KW_PLUS}, +#line 115 "kw.gperf" + {"++", KW_INCREMENT}, +#line 20 "kw.gperf" + {"for", KW_FOR}, + {""}, #line 78 "kw.gperf" {"__restrict", KW_RESTRICT}, #line 22 "kw.gperf" @@ -143,244 +145,261 @@ LookupKw (register const char *str, register size_t len) {"__VA_OPT__", KW___VA_OPT__}, #line 13 "kw.gperf" {"struct", KW_STRUCT}, -#line 60 "kw.gperf" - {"strpbrk", KW_STRPBRK}, - {""}, {""}, -#line 31 "kw.gperf" - {"short", KW_SHORT}, -#line 28 "kw.gperf" - {"double", KW_DOUBLE}, -#line 79 "kw.gperf" - {"__restrict__", KW_RESTRICT}, -#line 95 "kw.gperf" - {"__builtin_popcount", KW___BUILTIN_POPCOUNT}, -#line 17 "kw.gperf" - {"void", KW_VOID}, -#line 69 "kw.gperf" - {"_Bool", KW__BOOL}, -#line 109 "kw.gperf" - {"+", KW_PLUS}, -#line 115 "kw.gperf" - {"++", KW_INCREMENT}, -#line 88 "kw.gperf" - {"__builtin_ffs", KW___BUILTIN_FFS}, +#line 118 "kw.gperf" + {"||", KW_LOGOR}, + {""}, #line 19 "kw.gperf" {"else", KW_ELSE}, -#line 25 "kw.gperf" - {"while", KW_WHILE}, -#line 85 "kw.gperf" - {"__builtin_compare_and_swap", KW___BUILTIN_COMPARE_AND_SWAP}, -#line 82 "kw.gperf" - {"__builtin_add_overflow", KW___BUILTIN_ADD_OVERFLOW}, -#line 81 "kw.gperf" - {"__typeof", KW_TYPEOF}, +#line 31 "kw.gperf" + {"short", KW_SHORT}, +#line 61 "kw.gperf" + {"strstr", KW_STRSTR}, +#line 79 "kw.gperf" + {"__restrict__", KW_RESTRICT}, +#line 67 "kw.gperf" + {"_Alignof", KW__ALIGNOF}, +#line 18 "kw.gperf" + {"char", KW_CHAR}, +#line 48 "kw.gperf" + {"endif", KW_ENDIF}, +#line 114 "kw.gperf" + {"~", KW_TILDE}, +#line 68 "kw.gperf" + {"_Atomic", KW__ATOMIC}, +#line 88 "kw.gperf" + {"__builtin_ffs", KW___BUILTIN_FFS}, #line 55 "kw.gperf" {"line", KW_LINE}, -#line 86 "kw.gperf" - {"__builtin_constant_p", KW___BUILTIN_CONSTANT_P}, +#line 25 "kw.gperf" + {"while", KW_WHILE}, + {""}, +#line 60 "kw.gperf" + {"strpbrk", KW_STRPBRK}, +#line 66 "kw.gperf" + {"_Alignas", KW__ALIGNAS}, +#line 47 "kw.gperf" + {"elif", KW_ELIF}, +#line 49 "kw.gperf" + {"error", KW_ERROR}, #line 74 "kw.gperf" {"__alignof__", KW___ALIGNOF__}, -#line 101 "kw.gperf" - {"__builtin_strpbrk", KW___BUILTIN_STRPBRK}, - {""}, {""}, {""}, {""}, -#line 103 "kw.gperf" - {"__builtin_sub_overflow", KW___BUILTIN_SUB_OVERFLOW}, -#line 72 "kw.gperf" - {"_Thread_local", KW__THREAD_LOCAL}, -#line 96 "kw.gperf" - {"__builtin_popcountl", KW___BUILTIN_POPCOUNTL}, -#line 97 "kw.gperf" - {"__builtin_popcountll", KW___BUILTIN_POPCOUNTLL}, -#line 56 "kw.gperf" - {"pragma", KW_PRAGMA}, -#line 92 "kw.gperf" - {"__builtin_mul_overflow", KW___BUILTIN_MUL_OVERFLOW}, -#line 104 "kw.gperf" - {"__builtin_types_compatible_p", KW___BUILTIN_TYPES_COMPATIBLE_P}, +#line 82 "kw.gperf" + {"__builtin_add_overflow", KW___BUILTIN_ADD_OVERFLOW}, +#line 44 "kw.gperf" + {"register", KW_REGISTER}, {""}, -#line 30 "kw.gperf" - {"float", KW_FLOAT}, +#line 69 "kw.gperf" + {"_Bool", KW__BOOL}, #line 87 "kw.gperf" {"__builtin_expect", KW___BUILTIN_EXPECT}, #line 119 "kw.gperf" {"->", KW_ARROW}, -#line 20 "kw.gperf" - {"for", KW_FOR}, -#line 47 "kw.gperf" - {"elif", KW_ELIF}, +#line 95 "kw.gperf" + {"__builtin_popcount", KW___BUILTIN_POPCOUNT}, + {""}, #line 91 "kw.gperf" {"__builtin_fpclassify", KW___BUILTIN_FPCLASSIFY}, -#line 108 "kw.gperf" - {"}", KW_RB}, -#line 42 "kw.gperf" - {"default", KW_DEFAULT}, - {""}, -#line 89 "kw.gperf" - {"__builtin_ffsl", KW___BUILTIN_FFSL}, -#line 90 "kw.gperf" - {"__builtin_ffsll", KW___BUILTIN_FFSLL}, - {""}, {""}, {""}, -#line 18 "kw.gperf" - {"char", KW_CHAR}, -#line 64 "kw.gperf" - {"undef", KW_UNDEF}, -#line 61 "kw.gperf" - {"strstr", KW_STRSTR}, -#line 118 "kw.gperf" - {"||", KW_LOGOR}, -#line 67 "kw.gperf" - {"_Alignof", KW__ALIGNOF}, -#line 124 "kw.gperf" - {"__sync_lock_test_and_set", KW___SYNC_LOCK_TEST_AND_SET}, -#line 49 "kw.gperf" - {"error", KW_ERROR}, -#line 58 "kw.gperf" - {"strchr", KW_STRCHR}, -#line 40 "kw.gperf" - {"defined", KW_DEFINED}, -#line 65 "kw.gperf" - {"volatile", KW_VOLATILE}, -#line 71 "kw.gperf" - {"_Static_assert", KW__STATIC_ASSERT}, -#line 48 "kw.gperf" - {"endif", KW_ENDIF}, -#line 16 "kw.gperf" - {"static", KW_STATIC}, - {""}, -#line 66 "kw.gperf" - {"_Alignas", KW__ALIGNAS}, -#line 125 "kw.gperf" - {"__sync_lock_release", KW___SYNC_LOCK_RELEASE}, - {""}, -#line 39 "kw.gperf" - {"define", KW_DEFINE}, - {""}, -#line 35 "kw.gperf" - {"continue", KW_CONTINUE}, -#line 43 "kw.gperf" - {"auto", KW_AUTO}, - {""}, #line 99 "kw.gperf" {"__builtin_strchr", KW___BUILTIN_STRCHR}, -#line 21 "kw.gperf" - {"do", KW_DO}, - {""}, {""}, {""}, {""}, {""}, -#line 70 "kw.gperf" - {"_Generic", KW__GENERIC}, +#line 103 "kw.gperf" + {"__builtin_sub_overflow", KW___BUILTIN_SUB_OVERFLOW}, +#line 72 "kw.gperf" + {"_Thread_local", KW__THREAD_LOCAL}, #line 98 "kw.gperf" {"__builtin_reg_class", KW___BUILTIN_REG_CLASS}, {""}, #line 102 "kw.gperf" {"__builtin_strstr", KW___BUILTIN_STRSTR}, -#line 84 "kw.gperf" - {"__atomic_exchange", KW___ATOMIC_EXCHANGE}, -#line 45 "kw.gperf" - {"__attribute__", KW___ATTRIBUTE__}, -#line 83 "kw.gperf" - {"__builtin_assume_aligned", KW___BUILTIN_ASSUME_ALIGNED}, +#line 92 "kw.gperf" + {"__builtin_mul_overflow", KW___BUILTIN_MUL_OVERFLOW}, +#line 81 "kw.gperf" + {"__typeof", KW_TYPEOF}, {""}, -#line 32 "kw.gperf" - {"signed", KW_SIGNED}, +#line 86 "kw.gperf" + {"__builtin_constant_p", KW___BUILTIN_CONSTANT_P}, +#line 108 "kw.gperf" + {"}", KW_RB}, +#line 101 "kw.gperf" + {"__builtin_strpbrk", KW___BUILTIN_STRPBRK}, +#line 104 "kw.gperf" + {"__builtin_types_compatible_p", KW___BUILTIN_TYPES_COMPATIBLE_P}, +#line 89 "kw.gperf" + {"__builtin_ffsl", KW___BUILTIN_FFSL}, +#line 90 "kw.gperf" + {"__builtin_ffsll", KW___BUILTIN_FFSLL}, + {""}, {""}, {""}, +#line 96 "kw.gperf" + {"__builtin_popcountl", KW___BUILTIN_POPCOUNTL}, +#line 97 "kw.gperf" + {"__builtin_popcountll", KW___BUILTIN_POPCOUNTLL}, +#line 85 "kw.gperf" + {"__builtin_compare_and_swap", KW___BUILTIN_COMPARE_AND_SWAP}, {""}, #line 77 "kw.gperf" {"__int128", KW___INT128}, -#line 24 "kw.gperf" - {"long", KW_LONG}, -#line 33 "kw.gperf" - {"break", KW_BREAK}, -#line 50 "kw.gperf" - {"extern", KW_EXTERN}, +#line 17 "kw.gperf" + {"void", KW_VOID}, +#line 64 "kw.gperf" + {"undef", KW_UNDEF}, +#line 28 "kw.gperf" + {"double", KW_DOUBLE}, + {""}, +#line 70 "kw.gperf" + {"_Generic", KW__GENERIC}, +#line 43 "kw.gperf" + {"auto", KW_AUTO}, + {""}, +#line 58 "kw.gperf" + {"strchr", KW_STRCHR}, {""}, #line 76 "kw.gperf" {"__inline", KW_INLINE}, -#line 46 "kw.gperf" - {"_Noreturn", KW__NORETURN}, {""}, {""}, -#line 12 "kw.gperf" - {"if", KW_IF}, -#line 54 "kw.gperf" - {"int", KW_INT}, +#line 39 "kw.gperf" + {"define", KW_DEFINE}, {""}, -#line 37 "kw.gperf" - {"ifdef", KW_IFDEF}, -#line 59 "kw.gperf" - {"strlen", KW_STRLEN}, +#line 57 "kw.gperf" + {"restrict", KW_RESTRICT}, + {""}, {""}, +#line 16 "kw.gperf" + {"static", KW_STATIC}, + {""}, +#line 35 "kw.gperf" + {"continue", KW_CONTINUE}, +#line 127 "kw.gperf" + {"__sync_lock_test_and_set", KW___SYNC_LOCK_TEST_AND_SET}, +#line 30 "kw.gperf" + {"float", KW_FLOAT}, +#line 56 "kw.gperf" + {"pragma", KW_PRAGMA}, {""}, #line 94 "kw.gperf" {"__builtin_offsetof", KW___BUILTIN_OFFSETOF}, -#line 34 "kw.gperf" - {"enum", KW_ENUM}, - {""}, -#line 27 "kw.gperf" - {"switch", KW_SWITCH}, -#line 93 "kw.gperf" - {"__builtin_neg_overflow", KW___BUILTIN_NEG_OVERFLOW}, -#line 57 "kw.gperf" - {"restrict", KW_RESTRICT}, -#line 51 "kw.gperf" - {"goto", KW_GOTO}, +#line 128 "kw.gperf" + {"__sync_lock_release", KW___SYNC_LOCK_RELEASE}, {""}, #line 111 "kw.gperf" {"&", KW_AMP}, #line 117 "kw.gperf" {"&&", KW_LOGAND}, -#line 80 "kw.gperf" - {"__thread", KW__THREAD_LOCAL}, +#line 45 "kw.gperf" + {"__attribute__", KW___ATTRIBUTE__}, +#line 51 "kw.gperf" + {"goto", KW_GOTO}, {""}, {""}, +#line 12 "kw.gperf" + {"if", KW_IF}, +#line 54 "kw.gperf" + {"int", KW_INT}, +#line 122 "kw.gperf" + {"__atomic_store", KW___ATOMIC_STORE}, +#line 37 "kw.gperf" + {"ifdef", KW_IFDEF}, +#line 126 "kw.gperf" + {"__atomic_test_and_set", KW___ATOMIC_TEST_AND_SET}, +#line 84 "kw.gperf" + {"__atomic_exchange", KW___ATOMIC_EXCHANGE}, +#line 65 "kw.gperf" + {"volatile", KW_VOLATILE}, + {""}, {""}, {""}, +#line 21 "kw.gperf" + {"do", KW_DO}, + {""}, +#line 71 "kw.gperf" + {"_Static_assert", KW__STATIC_ASSERT}, + {""}, #line 38 "kw.gperf" {"ifndef", KW_IFNDEF}, - {""}, -#line 23 "kw.gperf" - {"unsigned", KW_UNSIGNED}, {""}, {""}, -#line 107 "kw.gperf" - {"{", KW_LB}, +#line 24 "kw.gperf" + {"long", KW_LONG}, + {""}, {""}, {""}, {""}, +#line 123 "kw.gperf" + {"__atomic_clear", KW___ATOMIC_CLEAR}, + {""}, +#line 32 "kw.gperf" + {"signed", KW_SIGNED}, +#line 40 "kw.gperf" + {"defined", KW_DEFINED}, + {""}, {""}, {""}, +#line 53 "kw.gperf" + {"inline", KW_INLINE}, +#line 36 "kw.gperf" + {"include", KW_INCLUDE}, + {""}, {""}, {""}, +#line 50 "kw.gperf" + {"extern", KW_EXTERN}, #line 52 "kw.gperf" {"include_next", KW_INCLUDE_NEXT}, {""}, {""}, {""}, -#line 100 "kw.gperf" - {"__builtin_strlen", KW___BUILTIN_STRLEN}, -#line 126 "kw.gperf" - {"__builtin_ia32_movntdq", KW___BUILTIN_IA32_MOVNTDQ}, - {""}, {""}, {""}, -#line 120 "kw.gperf" - {".", KW_DOT}, -#line 36 "kw.gperf" - {"include", KW_INCLUDE}, -#line 122 "kw.gperf" - {"__atomic_fetch_add", KW___ATOMIC_FETCH_ADD}, - {""}, {""}, #line 14 "kw.gperf" {"return", KW_RETURN}, - {""}, {""}, {""}, -#line 26 "kw.gperf" - {"union", KW_UNION}, -#line 127 "kw.gperf" + {""}, +#line 23 "kw.gperf" + {"unsigned", KW_UNSIGNED}, +#line 46 "kw.gperf" + {"_Noreturn", KW__NORETURN}, + {""}, +#line 130 "kw.gperf" {"__builtin_ia32_pmovmskb128", KW___BUILTIN_IA32_PMOVMSKB128}, +#line 42 "kw.gperf" + {"default", KW_DEFAULT}, + {""}, +#line 34 "kw.gperf" + {"enum", KW_ENUM}, + {""}, +#line 59 "kw.gperf" + {"strlen", KW_STRLEN}, +#line 129 "kw.gperf" + {"__builtin_ia32_movntdq", KW___BUILTIN_IA32_MOVNTDQ}, + {""}, +#line 83 "kw.gperf" + {"__builtin_assume_aligned", KW___BUILTIN_ASSUME_ALIGNED}, + {""}, +#line 27 "kw.gperf" + {"switch", KW_SWITCH}, + {""}, {""}, {""}, {""}, {""}, +#line 93 "kw.gperf" + {"__builtin_neg_overflow", KW___BUILTIN_NEG_OVERFLOW}, + {""}, {""}, {""}, +#line 107 "kw.gperf" + {"{", KW_LB}, + {""}, +#line 80 "kw.gperf" + {"__thread", KW__THREAD_LOCAL}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 100 "kw.gperf" + {"__builtin_strlen", KW___BUILTIN_STRLEN}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, +#line 120 "kw.gperf" + {".", KW_DOT}, + {""}, {""}, {""}, +#line 33 "kw.gperf" + {"break", KW_BREAK}, + {""}, {""}, {""}, {""}, {""}, #line 112 "kw.gperf" {"*", KW_STAR}, {""}, #line 121 "kw.gperf" {"__atomic_load", KW___ATOMIC_LOAD}, - {""}, {""}, {""}, {""}, -#line 44 "kw.gperf" - {"register", KW_REGISTER}, - {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, #line 106 "kw.gperf" {")", KW_RP}, - {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, +#line 26 "kw.gperf" + {"union", KW_UNION}, + {""}, {""}, {""}, {""}, {""}, #line 105 "kw.gperf" {"(", KW_LP}, - {""}, {""}, {""}, {""}, -#line 53 "kw.gperf" - {"inline", KW_INLINE}, - {""}, -#line 123 "kw.gperf" - {"__atomic_sub_fetch", KW___ATOMIC_SUB_FETCH}, - {""}, {""}, + {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, #line 113 "kw.gperf" - {"!", KW_EXCLAIM} + {"!", KW_EXCLAIM}, + {""}, +#line 125 "kw.gperf" + {"__atomic_fetch_add", KW___ATOMIC_FETCH_ADD}, + {""}, {""}, {""}, {""}, +#line 124 "kw.gperf" + {"__atomic_sub_fetch", KW___ATOMIC_SUB_FETCH} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) diff --git a/third_party/chibicc/parse.c b/third_party/chibicc/parse.c index 7945505e8..35b1f2e1e 100644 --- a/third_party/chibicc/parse.c +++ b/third_party/chibicc/parse.c @@ -559,6 +559,7 @@ static Token *thing_attributes(Token *tok, void *arg) { consume_attribute(&tok, tok, "warn_unused_result") || consume_attribute(&tok, tok, "flatten") || consume_attribute(&tok, tok, "leaf") || + consume_attribute(&tok, tok, "no_reorder") || consume_attribute(&tok, tok, "dontthrow") || consume_attribute(&tok, tok, "optnone") || consume_attribute(&tok, tok, "returns_twice") || @@ -3259,7 +3260,42 @@ static Node *primary(Token **rest, Token *tok) { tok = skip(tok, ','); node->rhs = assign(&tok, tok); tok = skip(tok, ','); - const_expr(&tok, tok); + node->memorder = const_expr(&tok, tok); + *rest = skip(tok, ')'); + return node; + } + if (kw == KW___ATOMIC_STORE) { + Node *node = new_node(ND_STORE, tok); + tok = skip(tok->next, '('); + node->lhs = assign(&tok, tok); + add_type(node->lhs); + node->ty = node->lhs->ty->base; + tok = skip(tok, ','); + node->rhs = assign(&tok, tok); + tok = skip(tok, ','); + node->memorder = const_expr(&tok, tok); + *rest = skip(tok, ')'); + return node; + } + if (kw == KW___ATOMIC_TEST_AND_SET) { + Node *node = new_node(ND_TESTANDSETA, tok); + tok = skip(tok->next, '('); + node->lhs = assign(&tok, tok); + add_type(node->lhs); + node->ty = node->lhs->ty->base; + tok = skip(tok, ','); + node->memorder = const_expr(&tok, tok); + *rest = skip(tok, ')'); + return node; + } + if (kw == KW___ATOMIC_CLEAR) { + Node *node = new_node(ND_CLEAR, tok); + tok = skip(tok->next, '('); + node->lhs = assign(&tok, tok); + add_type(node->lhs); + node->ty = node->lhs->ty->base; + tok = skip(tok, ','); + node->memorder = const_expr(&tok, tok); *rest = skip(tok, ')'); return node; } diff --git a/third_party/chibicc/preprocess.c b/third_party/chibicc/preprocess.c index d71363dd6..a5a6acd74 100644 --- a/third_party/chibicc/preprocess.c +++ b/third_party/chibicc/preprocess.c @@ -1174,6 +1174,14 @@ __INT_FAST32_TYPE__\000\ int\000\ __UINT_FAST32_TYPE__\000\ unsigned\000\ +__INT_FAST8_MAX__\000\ +0x7f\000\ +__INT_FAST16_MAX__\000\ +0x7fffffff\000\ +__INT_FAST32_MAX__\000\ +0x7fffffff\000\ +__INT_FAST64_MAX__\000\ +0x7fffffffffffffffl\000\ __INT_FAST64_TYPE__\000\ long\000\ __UINT_FAST64_TYPE__\000\ diff --git a/third_party/chibicc/test/spinlock_test.c b/third_party/chibicc/test/spinlock_test.c index 5e50af42d..07086abb0 100644 --- a/third_party/chibicc/test/spinlock_test.c +++ b/third_party/chibicc/test/spinlock_test.c @@ -15,12 +15,66 @@ #define SPUNLOCK(lock) __sync_lock_release(lock) +//////////////////////////////////////////////////////////////////////////////// + +#define SPINLOCK2(lock) \ + do { \ + for (;;) { \ + typeof(*(lock)) x; \ + __atomic_load(lock, &x, __ATOMIC_RELAXED); \ + if (!x && !__atomic_test_and_set(lock, __ATOMIC_SEQ_CST)) { \ + break; \ + } else { \ + __builtin_ia32_pause(); \ + } \ + } \ + } while (0) + +#define SPUNLOCK2(lock) __sync_lock_release(lock) + +//////////////////////////////////////////////////////////////////////////////// + _Alignas(64) char lock; main() { + int x, y; + ASSERT(0, lock); SPINLOCK(&lock); ASSERT(1, lock); SPUNLOCK(&lock); ASSERT(0, lock); + + ASSERT(0, lock); + SPINLOCK2(&lock); + ASSERT(1, lock); + SPUNLOCK2(&lock); + ASSERT(0, lock); + + x = 0; + y = 7; + ASSERT(0, x); + ASSERT(7, y); + __atomic_store(&x, &y, __ATOMIC_RELAXED); + ASSERT(7, x); + ASSERT(7, y); + + x = 0; + y = 7; + ASSERT(0, x); + ASSERT(7, y); + __atomic_store(&x, &y, __ATOMIC_SEQ_CST); + ASSERT(7, x); + ASSERT(7, y); + + x = 5; + y = __atomic_test_and_set(&x, __ATOMIC_SEQ_CST); + ASSERT(1, x); + ASSERT(5, y); + + x = 5; + __atomic_clear(&x, __ATOMIC_SEQ_CST); + ASSERT(0, x); + + // } diff --git a/third_party/chibicc/test/test.mk b/third_party/chibicc/test/test.mk index e42be50b0..3686e6db3 100644 --- a/third_party/chibicc/test/test.mk +++ b/third_party/chibicc/test/test.mk @@ -79,7 +79,7 @@ o/$(MODE)/third_party/chibicc/test/%.com.dbg: \ o/$(MODE)/third_party/chibicc/test/%.chibicc.o \ $(THIRD_PARTY_CHIBICC_TEST_A).pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \ @@ -88,7 +88,7 @@ o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \ o/$(MODE)/third_party/chibicc/test/%.chibicc2.o \ $(THIRD_PARTY_CHIBICC_TEST2_A).pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PRECIOUS: $(THIRD_PARTY_CHIBICC_TEST_OBJS) diff --git a/third_party/chibicc/type.c b/third_party/chibicc/type.c index f3c4bba03..5ddac510d 100644 --- a/third_party/chibicc/type.c +++ b/third_party/chibicc/type.c @@ -1,3 +1,4 @@ +#include "libc/assert.h" #include "third_party/chibicc/chibicc.h" /* TODO(jart): Why can't these be const? */ @@ -144,6 +145,9 @@ static Type *get_common_type(Type *ty1, Type *ty2) { // // This operation is called the "usual arithmetic conversion". static void usual_arith_conv(Node **lhs, Node **rhs) { + if (!(*lhs)->ty || !(*rhs)->ty) { + error_tok((*lhs)->tok, "internal npe error"); + } Type *ty = get_common_type((*lhs)->ty, (*rhs)->ty); *lhs = new_cast(*lhs, ty); *rhs = new_cast(*rhs, ty); diff --git a/third_party/dlmalloc/dlmalloc.greg.c b/third_party/dlmalloc/dlmalloc.c similarity index 99% rename from third_party/dlmalloc/dlmalloc.greg.c rename to third_party/dlmalloc/dlmalloc.c index 6bc34ac80..b5f76f6b4 100644 --- a/third_party/dlmalloc/dlmalloc.greg.c +++ b/third_party/dlmalloc/dlmalloc.c @@ -351,7 +351,7 @@ unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); # endif # endif # ifdef _SC_PAGE_SIZE -# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# define malloc_getpagesize 4096 /*sysconf(_SC_PAGE_SIZE)*/ # else # if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) extern size_t getpagesize(); @@ -1514,7 +1514,10 @@ static int init_mparams(void) { size_t psize; size_t gsize; -#ifndef WIN32 +#if defined(__COSMOPOLITAN__) + psize = 4096; + gsize = 65536; +#elif !defined(WIN32) psize = malloc_getpagesize; gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize); #else /* WIN32 */ diff --git a/third_party/dlmalloc/dlmalloc.mk b/third_party/dlmalloc/dlmalloc.mk index 2c27169fa..6c009af2c 100644 --- a/third_party/dlmalloc/dlmalloc.mk +++ b/third_party/dlmalloc/dlmalloc.mk @@ -49,10 +49,17 @@ $(THIRD_PARTY_DLMALLOC_A).pkg: \ $(THIRD_PARTY_DLMALLOC_A_OBJS) \ $(foreach x,$(THIRD_PARTY_DLMALLOC_A_DIRECTDEPS),$($(x)_A).pkg) -$(THIRD_PARTY_DLMALLOC_A_OBJS): \ +# we can't use address sanitizer because: +# address sanitizer depends on dlmalloc +o/$(MODE)/third_party/dlmalloc/dlmalloc.o: \ OVERRIDE_CFLAGS += \ - $(NO_MAGIC) \ -ffreestanding \ + -fno-sanitize=address + +# we must segregate codegen because: +# file contains multiple independently linkable apis +o/$(MODE)/third_party/dlmalloc/dlmalloc.o: \ + OVERRIDE_CFLAGS += \ -ffunction-sections \ -fdata-sections diff --git a/third_party/dlmalloc/vespene.greg.c b/third_party/dlmalloc/vespene.c similarity index 97% rename from third_party/dlmalloc/vespene.greg.c rename to third_party/dlmalloc/vespene.c index bbcbd0989..da84f24cc 100644 --- a/third_party/dlmalloc/vespene.greg.c +++ b/third_party/dlmalloc/vespene.c @@ -33,7 +33,7 @@ void *dlmalloc_requires_more_vespene_gas(size_t size) { if ((p = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { if (weaken(__asan_poison)) { - weaken(__asan_poison)((uintptr_t)p, size, kAsanHeapFree); + weaken(__asan_poison)(p, size, kAsanHeapFree); } } return p; diff --git a/third_party/gcc/bin/x86_64-linux-musl-c++ b/third_party/gcc/bin/x86_64-linux-musl-c++ deleted file mode 120000 index 5311ab2a9..000000000 --- a/third_party/gcc/bin/x86_64-linux-musl-c++ +++ /dev/null @@ -1 +0,0 @@ -x86_64-linux-musl-g++ \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-c++.sym b/third_party/gcc/bin/x86_64-linux-musl-c++.sym new file mode 100644 index 000000000..5311ab2a9 --- /dev/null +++ b/third_party/gcc/bin/x86_64-linux-musl-c++.sym @@ -0,0 +1 @@ +x86_64-linux-musl-g++ \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-cc b/third_party/gcc/bin/x86_64-linux-musl-cc deleted file mode 120000 index d7bd3b204..000000000 --- a/third_party/gcc/bin/x86_64-linux-musl-cc +++ /dev/null @@ -1 +0,0 @@ -x86_64-linux-musl-gcc \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-cc.sym b/third_party/gcc/bin/x86_64-linux-musl-cc.sym new file mode 100644 index 000000000..d7bd3b204 --- /dev/null +++ b/third_party/gcc/bin/x86_64-linux-musl-cc.sym @@ -0,0 +1 @@ +x86_64-linux-musl-gcc \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-gcc-9.2.0 b/third_party/gcc/bin/x86_64-linux-musl-gcc-9.2.0 deleted file mode 120000 index d7bd3b204..000000000 --- a/third_party/gcc/bin/x86_64-linux-musl-gcc-9.2.0 +++ /dev/null @@ -1 +0,0 @@ -x86_64-linux-musl-gcc \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-gcc-9.2.0.sym b/third_party/gcc/bin/x86_64-linux-musl-gcc-9.2.0.sym new file mode 100644 index 000000000..d7bd3b204 --- /dev/null +++ b/third_party/gcc/bin/x86_64-linux-musl-gcc-9.2.0.sym @@ -0,0 +1 @@ +x86_64-linux-musl-gcc \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-ld b/third_party/gcc/bin/x86_64-linux-musl-ld deleted file mode 120000 index cf399b994..000000000 --- a/third_party/gcc/bin/x86_64-linux-musl-ld +++ /dev/null @@ -1 +0,0 @@ -../x86_64-linux-musl/bin/ld.bfd \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-ld.bfd b/third_party/gcc/bin/x86_64-linux-musl-ld.bfd deleted file mode 120000 index cf399b994..000000000 --- a/third_party/gcc/bin/x86_64-linux-musl-ld.bfd +++ /dev/null @@ -1 +0,0 @@ -../x86_64-linux-musl/bin/ld.bfd \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-ld.bfd.sym b/third_party/gcc/bin/x86_64-linux-musl-ld.bfd.sym new file mode 100644 index 000000000..cf399b994 --- /dev/null +++ b/third_party/gcc/bin/x86_64-linux-musl-ld.bfd.sym @@ -0,0 +1 @@ +../x86_64-linux-musl/bin/ld.bfd \ No newline at end of file diff --git a/third_party/gcc/bin/x86_64-linux-musl-ld.sym b/third_party/gcc/bin/x86_64-linux-musl-ld.sym new file mode 100644 index 000000000..cf399b994 --- /dev/null +++ b/third_party/gcc/bin/x86_64-linux-musl-ld.sym @@ -0,0 +1 @@ +../x86_64-linux-musl/bin/ld.bfd \ No newline at end of file diff --git a/third_party/gcc/libexec/gcc/x86_64-linux-musl/9.2.0/as b/third_party/gcc/libexec/gcc/x86_64-linux-musl/9.2.0/as deleted file mode 120000 index 244777532..000000000 --- a/third_party/gcc/libexec/gcc/x86_64-linux-musl/9.2.0/as +++ /dev/null @@ -1 +0,0 @@ -../../../../bin/x86_64-linux-musl-as \ No newline at end of file diff --git a/third_party/gcc/libexec/gcc/x86_64-linux-musl/9.2.0/as.sym b/third_party/gcc/libexec/gcc/x86_64-linux-musl/9.2.0/as.sym new file mode 100644 index 000000000..244777532 --- /dev/null +++ b/third_party/gcc/libexec/gcc/x86_64-linux-musl/9.2.0/as.sym @@ -0,0 +1 @@ +../../../../bin/x86_64-linux-musl-as \ No newline at end of file diff --git a/third_party/gcc/unbundle.sh b/third_party/gcc/unbundle.sh deleted file mode 100755 index 77bfb0168..000000000 --- a/third_party/gcc/unbundle.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐ -#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘ -mkdir -p o/third_party -cp -R third_party/gcc o/third_party/gcc.$$ -for f in $(find o/third_party/gcc.$$ -name \*.gz); do - gunzip $f - chmod +x ${f%.gz} -done -mv o/third_party/gcc.$$ o/third_party/gcc diff --git a/third_party/gcc/x86_64-linux-musl/bin/ar b/third_party/gcc/x86_64-linux-musl/bin/ar deleted file mode 120000 index 18b47c53d..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/ar +++ /dev/null @@ -1 +0,0 @@ -../../bin/x86_64-linux-musl-ar \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/ar.sym b/third_party/gcc/x86_64-linux-musl/bin/ar.sym new file mode 100644 index 000000000..18b47c53d --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/ar.sym @@ -0,0 +1 @@ +../../bin/x86_64-linux-musl-ar \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/as b/third_party/gcc/x86_64-linux-musl/bin/as deleted file mode 120000 index 9db7664e8..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/as +++ /dev/null @@ -1 +0,0 @@ -../../bin/x86_64-linux-musl-as \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/as.sym b/third_party/gcc/x86_64-linux-musl/bin/as.sym new file mode 100644 index 000000000..9db7664e8 --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/as.sym @@ -0,0 +1 @@ +../../bin/x86_64-linux-musl-as \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/ld b/third_party/gcc/x86_64-linux-musl/bin/ld deleted file mode 120000 index 3f5ce09ea..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/ld +++ /dev/null @@ -1 +0,0 @@ -ld.bfd \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/ld.sym b/third_party/gcc/x86_64-linux-musl/bin/ld.sym new file mode 100644 index 000000000..3f5ce09ea --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/ld.sym @@ -0,0 +1 @@ +ld.bfd \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/nm b/third_party/gcc/x86_64-linux-musl/bin/nm deleted file mode 120000 index 8312c6cf2..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/nm +++ /dev/null @@ -1 +0,0 @@ -../../bin/x86_64-linux-musl-nm \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/nm.sym b/third_party/gcc/x86_64-linux-musl/bin/nm.sym new file mode 100644 index 000000000..8312c6cf2 --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/nm.sym @@ -0,0 +1 @@ +../../bin/x86_64-linux-musl-nm \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/objcopy b/third_party/gcc/x86_64-linux-musl/bin/objcopy deleted file mode 120000 index 1996c8fbd..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/objcopy +++ /dev/null @@ -1 +0,0 @@ -../../bin/x86_64-linux-musl-objcopy \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/objcopy.sym b/third_party/gcc/x86_64-linux-musl/bin/objcopy.sym new file mode 100644 index 000000000..1996c8fbd --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/objcopy.sym @@ -0,0 +1 @@ +../../bin/x86_64-linux-musl-objcopy \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/objdump b/third_party/gcc/x86_64-linux-musl/bin/objdump deleted file mode 120000 index 9e6eb648e..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/objdump +++ /dev/null @@ -1 +0,0 @@ -../../bin/x86_64-linux-musl-objdump \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/objdump.sym b/third_party/gcc/x86_64-linux-musl/bin/objdump.sym new file mode 100644 index 000000000..9e6eb648e --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/objdump.sym @@ -0,0 +1 @@ +../../bin/x86_64-linux-musl-objdump \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/ranlib b/third_party/gcc/x86_64-linux-musl/bin/ranlib deleted file mode 120000 index 9fd9a9ba5..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/ranlib +++ /dev/null @@ -1 +0,0 @@ -../../bin/x86_64-linux-musl-ranlib \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/ranlib.sym b/third_party/gcc/x86_64-linux-musl/bin/ranlib.sym new file mode 100644 index 000000000..9fd9a9ba5 --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/ranlib.sym @@ -0,0 +1 @@ +../../bin/x86_64-linux-musl-ranlib \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/readelf b/third_party/gcc/x86_64-linux-musl/bin/readelf deleted file mode 120000 index bce53096b..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/readelf +++ /dev/null @@ -1 +0,0 @@ -../../bin/x86_64-linux-musl-readelf \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/readelf.sym b/third_party/gcc/x86_64-linux-musl/bin/readelf.sym new file mode 100644 index 000000000..bce53096b --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/readelf.sym @@ -0,0 +1 @@ +../../bin/x86_64-linux-musl-readelf \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/strip b/third_party/gcc/x86_64-linux-musl/bin/strip deleted file mode 120000 index 3905fc078..000000000 --- a/third_party/gcc/x86_64-linux-musl/bin/strip +++ /dev/null @@ -1 +0,0 @@ -../../bin/x86_64-linux-musl-strip \ No newline at end of file diff --git a/third_party/gcc/x86_64-linux-musl/bin/strip.sym b/third_party/gcc/x86_64-linux-musl/bin/strip.sym new file mode 100644 index 000000000..3905fc078 --- /dev/null +++ b/third_party/gcc/x86_64-linux-musl/bin/strip.sym @@ -0,0 +1 @@ +../../bin/x86_64-linux-musl-strip \ No newline at end of file diff --git a/third_party/libcxx/errno.h b/third_party/libcxx/errno.h index 00d7f7f83..1dfe334b6 100644 --- a/third_party/libcxx/errno.h +++ b/third_party/libcxx/errno.h @@ -78,320 +78,6 @@ static const int __elast2 = 105; // supply errno values likely to be missing, particularly on Windows -#ifndef EAFNOSUPPORT -#define EAFNOSUPPORT 9901 -#endif - -#ifndef EADDRINUSE -#define EADDRINUSE 9902 -#endif - -#ifndef EADDRNOTAVAIL -#define EADDRNOTAVAIL 9903 -#endif - -#ifndef EISCONN -#define EISCONN 9904 -#endif - -#ifndef EBADMSG -#define EBADMSG 9905 -#endif - -#ifndef ECONNABORTED -#define ECONNABORTED 9906 -#endif - -#ifndef EALREADY -#define EALREADY 9907 -#endif - -#ifndef ECONNREFUSED -#define ECONNREFUSED 9908 -#endif - -#ifndef ECONNRESET -#define ECONNRESET 9909 -#endif - -#ifndef EDESTADDRREQ -#define EDESTADDRREQ 9910 -#endif - -#ifndef EHOSTUNREACH -#define EHOSTUNREACH 9911 -#endif - -#ifndef EIDRM -#define EIDRM 9912 -#endif - -#ifndef EMSGSIZE -#define EMSGSIZE 9913 -#endif - -#ifndef ENETDOWN -#define ENETDOWN 9914 -#endif - -#ifndef ENETRESET -#define ENETRESET 9915 -#endif - -#ifndef ENETUNREACH -#define ENETUNREACH 9916 -#endif - -#ifndef ENOBUFS -#define ENOBUFS 9917 -#endif - -#ifndef ENOLINK -#define ENOLINK 9918 -#endif - -#ifndef ENODATA -#define ENODATA 9919 -#endif - -#ifndef ENOMSG -#define ENOMSG 9920 -#endif - -#ifndef ENOPROTOOPT -#define ENOPROTOOPT 9921 -#endif - -#ifndef ENOSR -#define ENOSR 9922 -#endif - -#ifndef ENOTSOCK -#define ENOTSOCK 9923 -#endif - -#ifndef ENOSTR -#define ENOSTR 9924 -#endif - -#ifndef ENOTCONN -#define ENOTCONN 9925 -#endif - -#ifndef ENOTSUP -#define ENOTSUP 9926 -#endif - -#ifndef ECANCELED -#define ECANCELED 9927 -#endif - -#ifndef EINPROGRESS -#define EINPROGRESS 9928 -#endif - -#ifndef EOPNOTSUPP -#define EOPNOTSUPP 9929 -#endif - -#ifndef EWOULDBLOCK -#define EWOULDBLOCK 9930 -#endif - -#ifndef EOWNERDEAD -#define EOWNERDEAD 9931 -#endif - -#ifndef EPROTO -#define EPROTO 9932 -#endif - -#ifndef EPROTONOSUPPORT -#define EPROTONOSUPPORT 9933 -#endif - -#ifndef ENOTRECOVERABLE -#define ENOTRECOVERABLE 9934 -#endif - -#ifndef ETIME -#define ETIME 9935 -#endif - -#ifndef ETXTBSY -#define ETXTBSY 9936 -#endif - -#ifndef ETIMEDOUT -#define ETIMEDOUT 9938 -#endif - -#ifndef ELOOP -#define ELOOP 9939 -#endif - -#ifndef EOVERFLOW -#define EOVERFLOW 9940 -#endif - -#ifndef EPROTOTYPE -#define EPROTOTYPE 9941 -#endif - -#ifndef ENOSYS -#define ENOSYS 9942 -#endif - -#ifndef EINVAL -#define EINVAL 9943 -#endif - -#ifndef ERANGE -#define ERANGE 9944 -#endif - -#ifndef EILSEQ -#define EILSEQ 9945 -#endif - -// Windows Mobile doesn't appear to define these: - -#ifndef E2BIG -#define E2BIG 9946 -#endif - -#ifndef EDOM -#define EDOM 9947 -#endif - -#ifndef EFAULT -#define EFAULT 9948 -#endif - -#ifndef EBADF -#define EBADF 9949 -#endif - -#ifndef EPIPE -#define EPIPE 9950 -#endif - -#ifndef EXDEV -#define EXDEV 9951 -#endif - -#ifndef EBUSY -#define EBUSY 9952 -#endif - -#ifndef ENOTEMPTY -#define ENOTEMPTY 9953 -#endif - -#ifndef ENOEXEC -#define ENOEXEC 9954 -#endif - -#ifndef EEXIST -#define EEXIST 9955 -#endif - -#ifndef EFBIG -#define EFBIG 9956 -#endif - -#ifndef ENAMETOOLONG -#define ENAMETOOLONG 9957 -#endif - -#ifndef ENOTTY -#define ENOTTY 9958 -#endif - -#ifndef EINTR -#define EINTR 9959 -#endif - -#ifndef ESPIPE -#define ESPIPE 9960 -#endif - -#ifndef EIO -#define EIO 9961 -#endif - -#ifndef EISDIR -#define EISDIR 9962 -#endif - -#ifndef ECHILD -#define ECHILD 9963 -#endif - -#ifndef ENOLCK -#define ENOLCK 9964 -#endif - -#ifndef ENOSPC -#define ENOSPC 9965 -#endif - -#ifndef ENXIO -#define ENXIO 9966 -#endif - -#ifndef ENODEV -#define ENODEV 9967 -#endif - -#ifndef ENOENT -#define ENOENT 9968 -#endif - -#ifndef ESRCH -#define ESRCH 9969 -#endif - -#ifndef ENOTDIR -#define ENOTDIR 9970 -#endif - -#ifndef ENOMEM -#define ENOMEM 9971 -#endif - -#ifndef EPERM -#define EPERM 9972 -#endif - -#ifndef EACCES -#define EACCES 9973 -#endif - -#ifndef EROFS -#define EROFS 9974 -#endif - -#ifndef EDEADLK -#define EDEADLK 9975 -#endif - -#ifndef EAGAIN -#define EAGAIN 9976 -#endif - -#ifndef ENFILE -#define ENFILE 9977 -#endif - -#ifndef EMFILE -#define EMFILE 9978 -#endif - -#ifndef EMLINK -#define EMLINK 9979 -#endif - #endif // __cplusplus #endif // _LIBCPP_ERRNO_H diff --git a/third_party/libcxx/libcxx.mk b/third_party/libcxx/libcxx.mk index df2414a9f..500a96445 100644 --- a/third_party/libcxx/libcxx.mk +++ b/third_party/libcxx/libcxx.mk @@ -69,7 +69,7 @@ THIRD_PARTY_LIBCXX_A_SRCS_CC = \ THIRD_PARTY_LIBCXX_A_SRCS = \ $(THIRD_PARTY_LIBCXX_A_SRCS_S) \ - $(THIRD_PARTY_LIBCXX_A_SRCS_C) + $(THIRD_PARTY_LIBCXX_A_SRCS_CC) THIRD_PARTY_LIBCXX_A_OBJS = \ $(THIRD_PARTY_LIBCXX_A_SRCS_S:%.S=o/$(MODE)/%.o) \ diff --git a/third_party/libcxx/random.cc b/third_party/libcxx/random.cc index cb75edb4b..a09a5c9e1 100644 --- a/third_party/libcxx/random.cc +++ b/third_party/libcxx/random.cc @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "libc/rand/rand.h" #include "third_party/libcxx/__config" #if defined(_LIBCPP_USING_WIN32_RANDOM) @@ -24,15 +25,6 @@ #include "third_party/libcxx/stdio.h" #include "third_party/libcxx/stdlib.h" -#if defined(_LIBCPP_USING_GETENTROPY) -#include "libc/isystem/sys/random.h" -#elif defined(_LIBCPP_USING_DEV_RANDOM) -#include "third_party/libcxx/fcntl.h" -#include "third_party/libcxx/unistd.h" -#elif defined(_LIBCPP_USING_NACL_RANDOM) -#include "third_party/libcxx/nacl/nacl_random.h" -#endif - _LIBCPP_BEGIN_NAMESPACE_STD #if defined(_LIBCPP_USING_GETENTROPY) diff --git a/third_party/libcxx/stdexcept_default.hh b/third_party/libcxx/stdexcept_default.hh index 40e6ab78e..63d489286 100644 --- a/third_party/libcxx/stdexcept_default.hh +++ b/third_party/libcxx/stdexcept_default.hh @@ -9,12 +9,6 @@ #include "third_party/libcxx/refstring.hh" #include "third_party/libcxx/string" -/* For _LIBCPPABI_VERSION */ -#if !defined(_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY) && \ - (defined(LIBCXX_BUILDING_LIBCXXABI) || defined(LIBCXXRT)) -#include "third_party/libcxx/cxxabi.h" -#endif - static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char*), ""); namespace std // purposefully not using versioning namespace diff --git a/third_party/libcxx/system_error.cc b/third_party/libcxx/system_error.cc index 3e1185d6b..4f00c9650 100644 --- a/third_party/libcxx/system_error.cc +++ b/third_party/libcxx/system_error.cc @@ -19,10 +19,6 @@ #include "third_party/libcxx/string.h" #include "third_party/libcxx/__debug" -#if defined(__ANDROID__) -#include "third_party/libcxx/android/api-level.h" -#endif - _LIBCPP_BEGIN_NAMESPACE_STD // class error_category diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index 4c0140ce2..a0df3a16e 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -772,7 +772,8 @@ static ssize_t linenoiseRead(int fd, char *buf, size_t size, return -1; } if (gotcont && rawmode != -1) { - linenoiseEnableRawMode(rawmode); + rawmode = -1; + linenoiseEnableRawMode(0); if (l) refreshme = 1; } if (l && gotwinch) refreshme = 1; diff --git a/third_party/lua/lrepl.c b/third_party/lua/lrepl.c index 482b0577e..c579add12 100644 --- a/third_party/lua/lrepl.c +++ b/third_party/lua/lrepl.c @@ -234,9 +234,9 @@ static ssize_t pushline (lua_State *L, int firstline) { ssize_t rc; char *prmt; globalL = L; + prmt = strdup(get_prompt(L, firstline)); + lua_pop(L, 1); /* remove prompt */ if (lua_repl_isterminal) { - prmt = strdup(get_prompt(L, firstline)); - lua_pop(L, 1); /* remove prompt */ LUA_REPL_UNLOCK; rc = linenoiseEdit(lua_repl_linenoise, prmt, &b, !firstline || lua_repl_blocking); free(prmt); @@ -250,12 +250,20 @@ static ssize_t pushline (lua_State *L, int firstline) { LUA_REPL_LOCK; } else { LUA_REPL_UNLOCK; + fputs(prmt, stdout); + fflush(stdout); b = linenoiseGetLine(stdin); + if (b) { + rc = 1; + } else if (ferror(stdin)) { + rc = -1; + } else { + rc = 0; + } LUA_REPL_LOCK; - rc = b ? 1 : -1; } if (!(rc == -1 && errno == EAGAIN)) { - write(1, "\n", 1); + write(1, "\n", 1); } if (rc == -1 || (!rc && !b)) { return rc; @@ -380,6 +388,13 @@ int lua_loadline (lua_State *L) { } +void lua_sigint (lua_State *L, int sig) { + int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT; + lua_sethook(L, lstop, flag, 1); +} + + + /* ** Function to be called at a C signal. Because a C signal cannot ** just change a Lua state (as there is no proper synchronization), @@ -387,6 +402,7 @@ int lua_loadline (lua_State *L) { ** interpreter. */ static void laction (int i) { + lua_sigint(globalL, i); int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT; lua_sethook(globalL, lstop, flag, 1); } diff --git a/third_party/lua/lrepl.h b/third_party/lua/lrepl.h index 5de303a7a..304bc3ac4 100644 --- a/third_party/lua/lrepl.h +++ b/third_party/lua/lrepl.h @@ -28,6 +28,7 @@ extern linenoiseCompletionCallback *lua_repl_completions_callback; void lua_freerepl(void); int lua_loadline(lua_State *); void lua_l_print(lua_State *); +void lua_sigint(lua_State *, int); void lua_initrepl(lua_State *, const char *); int lua_report(lua_State *, int); int lua_runchunk(lua_State *, int, int); diff --git a/third_party/lua/lua.main.c b/third_party/lua/lua.main.c index 73818ea0f..9a0ed28fc 100644 --- a/third_party/lua/lua.main.c +++ b/third_party/lua/lua.main.c @@ -307,7 +307,8 @@ static void doREPL (lua_State *L) { progname = NULL; /* no 'progname' on errors in interactive mode */ lua_initrepl(L, LUA_PROGNAME); for (;;) { - linenoiseEnableRawMode(0); + if (lua_repl_isterminal) + linenoiseEnableRawMode(0); TryAgain: status = lua_loadline(L); if (status == -2 && errno == EAGAIN) { @@ -315,7 +316,8 @@ static void doREPL (lua_State *L) { poll(&(struct pollfd){0, POLLIN}, 1, -1); goto TryAgain; } - linenoiseDisableRawMode(); + if (lua_repl_isterminal) + linenoiseDisableRawMode(); if (status == -1) { break; } else if (status == -2) { diff --git a/third_party/lua/lua.mk b/third_party/lua/lua.mk index e9915859f..9a42729dc 100644 --- a/third_party/lua/lua.mk +++ b/third_party/lua/lua.mk @@ -59,7 +59,7 @@ o/$(MODE)/third_party/lua/lua.com.dbg: \ $(THIRD_PARTY_LUA_A).pkg \ o/$(MODE)/third_party/lua/lua.main.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/lua/luac.com.dbg: \ @@ -68,7 +68,7 @@ o/$(MODE)/third_party/lua/luac.com.dbg: \ $(THIRD_PARTY_LUA_A).pkg \ o/$(MODE)/third_party/lua/luac.main.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/lua/lua.com: \ @@ -81,6 +81,7 @@ o/$(MODE)/third_party/lua/lua.com: \ @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \ o/$(MODE)/third_party/lua/.lua/.symtab +o/$(MODE)/third_party/lua/lmathlib.o \ o//third_party/lua/lgc.o: \ OVERRIDE_CFLAGS += \ -O2 diff --git a/third_party/lz4cli/lz4cli.mk b/third_party/lz4cli/lz4cli.mk index 568db66c6..2c1b93d19 100644 --- a/third_party/lz4cli/lz4cli.mk +++ b/third_party/lz4cli/lz4cli.mk @@ -56,7 +56,7 @@ o/$(MODE)/third_party/lz4cli/lz4cli.com.dbg: \ $(THIRD_PARTY_LZ4CLI_DEPS) \ $(THIRD_PARTY_LZ4CLI_OBJS) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(THIRD_PARTY_LZ4CLI_OBJS): \ diff --git a/third_party/make/ar.c b/third_party/make/ar.c index 2b4cd30a8..f55738e6e 100644 --- a/third_party/make/ar.c +++ b/third_party/make/ar.c @@ -14,7 +14,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "libc/alg/alg.h" #include "third_party/make/dep.h" diff --git a/third_party/make/arscan.c b/third_party/make/arscan.c index ce942ec6c..925e12783 100644 --- a/third_party/make/arscan.c +++ b/third_party/make/arscan.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "libc/sysv/consts/o.h" -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /* clang-format off */ #ifdef TEST diff --git a/third_party/make/commands.c b/third_party/make/commands.c index 0792db7f3..48f98daed 100644 --- a/third_party/make/commands.c +++ b/third_party/make/commands.c @@ -14,7 +14,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "third_party/make/dep.h" #include "third_party/make/filedef.h" diff --git a/third_party/make/config.h b/third_party/make/config.h index 48f976078..14385ed0b 100644 --- a/third_party/make/config.h +++ b/third_party/make/config.h @@ -620,7 +620,7 @@ /* #undef HAVE__SET_INVALID_PARAMETER_HANDLER */ /* Build host information. */ -#define MAKE_HOST "x86_64-pc-linux-gnu" +#define MAKE_HOST "x86_64-pc-cosmopolitan" /* Define to 1 to enable job server support in GNU make. */ /* TODO(jart): make it work */ diff --git a/third_party/make/default.c b/third_party/make/default.c index b71edf8f5..1ba88c285 100644 --- a/third_party/make/default.c +++ b/third_party/make/default.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "third_party/make/filedef.h" #include "third_party/make/variable.h" diff --git a/third_party/make/dir.c b/third_party/make/dir.c index fdfdd6686..9a828158b 100644 --- a/third_party/make/dir.c +++ b/third_party/make/dir.c @@ -14,7 +14,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "third_party/make/dep.h" #include "third_party/make/filedef.h" @@ -689,15 +689,9 @@ void print_dir_data_base(void) { if (dir->contents == 0) printf(_("# %s: could not be stat'd.\n"), dir->name); else if (dir->contents->dirfiles.ht_vec == 0) { -#ifdef WINDOWS32 - printf(_("# %s (key %s, mtime %I64u): could not be opened.\n"), - dir->name, dir->contents->path_key, - (unsigned long long)dir->contents->mtime); -#else /* WINDOWS32 */ printf(_("# %s (device %ld, inode %ld): could not be opened.\n"), dir->name, (long int)dir->contents->dev, (long int)dir->contents->ino); -#endif /* WINDOWS32 */ } else { unsigned int f = 0; unsigned int im = 0; @@ -715,14 +709,8 @@ void print_dir_data_base(void) { ++f; } } -#ifdef WINDOWS32 - printf(_("# %s (key %s, mtime %I64u): "), dir->name, - dir->contents->path_key, - (unsigned long long)dir->contents->mtime); -#else /* WINDOWS32 */ printf(_("# %s (device %ld, inode %ld): "), dir->name, (long)dir->contents->dev, (long)dir->contents->ino); -#endif /* WINDOWS32 */ if (f == 0) fputs(_("No"), stdout); else @@ -822,9 +810,7 @@ static struct dirent *read_dirstream(__ptr_t stream) { #ifdef _DIRENT_HAVE_D_NAMLEN d->d_namlen = len - 1; #endif -#ifdef HAVE_STRUCT_DIRENT_D_TYPE d->d_type = df->type; -#endif memcpy(d->d_name, df->name, len); return d; } diff --git a/third_party/make/error.c b/third_party/make/error.c index 07bb08918..5fe39d0cc 100644 --- a/third_party/make/error.c +++ b/third_party/make/error.c @@ -57,48 +57,9 @@ void (*error_print_progname) (void); /* This variable is incremented each time 'error' is called. */ unsigned int error_message_count; -#ifdef _LIBC -/* In the GNU C library, there is a predefined variable for this. */ - -# define program_name program_invocation_name - -/* In GNU libc we want do not want to use the common name 'error' directly. - Instead make it a weak alias. */ -extern void __error (int status, int errnum, const char *message, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); -extern void __error_at_line (int status, int errnum, const char *file_name, - unsigned int line_number, const char *message, - ...) - __attribute__ ((__format__ (__printf__, 5, 6))); -# define error __error -# define error_at_line __error_at_line - -# define fflush(s) _IO_fflush (s) -# undef putc -# define putc(c, fp) _IO_putc (c, fp) - - -#else /* not _LIBC */ - -# if defined _WIN32 && ! defined __CYGWIN__ -/* Get declarations of the native Windows API functions. */ -# define WIN32_LEAN_AND_MEAN -/* Get _get_osfhandle. */ -# if GNULIB_MSVC_NOTHROW -# include "msvc-nothrow.h" -# else -# endif -# endif - -/* The gnulib override of fcntl is not needed in this file. */ -# undef fcntl - -# define program_name getprogname () - -# if GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r -# define __strerror_r strerror_r -# endif /* GNULIB_STRERROR_R_POSIX || HAVE_STRERROR_R || defined strerror_r */ -#endif /* not _LIBC */ +#undef fcntl +#define program_name getprogname () +#define __strerror_r strerror_r /* Return non-zero if FD is open. */ static int diff --git a/third_party/make/expand.c b/third_party/make/expand.c index bb09d877c..7ab3674f9 100644 --- a/third_party/make/expand.c +++ b/third_party/make/expand.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "third_party/make/filedef.h" #include "third_party/make/job.h" diff --git a/third_party/make/file.c b/third_party/make/file.c index a2c87f5dc..64c19216d 100644 --- a/third_party/make/file.c +++ b/third_party/make/file.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "third_party/make/filedef.h" #include "third_party/make/dep.h" diff --git a/third_party/make/function.c b/third_party/make/function.c index 4e70429f5..35adaeb4f 100644 --- a/third_party/make/function.c +++ b/third_party/make/function.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "third_party/make/filedef.h" #include "third_party/make/variable.h" diff --git a/third_party/make/guile.c b/third_party/make/guile.c index 2f9d3a2c7..b3a5e7099 100644 --- a/third_party/make/guile.c +++ b/third_party/make/guile.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" int guile_gmake_setup (const floc *flocp UNUSED) diff --git a/third_party/make/hash.c b/third_party/make/hash.c index 6ac3aa6e4..7f4806b01 100644 --- a/third_party/make/hash.c +++ b/third_party/make/hash.c @@ -14,7 +14,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "libc/assert.h" #include "third_party/make/hash.h" diff --git a/third_party/make/implicit.c b/third_party/make/implicit.c index 7e46e9022..e83e5192c 100644 --- a/third_party/make/implicit.c +++ b/third_party/make/implicit.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/rule.h" #include "third_party/make/dep.h" diff --git a/third_party/make/job.c b/third_party/make/job.c index df958aa3e..907a1f693 100644 --- a/third_party/make/job.c +++ b/third_party/make/job.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "third_party/make/debug.h" #include "third_party/make/filedef.h" diff --git a/third_party/make/load.c b/third_party/make/load.c index 9a5c77a1e..86466a8fc 100644 --- a/third_party/make/load.c +++ b/third_party/make/load.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" int load_file (const floc *flocp, const char **ldname UNUSED, int noerror) diff --git a/third_party/make/loadapi.c b/third_party/make/loadapi.c index 035ef3682..627e270b6 100644 --- a/third_party/make/loadapi.c +++ b/third_party/make/loadapi.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/variable.h" diff --git a/third_party/make/main.c b/third_party/make/main.c index 2fa0845b2..ec5ffea02 100644 --- a/third_party/make/main.c +++ b/third_party/make/main.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/os.h" #include "third_party/make/filedef.h" #include "third_party/make/dep.h" diff --git a/third_party/make/make.mk b/third_party/make/make.mk index fd472595e..8b703b661 100644 --- a/third_party/make/make.mk +++ b/third_party/make/make.mk @@ -13,6 +13,9 @@ THIRD_PARTY_MAKE_BINS = \ THIRD_PARTY_MAKE_A = \ o/$(MODE)/third_party/make/make.a +THIRD_PARTY_MAKE_INCS = \ + third_party/make/makeint.inc + THIRD_PARTY_MAKE_CHECKS = \ $(THIRD_PARTY_MAKE_A).pkg diff --git a/third_party/make/makeint.h b/third_party/make/makeint.inc similarity index 100% rename from third_party/make/makeint.h rename to third_party/make/makeint.inc diff --git a/third_party/make/misc.c b/third_party/make/misc.c index 82dbd4b9e..ee93ae300 100644 --- a/third_party/make/misc.c +++ b/third_party/make/misc.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/dep.h" #include "third_party/make/debug.h" diff --git a/third_party/make/output.c b/third_party/make/output.c index 8d576a11b..ecfc4b1e9 100644 --- a/third_party/make/output.c +++ b/third_party/make/output.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/os.h" #include "third_party/make/output.h" #include "libc/calls/struct/flock.h" diff --git a/third_party/make/posixos.c b/third_party/make/posixos.c index 084b3182a..058fbfb19 100644 --- a/third_party/make/posixos.c +++ b/third_party/make/posixos.c @@ -14,7 +14,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /**/ #include "libc/sysv/consts/sa.h" #include "third_party/make/debug.h" diff --git a/third_party/make/read.c b/third_party/make/read.c index ff81d8c61..696d60a97 100644 --- a/third_party/make/read.c +++ b/third_party/make/read.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/dep.h" #include "third_party/make/job.h" diff --git a/third_party/make/remake.c b/third_party/make/remake.c index 53ed0702f..2c50d2b81 100644 --- a/third_party/make/remake.c +++ b/third_party/make/remake.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/job.h" #include "third_party/make/commands.h" diff --git a/third_party/make/remote-stub.c b/third_party/make/remote-stub.c index 16c8d340d..4f51daae1 100644 --- a/third_party/make/remote-stub.c +++ b/third_party/make/remote-stub.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/job.h" #include "third_party/make/commands.h" diff --git a/third_party/make/rule.c b/third_party/make/rule.c index 03c833fc8..9d1503275 100644 --- a/third_party/make/rule.c +++ b/third_party/make/rule.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/dep.h" #include "third_party/make/job.h" diff --git a/third_party/make/signame.c b/third_party/make/signame.c index d390ab0cd..461f2e5f4 100644 --- a/third_party/make/signame.c +++ b/third_party/make/signame.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" /* If the system provides strsignal, we don't need it. */ diff --git a/third_party/make/strcache.c b/third_party/make/strcache.c index 4c515c8bb..70a9e2f15 100644 --- a/third_party/make/strcache.c +++ b/third_party/make/strcache.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/hash.h" /* A string cached here will never be freed, so we don't need to worry about diff --git a/third_party/make/variable.c b/third_party/make/variable.c index 048f92279..8daba9bd6 100644 --- a/third_party/make/variable.c +++ b/third_party/make/variable.c @@ -15,7 +15,7 @@ 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, see . */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/dep.h" diff --git a/third_party/make/vpath.c b/third_party/make/vpath.c index 545e10ae5..643701939 100644 --- a/third_party/make/vpath.c +++ b/third_party/make/vpath.c @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* clang-format off */ -#include "third_party/make/makeint.h" +#include "third_party/make/makeint.inc" #include "third_party/make/filedef.h" #include "third_party/make/variable.h" diff --git a/third_party/mbedtls/ecp.c b/third_party/mbedtls/ecp.c index c60d6fc64..fc269bd5e 100644 --- a/third_party/mbedtls/ecp.c +++ b/third_party/mbedtls/ecp.c @@ -512,6 +512,7 @@ int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp, * SECP384R1 192 IANA, NIST, FRANCE, GERMANY, NSA * X25519 112-128 IANA * X448 224 IANA + * SECP256K1 128 BITCOIN * BP384R1 GERMANY * SECP521R1 FRANCE * GC512A RUSSIA diff --git a/third_party/mbedtls/ecp256.c b/third_party/mbedtls/ecp256.c index ebbe25e17..2f5d93bd7 100644 --- a/third_party/mbedtls/ecp256.c +++ b/third_party/mbedtls/ecp256.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/log/check.h" #include "libc/nexgen32e/x86feature.h" #include "libc/runtime/gc.internal.h" @@ -26,6 +27,7 @@ #include "third_party/mbedtls/error.h" #include "third_party/mbedtls/math.h" #include "third_party/mbedtls/profile.h" +#include "third_party/mbedtls/select.h" /* clang-format off */ static bool @@ -53,17 +55,23 @@ static int mbedtls_p256_cmp( const uint64_t a[5], const uint64_t b[5] ) { - if ( (int64_t)a[4] < (int64_t)b[4] ) return -1; - if ( (int64_t)a[4] > (int64_t)b[4] ) return +1; - if ( a[3] < b[3] ) return -1; - if ( a[3] > b[3] ) return +1; - if ( a[2] < b[2] ) return -1; - if ( a[2] > b[2] ) return +1; - if ( a[1] < b[1] ) return -1; - if ( a[1] > b[1] ) return +1; - if ( a[0] < b[0] ) return -1; - if ( a[0] > b[0] ) return +1; - return 0; + int i, x, y, done = 0; + // return -1 if a[4] < b[4] + x = -((int64_t)a[4] < (int64_t)b[4]); + done = x; + // return +1 if a[4] > b[4] + y = (int64_t)a[4] > (int64_t)b[4]; + x = Select(x, y, done); + done |= -y; + for (i = 4; i--;) { + y = -(a[i] < b[i]); + x = Select(x, y, done); + done |= y; + y = a[i] > b[i]; + x = Select(x, y, done); + done |= -y; + } + return x; } static void diff --git a/third_party/mbedtls/ecp384.c b/third_party/mbedtls/ecp384.c index 0f46bbef3..8b6a6dd94 100644 --- a/third_party/mbedtls/ecp384.c +++ b/third_party/mbedtls/ecp384.c @@ -28,6 +28,7 @@ #include "third_party/mbedtls/error.h" #include "third_party/mbedtls/math.h" #include "third_party/mbedtls/profile.h" +#include "third_party/mbedtls/select.h" /* clang-format off */ static bool @@ -59,21 +60,23 @@ static int mbedtls_p384_cmp( const uint64_t a[7], const uint64_t b[7] ) { - if( (int64_t)a[6] < (int64_t)b[6] ) return( -1 ); - if( (int64_t)a[6] > (int64_t)b[6] ) return( +1 ); - if( a[5] < b[5] ) return( -1 ); - if( a[5] > b[5] ) return( +1 ); - if( a[4] < b[4] ) return( -1 ); - if( a[4] > b[4] ) return( +1 ); - if( a[3] < b[3] ) return( -1 ); - if( a[3] > b[3] ) return( +1 ); - if( a[2] < b[2] ) return( -1 ); - if( a[2] > b[2] ) return( +1 ); - if( a[1] < b[1] ) return( -1 ); - if( a[1] > b[1] ) return( +1 ); - if( a[0] < b[0] ) return( -1 ); - if( a[0] > b[0] ) return( +1 ); - return( 0 ); + int i, x, y, done = 0; + // return -1 if a[6] < b[6] + x = -((int64_t)a[6] < (int64_t)b[6]); + done = x; + // return +1 if a[6] > b[6] + y = (int64_t)a[6] > (int64_t)b[6]; + x = Select(x, y, done); + done |= -y; + for (i = 6; i--;) { + y = -(a[i] < b[i]); + x = Select(x, y, done); + done |= y; + y = a[i] > b[i]; + x = Select(x, y, done); + done |= -y; + } + return x; } static inline void diff --git a/third_party/mbedtls/ssl.h b/third_party/mbedtls/ssl.h index 6676e637d..8bc35e19d 100644 --- a/third_party/mbedtls/ssl.h +++ b/third_party/mbedtls/ssl.h @@ -12,20 +12,6 @@ COSMOPOLITAN_C_START_ /* clang-format off */ -#define MBEDTLS_ERR_NET_SOCKET_FAILED -0x0042 /*< Failed to open a socket. */ -#define MBEDTLS_ERR_NET_CONNECT_FAILED -0x0044 /*< The connection to the given server / port failed. */ -#define MBEDTLS_ERR_NET_BIND_FAILED -0x0046 /*< Binding of the socket failed. */ -#define MBEDTLS_ERR_NET_LISTEN_FAILED -0x0048 /*< Could not listen on the socket. */ -#define MBEDTLS_ERR_NET_ACCEPT_FAILED -0x004A /*< Could not accept the incoming connection. */ -#define MBEDTLS_ERR_NET_RECV_FAILED -0x004C /*< Reading information from the socket failed. */ -#define MBEDTLS_ERR_NET_SEND_FAILED -0x004E /*< Sending information through the socket failed. */ -#define MBEDTLS_ERR_NET_CONN_RESET -0x0050 /*< Connection was reset by peer. */ -#define MBEDTLS_ERR_NET_UNKNOWN_HOST -0x0052 /*< Failed to get an IP address for the given hostname. */ -#define MBEDTLS_ERR_NET_BUFFER_TOO_SMALL -0x0043 /*< Buffer is too small to hold the data. */ -#define MBEDTLS_ERR_NET_INVALID_CONTEXT -0x0045 /*< The context is invalid, eg because it was free()ed. */ -#define MBEDTLS_ERR_NET_POLL_FAILED -0x0047 /*< Polling the net context failed. */ -#define MBEDTLS_ERR_NET_BAD_INPUT_DATA -0x0049 /*< Input invalid. */ - /* * SSL Error codes */ diff --git a/third_party/mbedtls/ssl_ciphersuites.c b/third_party/mbedtls/ssl_ciphersuites.c index 32d78b7c4..82e71b1e8 100644 --- a/third_party/mbedtls/ssl_ciphersuites.c +++ b/third_party/mbedtls/ssl_ciphersuites.c @@ -15,6 +15,7 @@ │ See the License for the specific language governing permissions and │ │ limitations under the License. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/nexgen32e/x86feature.h" #include "third_party/mbedtls/cipher.h" #include "third_party/mbedtls/common.h" #include "third_party/mbedtls/platform.h" @@ -44,10 +45,6 @@ asm(".include \"libc/disclaimer.inc\""); #if defined(MBEDTLS_SSL_TLS_C) const uint16_t ciphersuite_preference[] = { -#if defined(MBEDTLS_SSL_CIPHERSUITES) - MBEDTLS_SSL_CIPHERSUITES, -#else - #ifdef MBEDTLS_KEY_EXCHANGE_SOME_PFS_ENABLED MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, @@ -175,7 +172,141 @@ const uint16_t ciphersuite_preference[] = MBEDTLS_TLS_PSK_WITH_NULL_SHA, #endif -#endif /* MBEDTLS_SSL_CIPHERSUITES */ + 0 +}; + +// if we don't have aes-ni then chacha will do a +// better job guarding against timing attacks +const uint16_t ciphersuite_preference_nehalem[] = +{ + +#ifdef MBEDTLS_KEY_EXCHANGE_SOME_PFS_ENABLED + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +#endif + +#ifdef MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED + MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256, +#endif + +#ifdef MBEDTLS_KEY_EXCHANGE_SOME_PFS_ENABLED + MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED + MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, +#endif + +#ifdef MBEDTLS_KEY_EXCHANGE_SOME_PFS_ENABLED + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, +#endif + +#ifdef MBEDTLS_KEY_EXCHANGE_SOME_NON_PFS_ENABLED + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED + MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, +#endif + +#ifdef MBEDTLS_DES_C + MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, // e.g. IE 8 XP + MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef MBEDTLS_ENABLE_WEAK_CIPHERSUITES + MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA, +#endif + +#ifdef MBEDTLS_CIPHER_NULL_CIPHER + MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_WITH_NULL_SHA256, + MBEDTLS_TLS_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_WITH_NULL_MD5, + MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_PSK_WITH_NULL_SHA, +#endif + 0 }; @@ -1338,12 +1469,6 @@ static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = 0, 0, 0, 0, 0 } }; -#if defined(MBEDTLS_SSL_CIPHERSUITES) -const uint16_t *mbedtls_ssl_list_ciphersuites( void ) -{ - return( ciphersuite_preference ); -} -#else #define MAX_CIPHERSUITES sizeof( ciphersuite_definitions ) / \ sizeof( ciphersuite_definitions[0] ) static uint16_t supported_ciphersuites[MAX_CIPHERSUITES]; @@ -1375,7 +1500,12 @@ const uint16_t *mbedtls_ssl_list_ciphersuites( void ) const uint16_t *p; uint16_t *q; - for( p = ciphersuite_preference, q = supported_ciphersuites; + if( X86_HAVE( AES ) ) + p = ciphersuite_preference; + else + p = ciphersuite_preference_nehalem; + + for( q = supported_ciphersuites; *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1; p++ ) { @@ -1393,7 +1523,6 @@ const uint16_t *mbedtls_ssl_list_ciphersuites( void ) return( supported_ciphersuites ); } -#endif /* MBEDTLS_SSL_CIPHERSUITES */ const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( const char *ciphersuite_name ) diff --git a/third_party/mbedtls/ssl_tls.c b/third_party/mbedtls/ssl_tls.c index 78e8edd0e..0fa09b0f6 100644 --- a/third_party/mbedtls/ssl_tls.c +++ b/third_party/mbedtls/ssl_tls.c @@ -7605,6 +7605,7 @@ static uint16_t ssl_preset_suiteb_ciphersuites[] = { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, 0 }; diff --git a/third_party/mbedtls/test/test.mk b/third_party/mbedtls/test/test.mk index 29130433e..95df2b1b1 100644 --- a/third_party/mbedtls/test/test.mk +++ b/third_party/mbedtls/test/test.mk @@ -130,7 +130,7 @@ o/$(MODE)/third_party/mbedtls/test/%.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/%.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/%.com: o/$(MODE)/third_party/mbedtls/test/%.com.dbg @@ -165,7 +165,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.cbc.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.cbc.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_aes.cfb.com: o/$(MODE)/third_party/mbedtls/test/test_suite_aes.cfb.com.dbg @@ -176,7 +176,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.cfb.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.cfb.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_aes.ecb.com: o/$(MODE)/third_party/mbedtls/test/test_suite_aes.ecb.com.dbg @@ -187,7 +187,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.ecb.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.ecb.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_aes.ofb.com: o/$(MODE)/third_party/mbedtls/test/test_suite_aes.ofb.com.dbg @@ -198,7 +198,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.ofb.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.ofb.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_aes.rest.com: o/$(MODE)/third_party/mbedtls/test/test_suite_aes.rest.com.dbg @@ -209,7 +209,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.rest.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.rest.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_aes.xts.com: o/$(MODE)/third_party/mbedtls/test/test_suite_aes.xts.com.dbg @@ -220,7 +220,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.xts.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_aes.xts.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_asn1parse.com: o/$(MODE)/third_party/mbedtls/test/test_suite_asn1parse.com.dbg @@ -231,7 +231,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_asn1parse.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_asn1parse.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_asn1write.com: o/$(MODE)/third_party/mbedtls/test/test_suite_asn1write.com.dbg @@ -242,7 +242,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_asn1write.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_asn1write.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_base64.com: o/$(MODE)/third_party/mbedtls/test/test_suite_base64.com.dbg @@ -253,7 +253,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_base64.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_base64.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_blowfish.com: o/$(MODE)/third_party/mbedtls/test/test_suite_blowfish.com.dbg @@ -264,7 +264,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_blowfish.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_blowfish.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_chacha20.com: o/$(MODE)/third_party/mbedtls/test/test_suite_chacha20.com.dbg @@ -275,7 +275,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_chacha20.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_chacha20.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_chachapoly.com: o/$(MODE)/third_party/mbedtls/test/test_suite_chachapoly.com.dbg @@ -286,7 +286,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_chachapoly.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_chachapoly.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.aes.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.aes.com.dbg @@ -297,7 +297,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.aes.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.aes.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.blowfish.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.blowfish.com.dbg @@ -308,7 +308,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.blowfish.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.blowfish.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.ccm.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.ccm.com.dbg @@ -319,7 +319,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.ccm.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.ccm.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.chacha20.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.chacha20.com.dbg @@ -330,7 +330,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.chacha20.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.chacha20.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.chachapoly.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.chachapoly.com.dbg @@ -341,7 +341,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.chachapoly.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.chachapoly.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.des.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.des.com.dbg @@ -352,7 +352,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.des.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.des.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.gcm.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.gcm.com.dbg @@ -363,7 +363,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.gcm.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.gcm.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.misc.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.misc.com.dbg @@ -374,7 +374,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.misc.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.misc.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.nist_kw.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.nist_kw.com.dbg @@ -385,7 +385,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.nist_kw.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.nist_kw.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.null.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.null.com.dbg @@ -396,7 +396,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.null.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.null.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.padding.com: o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.padding.com.dbg @@ -407,7 +407,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.padding.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_cipher.padding.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com: o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com.dbg @@ -418,7 +418,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_ctr_drbg.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_des.com: o/$(MODE)/third_party/mbedtls/test/test_suite_des.com.dbg @@ -429,7 +429,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_des.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_des.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_dhm.com: o/$(MODE)/third_party/mbedtls/test/test_suite_dhm.com.dbg @@ -442,7 +442,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_dhm.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/dhparams.pem.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_ecdh.com: o/$(MODE)/third_party/mbedtls/test/test_suite_ecdh.com.dbg @@ -453,7 +453,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_ecdh.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_ecdh.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_ecdsa.com: o/$(MODE)/third_party/mbedtls/test/test_suite_ecdsa.com.dbg @@ -464,7 +464,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_ecdsa.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_ecdsa.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_ecp.com: o/$(MODE)/third_party/mbedtls/test/test_suite_ecp.com.dbg @@ -475,7 +475,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_ecp.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_ecp.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_entropy.com: o/$(MODE)/third_party/mbedtls/test/test_suite_entropy.com.dbg @@ -486,7 +486,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_entropy.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_entropy.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_error.com: o/$(MODE)/third_party/mbedtls/test/test_suite_error.com.dbg @@ -497,7 +497,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_error.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_error.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes128_de.com: o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes128_de.com.dbg @@ -508,7 +508,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes128_de.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes128_de.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes128_en.com: o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes128_en.com.dbg @@ -519,7 +519,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes128_en.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes128_en.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes192_de.com: o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes192_de.com.dbg @@ -530,7 +530,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes192_de.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes192_de.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes192_en.com: o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes192_en.com.dbg @@ -541,7 +541,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes192_en.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes192_en.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes256_de.com: o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes256_de.com.dbg @@ -552,7 +552,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes256_de.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes256_de.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes256_en.com: o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes256_en.com.dbg @@ -563,7 +563,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes256_en.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.aes256_en.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.misc.com: o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.misc.com.dbg @@ -574,7 +574,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.misc.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_gcm.misc.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_hkdf.com: o/$(MODE)/third_party/mbedtls/test/test_suite_hkdf.com.dbg @@ -585,7 +585,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_hkdf.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_hkdf.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com: o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com.dbg @@ -596,7 +596,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.misc.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.no_reseed.com: o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.no_reseed.com.dbg @@ -607,7 +607,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.no_reseed.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.no_reseed.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.nopr.com: o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.nopr.com.dbg @@ -618,7 +618,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.nopr.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.nopr.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.pr.com: o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.pr.com.dbg @@ -629,7 +629,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.pr.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_hmac_drbg.pr.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_md.com: o/$(MODE)/third_party/mbedtls/test/test_suite_md.com.dbg @@ -645,7 +645,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_md.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/hash_file_5.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_mdx.com: o/$(MODE)/third_party/mbedtls/test/test_suite_mdx.com.dbg @@ -656,7 +656,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_mdx.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_mdx.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_memory_buffer_alloc.com: o/$(MODE)/third_party/mbedtls/test/test_suite_memory_buffer_alloc.com.dbg @@ -667,7 +667,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_memory_buffer_alloc.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_memory_buffer_alloc.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com: o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com.dbg @@ -683,7 +683,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_mpi.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/mpi_write.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_net.com: o/$(MODE)/third_party/mbedtls/test/test_suite_net.com.dbg @@ -694,7 +694,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_net.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_net.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_nist_kw.com: o/$(MODE)/third_party/mbedtls/test/test_suite_nist_kw.com.dbg @@ -705,7 +705,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_nist_kw.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_nist_kw.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_oid.com: o/$(MODE)/third_party/mbedtls/test/test_suite_oid.com.dbg @@ -716,7 +716,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_oid.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_oid.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_pem.com: o/$(MODE)/third_party/mbedtls/test/test_suite_pem.com.dbg @@ -727,7 +727,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_pem.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_pem.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_pk.com: o/$(MODE)/third_party/mbedtls/test/test_suite_pk.com.dbg @@ -744,7 +744,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_pk.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/server5.key.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs1_v15.com: o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs1_v15.com.dbg @@ -755,7 +755,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs1_v15.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs1_v15.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs1_v21.com: o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs1_v21.com.dbg @@ -766,7 +766,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs1_v21.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs1_v21.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs5.com: o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs5.com.dbg @@ -777,7 +777,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs5.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_pkcs5.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_pkparse.com: o/$(MODE)/third_party/mbedtls/test/test_suite_pkparse.com.dbg @@ -917,7 +917,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_pkparse.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/test-ca.key.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_pkwrite.com: o/$(MODE)/third_party/mbedtls/test/test_suite_pkwrite.com.dbg @@ -940,7 +940,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_pkwrite.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/server1.pubkey.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_poly1305.com: o/$(MODE)/third_party/mbedtls/test/test_suite_poly1305.com.dbg @@ -951,7 +951,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_poly1305.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_poly1305.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_random.com: o/$(MODE)/third_party/mbedtls/test/test_suite_random.com.dbg @@ -962,7 +962,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_random.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_random.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_rsa.com: o/$(MODE)/third_party/mbedtls/test/test_suite_rsa.com.dbg @@ -973,7 +973,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_rsa.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_rsa.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_shax.com: o/$(MODE)/third_party/mbedtls/test/test_suite_shax.com.dbg @@ -984,7 +984,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_shax.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_shax.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_ssl.com: o/$(MODE)/third_party/mbedtls/test/test_suite_ssl.com.dbg @@ -996,7 +996,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_ssl.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/server5.crt.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_timing.com: o/$(MODE)/third_party/mbedtls/test/test_suite_timing.com.dbg @@ -1007,7 +1007,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_timing.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_timing.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_version.com: o/$(MODE)/third_party/mbedtls/test/test_suite_version.com.dbg @@ -1018,7 +1018,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_version.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test_suite_version.datax.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_x509parse.com: o/$(MODE)/third_party/mbedtls/test/test_suite_x509parse.com.dbg @@ -1303,7 +1303,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_x509parse.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/test-int-ca3.crt.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_x509write.com: o/$(MODE)/third_party/mbedtls/test/test_suite_x509write.com.dbg @@ -1339,7 +1339,7 @@ o/$(MODE)/third_party/mbedtls/test/test_suite_x509write.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/data/test-ca.key.zip.o \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/everest_test.com: o/$(MODE)/third_party/mbedtls/test/everest_test.com.dbg @@ -1350,7 +1350,7 @@ o/$(MODE)/third_party/mbedtls/test/everest_test.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/secp384r1_test.com: o/$(MODE)/third_party/mbedtls/test/secp384r1_test.com.dbg @@ -1360,7 +1360,7 @@ o/$(MODE)/third_party/mbedtls/test/secp384r1_test.com.dbg: \ o/$(MODE)/third_party/mbedtls/test/test.pkg \ $(LIBC_TESTMAIN) \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/mbedtls/test/test_suite_asn1parse.com.runs: QUOTA = -M512m diff --git a/third_party/python/Include/ceval.h b/third_party/python/Include/ceval.h index 0822e0c78..47eaf797b 100644 --- a/third_party/python/Include/ceval.h +++ b/third_party/python/Include/ceval.h @@ -119,7 +119,7 @@ int _Py_CheckRecursiveCall(const char *); rc = _Py_CheckRecursiveCall(where); \ } else { \ rsp = (intptr_t)__builtin_frame_address(0); \ - bot = GetStackAddr(32768); \ + bot = (intptr_t)GetStackAddr(32768); \ if (UNLIKELY(rsp < bot)) { \ PyErr_Format(PyExc_MemoryError, "Stack overflow%s", where); \ rc = -1; \ diff --git a/third_party/python/Lib/os.py b/third_party/python/Lib/os.py index 76f62113b..df52811da 100644 --- a/third_party/python/Lib/os.py +++ b/third_party/python/Lib/os.py @@ -42,6 +42,7 @@ def _get_exports_list(module): name = 'posix' linesep = '\n' +realname = "nt" if cosmo.kernel == "nt" else "posix" from posix import * from posix import _exit __all__.append('_exit') diff --git a/third_party/python/Lib/site.py b/third_party/python/Lib/site.py index 40b0c865a..a58ae18da 100644 --- a/third_party/python/Lib/site.py +++ b/third_party/python/Lib/site.py @@ -240,7 +240,7 @@ def _getuserbase(): def joinuser(*args): return os.path.expanduser(os.path.join(*args)) - if os.name == "nt": + if os.realname == "nt": base = os.environ.get("APPDATA") or "~" if env_base: return env_base @@ -298,7 +298,7 @@ def getusersitepackages(): "posix_user":'{userbase}/lib/python3.6/site-packages', "nt_user": "{userbase}/Python36/site-packages", } - USER_SITE = purelib_map.get('%s_user' % os.name).format(userbase=user_base) + USER_SITE = purelib_map.get('%s_user' % os.realname).format(userbase=user_base) return USER_SITE def addusersitepackages(known_paths): diff --git a/third_party/python/Lib/test/test_coroutines.py b/third_party/python/Lib/test/test_coroutines.py index 291af248e..5bc5a1d80 100644 --- a/third_party/python/Lib/test/test_coroutines.py +++ b/third_party/python/Lib/test/test_coroutines.py @@ -1199,7 +1199,10 @@ class CoroutineTest(unittest.TestCase): with self.assertRaisesRegex(AttributeError, '__aexit__'): run_async(foo()) - @unittest.skipIf("tiny" in cosmo.MODE, "TODO: figure out error") + # TODO(jart,ahgamut): Figure out this error. + @unittest.skipIf(cosmo.MODE in ('tiny', 'rel'), + "No docstrings in MODE=tiny/rel") + @unittest.skipIf("tiny" in cosmo.MODE, "") def test_with_5(self): # While this test doesn't make a lot of sense, # it's a regression test for an early bug with opcodes diff --git a/third_party/python/Lib/test/test_doctest.py b/third_party/python/Lib/test/test_doctest.py index 6c870f0b9..d20718c4b 100644 --- a/third_party/python/Lib/test/test_doctest.py +++ b/third_party/python/Lib/test/test_doctest.py @@ -2921,7 +2921,7 @@ Invalid file name: >>> print(normalize(err)) # doctest: +ELLIPSIS Traceback (most recent call last): ... - FileNotFoundError: [Errno 2] ENOENT/2/No such file or directory: 'nosuchfile' + FileNotFoundError: [Errno 2] ENOENT... Invalid doctest option: diff --git a/third_party/python/Lib/test/test_module.py b/third_party/python/Lib/test/test_module.py index 2fbe9f1ce..81dccd2e8 100644 --- a/third_party/python/Lib/test/test_module.py +++ b/third_party/python/Lib/test/test_module.py @@ -29,7 +29,7 @@ class ModuleTests(unittest.TestCase): self.fail("__name__ = %s" % repr(s)) except AttributeError: pass - if cosmo.MODE != 'tiny': + if 'tiny' not in cosmo.MODE: self.assertEqual(foo.__doc__, ModuleType.__doc__) def test_uninitialized_missing_getattr(self): diff --git a/third_party/python/Lib/test/test_signal.py b/third_party/python/Lib/test/test_signal.py index 7c2db9890..37d10e56b 100644 --- a/third_party/python/Lib/test/test_signal.py +++ b/third_party/python/Lib/test/test_signal.py @@ -488,7 +488,6 @@ class SiginterruptTest(unittest.TestCase): try: # wait until the child process is loaded and has started first_line = process.stdout.readline() - stdout, stderr = process.communicate(timeout=5.0) except subprocess.TimeoutExpired: process.kill() @@ -515,12 +514,13 @@ class SiginterruptTest(unittest.TestCase): interrupted = self.readpipe_interrupted(True) self.assertTrue(interrupted) - def test_siginterrupt_off(self): - # If a signal handler is installed and siginterrupt is called with - # a false value for the second argument, when that signal arrives, it - # does not interrupt a syscall that's in progress. - interrupted = self.readpipe_interrupted(False) - self.assertFalse(interrupted) + # [jart]: lool a test that takes 5 seconds by design + # def test_siginterrupt_off(self): + # # If a signal handler is installed and siginterrupt is called with + # # a false value for the second argument, when that signal arrives, it + # # does not interrupt a syscall that's in progress. + # interrupted = self.readpipe_interrupted(False) + # self.assertFalse(interrupted) @unittest.skipIf(sys.platform == "win32", "Not valid on Windows") diff --git a/third_party/python/Modules/posixmodule.c b/third_party/python/Modules/posixmodule.c index 2bb79f0cd..e352fd3cb 100644 --- a/third_party/python/Modules/posixmodule.c +++ b/third_party/python/Modules/posixmodule.c @@ -14,6 +14,7 @@ #include "libc/calls/struct/dirent.h" #include "libc/calls/struct/stat.macros.h" #include "libc/calls/struct/winsize.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/termios.h" #include "libc/calls/weirdtypes.h" #include "libc/dce.h" @@ -29,6 +30,7 @@ #include "libc/runtime/dlfcn.h" #include "libc/runtime/gc.internal.h" #include "libc/runtime/sysconf.h" +#include "libc/sock/sendfile.internal.h" #include "libc/sock/sock.h" #include "libc/stdio/stdio.h" #include "libc/sysv/consts/at.h" diff --git a/third_party/python/Modules/socketmodule.c b/third_party/python/Modules/socketmodule.c index 81bef83d5..4f5234fa1 100644 --- a/third_party/python/Modules/socketmodule.c +++ b/third_party/python/Modules/socketmodule.c @@ -12,6 +12,7 @@ #include "libc/dns/ent.h" #include "libc/errno.h" #include "libc/nt/enum/version.h" +#include "libc/nt/version.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/sysv/consts/af.h" @@ -7146,9 +7147,9 @@ PyInit__socket(void) if (TCP_USER_TIMEOUT) PyModule_AddIntMacro(m, TCP_USER_TIMEOUT); if (TCP_SAVE_SYN) PyModule_AddIntMacro(m, TCP_SAVE_SYN); if (TCP_SAVED_SYN) PyModule_AddIntMacro(m, TCP_SAVED_SYN); - if (TCP_KEEPCNT && (!IsWindows() || NtGetVersion() >= kNtVersionWindows10)) + if (TCP_KEEPCNT && (!IsWindows() || IsAtLeastWindows10())) PyModule_AddIntMacro(m, TCP_KEEPCNT); - if (TCP_FASTOPEN && (!IsWindows() || NtGetVersion() >= kNtVersionWindows10)) + if (TCP_FASTOPEN && (!IsWindows() || IsAtLeastWindows10())) PyModule_AddIntMacro(m, TCP_FASTOPEN); if (TCP_FASTOPEN_CONNECT) PyModule_AddIntMacro(m, TCP_FASTOPEN_CONNECT); diff --git a/third_party/python/Objects/obmalloc.c b/third_party/python/Objects/obmalloc.c index fb5515732..93ec3d515 100644 --- a/third_party/python/Objects/obmalloc.c +++ b/third_party/python/Objects/obmalloc.c @@ -1984,8 +1984,8 @@ _PyMem_DebugRawAlloc(int use_calloc, void *ctx, size_t nbytes) _PyMem_DebugCheckAddress(api->api_id, p+2*SST); if (IsAsan()) { - __asan_poison((uintptr_t)(p + SST + 1), SST-1, kAsanHeapUnderrun); - __asan_poison((uintptr_t)tail, SST, kAsanHeapOverrun); + __asan_poison((p + SST + 1), SST-1, kAsanHeapUnderrun); + __asan_poison(tail, SST, kAsanHeapOverrun); } return p + 2*SST; @@ -2041,7 +2041,7 @@ _PyMem_DebugRawFree(void *ctx, void *p) nbytes += 4*SST; if (nbytes > 0) { if (IsAsan()) { - __asan_unpoison((uintptr_t)q, nbytes); + __asan_unpoison(q, nbytes); } memset(q, DEADBYTE, nbytes); } @@ -2080,12 +2080,12 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes) tail = q + nbytes; w = 0x0101010101010101ull * FORBIDDENBYTE; WRITE64LE(tail, w); - if (IsAsan()) __asan_poison((uintptr_t)tail, SST, kAsanHeapOverrun); + if (IsAsan()) __asan_poison(tail, SST, kAsanHeapOverrun); write_size_t(tail + SST, serialno); if (nbytes > original_nbytes) { /* growing: mark new extra memory clean */ if (IsAsan()) { - __asan_unpoison((uintptr_t)(q + original_nbytes), + __asan_unpoison((q + original_nbytes), nbytes - original_nbytes); } memset(q + original_nbytes, CLEANBYTE, diff --git a/third_party/python/Python/cosmomodule.c b/third_party/python/Python/cosmomodule.c index 71f795805..b6ea626c5 100644 --- a/third_party/python/Python/cosmomodule.c +++ b/third_party/python/Python/cosmomodule.c @@ -80,7 +80,7 @@ polyfilled yet."); static PyObject * cosmo_syscount(PyObject *self, PyObject *noargs) { - return PyLong_FromSize_t(g_syscount); + return PyLong_FromSize_t(__syscount); } PyDoc_STRVAR(rdtsc_doc, @@ -215,13 +215,13 @@ static int FtracerObject_init(PyObject* self, PyObject *args, PyObject *kwargs) static PyObject* FtracerObject_enter(PyObject *self, PyObject *Py_UNUSED(ignored)) { - ++g_ftrace; + ++__ftrace; return self; } static PyObject* FtracerObject_exit(PyObject *self, PyObject *args) { - --g_ftrace; + --__ftrace; return self; } diff --git a/third_party/python/python.c b/third_party/python/python.c index cb3cf1aeb..feab2bbda 100644 --- a/third_party/python/python.c +++ b/third_party/python/python.c @@ -1,6 +1,13 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Python 3 │ +│ https://docs.python.org/3/license.html │ +╚─────────────────────────────────────────────────────────────────────────────*/ #include "third_party/python/Include/yoink.h" - -STATIC_YOINK("RunPythonModule"); +#include "third_party/python/runpythonmodule.h" +#include "tool/args/args.h" +// clang-format off PYTHON_YOINK("xed"); PYTHON_YOINK("xterm"); @@ -516,3 +523,10 @@ PYTHON_YOINK("asyncio.unix_events"); PYTHON_YOINK("asyncio.windows_events"); PYTHON_YOINK("asyncio.windows_utils"); #endif + +int +main(int argc, char **argv) +{ + LoadZipArgs(&argc, &argv); + return RunPythonModule(argc, argv); +} diff --git a/third_party/python/python.mk b/third_party/python/python.mk index 21ff5d215..a623b04a8 100644 --- a/third_party/python/python.mk +++ b/third_party/python/python.mk @@ -47,6 +47,7 @@ THIRD_PARTY_PYTHON_STAGE1_A_OBJS = \ $(THIRD_PARTY_PYTHON_STAGE1_A_SRCS:%.c=o/$(MODE)/%.o) THIRD_PARTY_PYTHON_HDRS = \ + third_party/python/runpythonmodule.h \ third_party/python/Include/ezprint.h \ third_party/python/Include/yoink.h \ third_party/python/Include/object.h \ @@ -509,7 +510,7 @@ THIRD_PARTY_PYTHON_STAGE2_A_DATA_OBJS = \ third_party/python/Lib/.zip.o THIRD_PARTY_PYTHON_STAGE2_A_SRCS = \ - third_party/python/repl.c \ + third_party/python/runpythonmodule.c \ third_party/python/launch.c \ third_party/python/Objects/fromfd.c \ third_party/python/Objects/unicodeobject-deadcode.c \ @@ -1152,6 +1153,7 @@ THIRD_PARTY_PYTHON_STAGE2_A_DIRECTDEPS = \ THIRD_PARTY_MBEDTLS \ THIRD_PARTY_SQLITE3 \ THIRD_PARTY_ZLIB \ + THIRD_PARTY_XED \ TOOL_ARGS THIRD_PARTY_PYTHON_STAGE2_A_DEPS = \ @@ -2085,11 +2087,13 @@ THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DIRECTDEPS = \ LIBC_STR \ LIBC_UNICODE \ LIBC_STDIO \ + LIBC_CALLS \ LIBC_RUNTIME \ THIRD_PARTY_PYTHON_STAGE1 \ THIRD_PARTY_PYTHON_STAGE2 \ THIRD_PARTY_PYTHON_PYTEST \ THIRD_PARTY_LINENOISE \ + THIRD_PARTY_XED \ TOOL_ARGS THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DEPS = \ @@ -2097,7 +2101,7 @@ THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DEPS = \ o/$(MODE)/third_party/python/pythontester.pkg: \ $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_OBJS) \ - o/$(MODE)/third_party/python/repl.o \ + o/$(MODE)/third_party/python/pythontester.o \ $(foreach x,$(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DIRECTDEPS),$($(x)_A).pkg) o/$(MODE)/third_party/python/pythontester.com.dbg: \ @@ -2105,1497 +2109,1497 @@ o/$(MODE)/third_party/python/pythontester.com.dbg: \ $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_DEPS) \ $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_OBJS) \ $(THIRD_PARTY_PYTHON_PYTEST_TODOS:%.py=o/$(MODE)/%.o) \ - o/$(MODE)/third_party/python/repl.o \ + o/$(MODE)/third_party/python/pythontester.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/python/Lib/test/test_grammar.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_grammar $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_set.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_set $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_genexps.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_genexps $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_sqlite.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_sqlite $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_bz2.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_bz2 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_zlib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_zlib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_opcodes.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_opcodes $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_marshal.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_marshal $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pow.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pow $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_binascii.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_binascii $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_binhex.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_binhex $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_capi.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_capi $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test__locale.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test__locale $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_binop.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_binop $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test___future__.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test___future__ $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test__opcode.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test__opcode $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_abc.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_abc $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_bytes.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_bytes $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_setcomps.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_setcomps $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_itertools.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_itertools $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_listcomps.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_listcomps $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_aifc.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_aifc $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_audioop.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_audioop $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_bool.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_bool $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_base64.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_base64 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_baseexception.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_baseexception $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_array.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_array $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_builtin.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_builtin $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_charmapcodec.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_charmapcodec $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecs.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecs $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codeop.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codeop $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_cgi.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_cgi $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_abstract_numbers.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_abstract_numbers $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_augassign.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_augassign $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_bigaddrspace.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_bigaddrspace $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_class.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_class $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_call.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_call $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_buffer.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_buffer $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_bufio.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_bufio $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_enum.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_enum $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_code.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_code $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_cmd.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_cmd $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pwd.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pwd $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_cmath.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_cmath $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_defaultdict.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_defaultdict $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_decorators.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_decorators $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_copy.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_copy $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_csv.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_csv $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_difflib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_difflib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_colorsys.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_colorsys $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_compare.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_compare $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_copyreg.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_copyreg $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_collections.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_collections $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_format.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_format $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_fractions.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_fractions $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_eof.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_eof $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_fnmatch.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_fnmatch $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_frame.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_frame $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dummy_threading.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dummy_threading $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dynamic.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dynamic $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dict.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dict $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_wsgiref.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_wsgiref $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_wave.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_wave $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_urlparse.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_urlparse $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_userdict.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_userdict $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_userlist.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_userlist $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_userstring.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_userstring $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_utf8source.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_utf8source $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_uu.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_uu $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test__encoded_words.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test__encoded_words $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test__header_value_parser.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test__header_value_parser $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_asian_codecs.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_asian_codecs $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_contentmanager.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_contentmanager $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_defect_handling.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_defect_handling $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_email.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_email $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_generator.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_generator $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_headerregistry.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_headerregistry $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_inversion.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_inversion $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_message.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_message $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_parser.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_parser $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_pickleable.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_pickleable $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_policy.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_policy $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_email/test_utils.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_email.test_utils $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_strtod.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_strtod $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_struct.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_struct $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_structmembers.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_structmembers $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_hash.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_hash $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_heapq.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_heapq $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_operator.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_operator $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_optparse.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_optparse $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_finalization.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_finalization $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_enumerate.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_enumerate $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_errno.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_errno $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_html.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_html $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_htmlparser.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_htmlparser $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_http_cookiejar.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_http_cookiejar $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_http_cookies.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_http_cookies $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_list.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_list $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_long.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_long $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_longexp.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_longexp $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_glob.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_glob $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_global.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_global $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_ipaddress.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_ipaddress $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_isinstance.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_isinstance $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_iter.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_iter $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_json/__main__.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_json $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_tarfile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_tarfile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_iterlen.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_iterlen $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_stat.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_stat $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_memoryio.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_memoryio $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_memoryview.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_memoryview $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_metaclass.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_metaclass $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_mimetypes.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_mimetypes $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_kdf.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_kdf $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_cosmo.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_cosmo $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_scratch.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_scratch $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_hashlib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_hashlib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_complex.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_complex $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_funcattrs.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_funcattrs $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_functools.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_functools $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_int.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_int $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_int_literal.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_int_literal $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_bisect.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_bisect $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pyexpat.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pyexpat $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_ioctl.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_ioctl $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_getopt.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_getopt $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_sort.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_sort $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_slice.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_slice $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_decimal.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_decimal $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_deque.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_deque $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_mmap.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_mmap $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_poll.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_poll $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_robotparser.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_robotparser $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_re.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_re $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_range.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_range $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_sax.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_sax $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_scope.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_scope $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_stringprep.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_stringprep $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_syntax.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_syntax $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unicodedata.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unicodedata $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unpack.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unpack $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unpack_ex.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unpack_ex $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_file.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_file $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_uuid.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_uuid $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_filecmp.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_filecmp $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_fileinput.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_fileinput $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_fileio.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_fileio $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_float.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_float $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pickle.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pickle $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pickletools.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pickletools $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_tuple.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_tuple $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_reprlib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_reprlib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_strftime.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_strftime $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_quopri.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_quopri $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_with.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_with $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_raise.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_raise $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_yield_from.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_yield_from $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_typechecks.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_typechecks $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_types.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_types $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_random.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_random $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_typing.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_typing $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unary.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unary $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_print.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_print $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pprint.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pprint $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_secrets.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_secrets $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_select.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_select $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_selectors.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_selectors $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_contains.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_contains $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_super.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_super $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unicode.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unicode $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unicode_file.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unicode_file $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unicode_identifiers.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unicode_identifiers $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unicode_file_functions.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unicode_file_functions $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_textwrap.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_textwrap $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pulldom.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pulldom $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_minidom.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_minidom $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_xml_dom_minicompat.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_xml_dom_minicompat $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_xml_etree_c.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_xml_etree_c $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_coroutines.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_coroutines $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_tempfile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_tempfile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_normalization.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_normalization $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_os.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_os $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_logging.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_logging $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_io.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_io $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_gzip.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_gzip $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_tracemalloc.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_tracemalloc $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_configparser.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_configparser $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_flufl.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_flufl $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_keyword.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_keyword $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_keywordonlyarg.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_keywordonlyarg $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_sys.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_sys $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_cgitb.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_cgitb $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_asyncgen.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_asyncgen $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_runpy.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_runpy $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_doctest.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_doctest $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_doctest2.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_doctest2 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_calendar.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_calendar $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_asynchat.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_asynchat $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_asdl_parser.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_asdl_parser $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_atexit.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_atexit $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dis.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dis $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_asyncore.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_asyncore $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_epoll.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_epoll $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_cmd_line.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_cmd_line $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_cmd_line_script.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_cmd_line_script $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_code_module.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_code_module $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codeccallbacks.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codeccallbacks $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecmaps_cn.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecmaps_cn $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecmaps_jp.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecmaps_jp $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecencodings_cn.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecencodings_cn $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecencodings_hk.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecencodings_hk $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecmaps_hk.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecmaps_hk $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecmaps_kr.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecmaps_kr $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecmaps_tw.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecmaps_tw $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecencodings_iso2022.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecencodings_iso2022 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecencodings_jp.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecencodings_jp $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecencodings_kr.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecencodings_kr $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_codecencodings_tw.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_codecencodings_tw $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_compile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_compile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_contextlib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_contextlib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_cprofile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_cprofile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_crashers.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_crashers $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_crypt.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_crypt $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_datetime.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_datetime $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_descrtut.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_descrtut $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_devpoll.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_devpoll $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dict_version.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dict_version $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dictcomps.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dictcomps $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dictviews.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dictviews $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dtrace.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dtrace $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_dynamicclassattribute.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_dynamicclassattribute $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_eintr.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_eintr $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_exception_hierarchy.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_exception_hierarchy $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_xmlrpc_net.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_xmlrpc_net $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_bigmem.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_bigmem $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_exception_variations.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_exception_variations $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_exceptions.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_exceptions $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_time.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_time $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_docxmlrpc.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_docxmlrpc $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_extcall.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_extcall $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_faulthandler.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_faulthandler $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_fcntl.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_fcntl $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_file_eintr.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_file_eintr $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_fork1.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_fork1 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_fstring.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_fstring $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_ftplib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_ftplib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_future.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_future $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_future3.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_future3 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_future4.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_future4 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_future5.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_future5 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_gc.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_gc $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_gdb.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_gdb $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_generator_stop.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_generator_stop $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_generators.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_generators $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_genericpath.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_genericpath $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_getargs2.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_getargs2 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_getpass.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_getpass $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_gettext.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_gettext $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_grp.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_grp $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_imaplib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_imaplib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_imghdr.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_imghdr $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_imp.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_imp $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_index.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_index $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_kqueue.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_kqueue $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_largefile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_largefile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_linecache.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_linecache $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_locale.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_locale $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_macpath.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_macpath $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_macurl2path.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_macurl2path $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_mailbox.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_mailbox $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_mailcap.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_mailcap $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_module.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_module $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_modulefinder.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_modulefinder $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_multibytecodec.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_multibytecodec $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_multiprocessing_fork.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_multiprocessing_fork $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_multiprocessing_forkserver.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_multiprocessing_forkserver $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_multiprocessing_main_handling.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_multiprocessing_main_handling $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_multiprocessing_spawn.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_multiprocessing_spawn $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_netrc.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_netrc $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_nis.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_nis $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_nntplib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_nntplib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_ntpath.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_ntpath $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_numeric_tower.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_numeric_tower $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_ossaudiodev.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_ossaudiodev $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_parser.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_parser $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pathlib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pathlib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pdb.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pdb $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_peepholer.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_peepholer $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pipes.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pipes $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pkgimport.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pkgimport $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_platform.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_platform $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_plistlib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_plistlib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_httplib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_httplib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_popen.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_popen $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_poplib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_poplib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_posix.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_posix $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_posixpath.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_posixpath $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_profile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_profile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_property.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_property $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pstats.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pstats $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pty.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pty $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_py_compile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_py_compile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pyclbr.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pyclbr $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_pydoc.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_pydoc $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_readline.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_readline $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_regrtest.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_regrtest $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_repl.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_repl $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_resource.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_resource $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_richcmp.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_richcmp $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_sched.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_sched $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_script_helper.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_script_helper $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_shlex.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_shlex $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_shutil.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_shutil $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_signal.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_signal $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_site.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_site $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_smtpd.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_smtpd $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_smtplib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_smtplib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_smtpnet.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_smtpnet $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_sndhdr.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_sndhdr $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_socket.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_socket $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_socketserver.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_socketserver $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_spwd.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_spwd $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_startfile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_startfile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_statistics.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_statistics $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_string.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_string $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_string_literals.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_string_literals $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_strptime.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_strptime $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_structseq.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_structseq $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_subclassinit.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_subclassinit $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_subprocess.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_subprocess $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_sunau.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_sunau $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_support.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_support $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_symbol.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_symbol $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_symtable.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_symtable $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_sys_setprofile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_sys_setprofile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_syslog.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_syslog $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_telnetlib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_telnetlib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_threadedtempfile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_threadedtempfile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_timeit.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_timeit $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_timeout.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_timeout $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_tokenize.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_tokenize $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_trace.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_trace $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_traceback.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_traceback $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_turtle.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_turtle $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_unittest.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_unittest $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_univnewlines.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_univnewlines $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_urllib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_urllib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_urllib2.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_urllib2 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_urllib2_localnet.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_urllib2_localnet $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_urllib2net.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_urllib2net $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_urllib_response.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_urllib_response $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_urllibnet.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_urllibnet $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_wait3.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_wait3 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_wait4.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_wait4 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_webbrowser.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_webbrowser $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_xdrlib.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_xdrlib $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_weakref.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_weakref $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_weakset.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_weakset $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_zipapp.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_zipapp $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_zipimport.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_zipimport $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_zipfile.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_zipfile $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_zipfile64.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_zipfile64 $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/mp_preload.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.mp_preload $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/bisect.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.bisect $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/signalinterproctester.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.signalinterproctester $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/pythoninfo.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.pythoninfo $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/datetimetester.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.datetimetester $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/outstanding_bugs.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.outstanding_bugs $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/sortperf.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.sortperf $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_openpty.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_openpty $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_queue.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_queue $(PYTESTARGS) o/$(MODE)/third_party/python/Lib/test/test_ordered_dict.py.runs: \ - o/$(MODE)/third_party/python/pythontester.com.dbg + o/$(MODE)/third_party/python/pythontester.com @$(COMPILE) -ACHECK -tT$@ $(PYHARNESSARGS) $< -m test.test_ordered_dict $(PYTESTARGS) ################################################################################ @@ -4187,21 +4191,21 @@ $(THIRD_PARTY_PYTHON_PYTEST_A_PYS_OBJS): PYFLAGS += -P.python -C3 $(THIRD_PARTY_PYTHON_PYTEST_A_DATA_OBJS): ZIPOBJ_FLAGS += -P.python -C3 o/$(MODE)/third_party/python/Python/ceval.o: QUOTA = -C64 -M1024m -o/$(MODE)/third_party/python/Objects/unicodeobject.o: QUOTA += -C64 -M1024m +o/$(MODE)/third_party/python/Objects/unicodeobject.o: QUOTA += -C64 -M1024m -L180 o/$(MODE)/third_party/python/Parser/asdl_c.o: PYFLAGS += -m $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS_OBJS): PYFLAGS += -t -P.python -C3 $(THIRD_PARTY_PYTHON_PYTEST_TODOS:%.py=o/$(MODE)/%.o): PYFLAGS += -t -P.python -C3 o/$(MODE)/third_party/python/Lib/test/pystone.o: PYFLAGS += -m -O2 -P.python -C4 -o/$(MODE)/third_party/python/Lib/test/test_long.py.runs: QUOTA = -C64 +o/$(MODE)/third_party/python/Lib/test/test_long.py.runs: QUOTA = -C64 -L180 o/$(MODE)/third_party/python/Lib/test/test_hash.py.runs: QUOTA = -C64 o/$(MODE)/third_party/python/Lib/test/test_exceptions.py.runs: QUOTA = -C64 o/$(MODE)/third_party/python/Lib/test/test_tuple.py.runs: QUOTA = -M512m -o/$(MODE)/third_party/python/Lib/test/test_decimal.py.runs: QUOTA = -M512m -C64 +o/$(MODE)/third_party/python/Lib/test/test_decimal.py.runs: QUOTA = -M512m -C64 -L300 o/$(MODE)/third_party/python/Lib/test/test_longexp.py.runs: QUOTA = -M1024m -o/$(MODE)/third_party/python/Lib/test/test_unicode.py.runs: QUOTA = -M1400m -o/$(MODE)/third_party/python/Lib/test/test_unicodedata.py.runs: QUOTA = -C64 +o/$(MODE)/third_party/python/Lib/test/test_unicode.py.runs: QUOTA = -M1400m -L300 +o/$(MODE)/third_party/python/Lib/test/test_unicodedata.py.runs: QUOTA = -C64 -L300 o/$(MODE)/third_party/python/Lib/test/test_logging.py.runs: QUOTA = -M512m o/$(MODE)/third_party/python/Lib/test/test_itertools.py.runs: QUOTA = -M1024m o/$(MODE)/third_party/python/Lib/test/test_tarfile.py.runs: QUOTA = -L120 -C64 @@ -4210,6 +4214,8 @@ o/$(MODE)/third_party/python/Lib/test/test_gzip.py.runs: QUOTA = -L120 o/$(MODE)/third_party/python/Lib/test/test_logging.py.runs: QUOTA = -M512m o/$(MODE)/third_party/python/Lib/test/test_resource.py.runs: QUOTA = -C1000000 o/$(MODE)/third_party/python/Lib/test/test_email/test_email.py.runs: QUOTA = -C32 -M1024m +o/$(MODE)/third_party/python/Lib/test/test_selectors.py.runs: QUOTA = -L180 +o/$(MODE)/third_party/python/Lib/test/test_tracemalloc.py.runs: QUOTA = -L300 THIRD_PARTY_PYTHON_LIBS = \ $(foreach x,$(THIRD_PARTY_PYTHON_ARTIFACTS),$($(x))) @@ -4252,6 +4258,7 @@ THIRD_PARTY_PYTHON_PYTHON_DIRECTDEPS = \ THIRD_PARTY_PYTHON_STAGE1 \ THIRD_PARTY_PYTHON_STAGE2 \ THIRD_PARTY_PYTHON_PYTEST \ + THIRD_PARTY_XED \ TOOL_ARGS o/$(MODE)/third_party/python/python.pkg: \ @@ -4298,6 +4305,7 @@ THIRD_PARTY_PYTHON_FREEZE_DIRECTDEPS = \ LIBC_UNICODE \ LIBC_X \ THIRD_PARTY_GETOPT \ + THIRD_PARTY_XED \ THIRD_PARTY_PYTHON_STAGE1 o/$(MODE)/third_party/python/freeze.pkg: \ diff --git a/third_party/python/pythontester.c b/third_party/python/pythontester.c new file mode 100644 index 000000000..45db63426 --- /dev/null +++ b/third_party/python/pythontester.c @@ -0,0 +1,19 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Python 3 │ +│ https://docs.python.org/3/license.html │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/runtime.h" +#include "third_party/python/Include/yoink.h" +#include "third_party/python/runpythonmodule.h" +#include "tool/args/args.h" +// clang-format off + +int +main(int argc, char **argv) +{ + LoadZipArgs(&argc, &argv); + __nosync = 0x5453455454534146; + return RunPythonModule(argc, argv); +} diff --git a/third_party/python/repl.c b/third_party/python/repl.c index cbb5d7f76..412790e79 100644 --- a/third_party/python/repl.c +++ b/third_party/python/repl.c @@ -4,347 +4,10 @@ │ Python 3 │ │ https://docs.python.org/3/license.html │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#define PY_SSIZE_T_CLEAN -#include "libc/bits/bits.h" -#include "libc/bits/safemacros.internal.h" -#include "libc/bits/weaken.h" -#include "libc/calls/calls.h" -#include "libc/dce.h" -#include "libc/errno.h" -#include "libc/log/check.h" -#include "libc/log/log.h" -#include "libc/mem/mem.h" -#include "libc/runtime/gc.internal.h" -#include "libc/runtime/runtime.h" -#include "libc/runtime/symbols.internal.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/fileno.h" -#include "libc/sysv/consts/sig.h" -#include "libc/unicode/locale.h" -#include "libc/x/x.h" -#include "third_party/linenoise/linenoise.h" -#include "third_party/python/Include/abstract.h" -#include "third_party/python/Include/ceval.h" -#include "third_party/python/Include/dictobject.h" -#include "third_party/python/Include/fileutils.h" -#include "third_party/python/Include/funcobject.h" -#include "third_party/python/Include/import.h" -#include "third_party/python/Include/listobject.h" -#include "third_party/python/Include/moduleobject.h" -#include "third_party/python/Include/object.h" -#include "third_party/python/Include/pydebug.h" -#include "third_party/python/Include/pyerrors.h" -#include "third_party/python/Include/pylifecycle.h" -#include "third_party/python/Include/pymem.h" -#include "third_party/python/Include/pyport.h" -#include "third_party/python/Include/pythonrun.h" -#include "third_party/python/Include/unicodeobject.h" #include "third_party/python/Include/yoink.h" +#include "third_party/python/runpythonmodule.h" #include "tool/args/args.h" -/* clang-format off */ - -STATIC_STACK_SIZE(0x100000); - -STATIC_YOINK("__die"); -STATIC_YOINK("zip_uri_support"); - -PYTHON_YOINK("cosmo"); -PYTHON_YOINK("_locale"); -PYTHON_YOINK("_bootlocale"); -PYTHON_YOINK("encodings.aliases"); -PYTHON_YOINK("encodings.latin_1"); -PYTHON_YOINK("encodings.utf_8"); - -extern char kLaunchPythonModuleName[]; /* optionally generated by pyobj.com */ -const struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules; -struct _inittab *PyImport_Inittab = _PyImport_Inittab; -static int g_gotint; - -static void -OnKeyboardInterrupt(int sig) -{ - g_gotint = sig; -} - -static void -AddCompletion(linenoiseCompletions *c, char *s) -{ - char **p = c->cvec; - size_t n = c->len + 1; - if ((p = realloc(p, n * sizeof(*p)))) { - p[n - 1] = s; - c->cvec = p; - c->len = n; - } -} - -static void -CompleteModule(const char *s, const char *p, linenoiseCompletions *c) -{ - const char *name; - struct _inittab *it; - Py_ssize_t plen, namelen; - PyObject *m, *f, *g, *i, *v, *n; - plen = strlen(p); - for (it = PyImport_Inittab; it->name; ++it) { - if (startswithi(it->name, p)) { - AddCompletion(c, xasprintf("%s%s", s, it->name + plen)); - } - } - if ((m = PyImport_ImportModule("pkgutil"))) { - if ((f = PyObject_GetAttrString(m, "iter_modules"))) { - if ((g = PyObject_CallFunctionObjArgs(f, 0))) { - if ((i = PyObject_GetIter(g))) { - while ((v = PyIter_Next(i))) { - if ((n = PyObject_GetAttrString(v, "name"))) { - if (((name = PyUnicode_AsUTF8AndSize(n, &namelen)) && - namelen >= plen && !memcasecmp(name, p, plen))) { - AddCompletion(c, xasprintf("%s%s", s, name + plen)); - } - Py_DECREF(n); - } - Py_DECREF(v); - } - Py_DECREF(i); - } - Py_DECREF(g); - } - Py_DECREF(f); - } - Py_DECREF(m); - } -} - -static void -CompleteDict(const char *b, const char *q, const char *p, - linenoiseCompletions *c, PyObject *o) -{ - const char *s; - PyObject *k, *v; - Py_ssize_t i, m; - for (i = 0; PyDict_Next(o, &i, &k, &v);) { - if ((v != Py_None && PyUnicode_Check(k) && - (s = PyUnicode_AsUTF8AndSize(k, &m)) && - m >= q - p && !memcasecmp(s, p, q - p))) { - AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); - } - } -} - -static void -CompleteDir(const char *b, const char *q, const char *p, - linenoiseCompletions *c, PyObject *o) -{ - Py_ssize_t m; - const char *s; - PyObject *d, *i, *k; - if ((d = PyObject_Dir(o))) { - if ((i = PyObject_GetIter(d))) { - while ((k = PyIter_Next(i))) { - if (((s = PyUnicode_AsUTF8AndSize(k, &m)) && - m >= q - p && !memcasecmp(s, p, q - p) && - !(q - p == 0 && m > 4 && - (s[0+0] == '_' && s[0+1] == '_' && - s[m-1] == '_' && s[m-2] == '_')))) { - AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); - } - Py_DECREF(k); - } - Py_DECREF(i); - } - Py_DECREF(d); - } -} - -static void -Complete(const char *p, linenoiseCompletions *c) -{ - PyObject *o, *t, *i; - const char *q, *s, *b; - if (startswith(p, "import ")) { - for (q = p + 7; *q; ++q) { - if (!isalnum(*q) && *q != '_') { - return; - } - } - CompleteModule(p, p + 7, c); - return; - } - for (b = p, p += strlen(p); p > b; --p) { - if (!isalnum(p[-1]) && p[-1] != '.' && p[-1] != '_') { - break; - } - } - o = PyModule_GetDict(PyImport_AddModule("__main__")); - if (!*(q = strchrnul(p, '.'))) { - CompleteDict(b, q, p, c, o); - CompleteDir(b, q, p, c, PyDict_GetItemString(o, "__builtins__")); - } else { - s = strndup(p, q - p); - if ((t = PyDict_GetItemString(o, s))) { - Py_INCREF(t); - } else { - o = PyDict_GetItemString(o, "__builtins__"); - if (PyObject_HasAttrString(o, s)) { - t = PyObject_GetAttrString(o, s); - } - } - while ((p = q + 1), (o = t)) { - if (*(q = strchrnul(p, '.'))) { - t = PyObject_GetAttrString(o, gc(strndup(p, q - p))); - Py_DECREF(o); - } else { - CompleteDir(b, q, p, c, o); - Py_DECREF(o); - break; - } - } - free(s); - } -} - -static void -TerminalCompletion(const char *p, linenoiseCompletions *c) -{ - Complete(p, c); - if (PyErr_Occurred()) { - PyErr_Clear(); - } -} - -static char * -TerminalHint(const char *p, const char **ansi1, const char **ansi2) -{ - char *h = 0; - linenoiseCompletions c = {0}; - TerminalCompletion(p, &c); - if (c.len == 1) h = strdup(c.cvec[0] + strlen(p)); - linenoiseFreeCompletions(&c); - return h; -} - -static char * -ReinterpretCommand(const char *line) -{ - size_t n; - n = strlen(line); - if (n && line[n - 1] == '?') { - return xstrcat("help(", gc(strndup(gc(line), n - 1)), ')'); - } else { - return line; - } -} - -static char * -TerminalReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) -{ - size_t n; - char *p, *q; - PyOS_sighandler_t saint; - saint = PyOS_setsig(SIGINT, OnKeyboardInterrupt); - p = linenoiseWithHistory(prompt, "python"); - PyOS_setsig(SIGINT, saint); - if (g_gotint) { - PyOS_setsig(SIGINT, saint); - g_gotint = 0; - q = 0; - } else if (p) { - p = ReinterpretCommand(p); - n = strlen(p); - q = PyMem_RawMalloc(n + 2); - strcpy(mempcpy(q, p, n), "\n"); - clearerr(sys_stdin); - } else if ((q = PyMem_RawMalloc(1))) { - *q = 0; - } - free(p); - return q; -} - -int -RunPythonModule(int argc, char **argv) -{ - char *launchargs[4]; - wchar_t **argv_copy; - /* We need a second copy, as Python might modify the first one. */ - wchar_t **argv_copy2; - int i, res; - char *oldloc; - - if (argc == 1 && weaken(kLaunchPythonModuleName)) { - launchargs[0] = argv[0]; - launchargs[1] = strdup("-m"); - launchargs[2] = strdup(kLaunchPythonModuleName); - launchargs[3] = 0; - argc = 3; - argv = launchargs; - } - - PyOS_ReadlineFunctionPointer = TerminalReadline; - linenoiseSetCompletionCallback(TerminalCompletion); - linenoiseSetHintsCallback(TerminalHint); - linenoiseSetFreeHintsCallback(free); - -#if IsModeDbg() - /* Force malloc() allocator to bootstrap Python */ - _PyMem_SetupAllocators("malloc"); -#endif - - argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); - argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); - if (!argv_copy || !argv_copy2) { - fprintf(stderr, "out of memory\n"); - return 1; - } - - /* 754 requires that FP exceptions run in "no stop" mode by default, - * and until C vendors implement C99's ways to control FP exceptions, - * Python requires non-stop mode. Alas, some platforms enable FP - * exceptions by default. Here we disable them. - */ -#ifdef __FreeBSD__ - fedisableexcept(FE_OVERFLOW); -#endif - - oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); - if (!oldloc) { - fprintf(stderr, "out of memory\n"); - return 1; - } - - setlocale(LC_ALL, ""); - for (i = 0; i < argc; i++) { - argv_copy[i] = Py_DecodeLocale(argv[i], NULL); - if (!argv_copy[i]) { - PyMem_RawFree(oldloc); - fprintf(stderr, "Fatal Python error: " - "unable to decode the command line argument #%i\n", - i + 1); - return 1; - } - argv_copy2[i] = argv_copy[i]; - } - argv_copy2[argc] = argv_copy[argc] = NULL; - - setlocale(LC_ALL, oldloc); - PyMem_RawFree(oldloc); - - res = Py_Main(argc, argv_copy); - -#if IsModeDbg() - /* Force again malloc() allocator to release memory blocks allocated - before Py_Main() */ - _PyMem_SetupAllocators("malloc"); -#endif - - for (i = 0; i < argc; i++) { - PyMem_RawFree(argv_copy2[i]); - } - PyMem_RawFree(argv_copy); - PyMem_RawFree(argv_copy2); - return res; -} +// clang-format off int main(int argc, char **argv) diff --git a/third_party/python/runpythonmodule.c b/third_party/python/runpythonmodule.c new file mode 100644 index 000000000..52f4e5f46 --- /dev/null +++ b/third_party/python/runpythonmodule.c @@ -0,0 +1,356 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Python 3 │ +│ https://docs.python.org/3/license.html │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#define PY_SSIZE_T_CLEAN +#include "libc/bits/bits.h" +#include "libc/bits/safemacros.internal.h" +#include "libc/bits/weaken.h" +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/sigbits.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/struct/sigset.h" +#include "libc/calls/ucontext.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/intrin/kprintf.h" +#include "libc/log/check.h" +#include "libc/log/log.h" +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/runtime/gc.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/symbols.internal.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/fileno.h" +#include "libc/sysv/consts/prot.h" +#include "libc/sysv/consts/sig.h" +#include "libc/time/time.h" +#include "libc/unicode/locale.h" +#include "libc/x/x.h" +#include "third_party/linenoise/linenoise.h" +#include "third_party/python/Include/abstract.h" +#include "third_party/python/Include/ceval.h" +#include "third_party/python/Include/dictobject.h" +#include "third_party/python/Include/fileutils.h" +#include "third_party/python/Include/funcobject.h" +#include "third_party/python/Include/import.h" +#include "third_party/python/Include/listobject.h" +#include "third_party/python/Include/moduleobject.h" +#include "third_party/python/Include/object.h" +#include "third_party/python/Include/pydebug.h" +#include "third_party/python/Include/pyerrors.h" +#include "third_party/python/Include/pylifecycle.h" +#include "third_party/python/Include/pymem.h" +#include "third_party/python/Include/pyport.h" +#include "third_party/python/Include/pythonrun.h" +#include "third_party/python/Include/unicodeobject.h" +#include "third_party/python/Include/yoink.h" +#include "third_party/xed/x86.h" +// clang-format off + +STATIC_STACK_SIZE(0x100000); + +STATIC_YOINK("__die"); +STATIC_YOINK("zip_uri_support"); + +PYTHON_YOINK("cosmo"); +PYTHON_YOINK("_locale"); +PYTHON_YOINK("_bootlocale"); +PYTHON_YOINK("encodings.aliases"); +PYTHON_YOINK("encodings.latin_1"); +PYTHON_YOINK("encodings.utf_8"); + +extern char kLaunchPythonModuleName[]; /* optionally generated by pyobj.com */ +const struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules; +struct _inittab *PyImport_Inittab = _PyImport_Inittab; +static int g_gotint; + +static void +OnKeyboardInterrupt(int sig) +{ + g_gotint = sig; +} + +static void +AddCompletion(linenoiseCompletions *c, char *s) +{ + char **p = c->cvec; + size_t n = c->len + 1; + if ((p = realloc(p, n * sizeof(*p)))) { + p[n - 1] = s; + c->cvec = p; + c->len = n; + } +} + +static void +CompleteModule(const char *s, const char *p, linenoiseCompletions *c) +{ + const char *name; + struct _inittab *it; + Py_ssize_t plen, namelen; + PyObject *m, *f, *g, *i, *v, *n; + plen = strlen(p); + for (it = PyImport_Inittab; it->name; ++it) { + if (startswithi(it->name, p)) { + AddCompletion(c, xasprintf("%s%s", s, it->name + plen)); + } + } + if ((m = PyImport_ImportModule("pkgutil"))) { + if ((f = PyObject_GetAttrString(m, "iter_modules"))) { + if ((g = PyObject_CallFunctionObjArgs(f, 0))) { + if ((i = PyObject_GetIter(g))) { + while ((v = PyIter_Next(i))) { + if ((n = PyObject_GetAttrString(v, "name"))) { + if (((name = PyUnicode_AsUTF8AndSize(n, &namelen)) && + namelen >= plen && !memcasecmp(name, p, plen))) { + AddCompletion(c, xasprintf("%s%s", s, name + plen)); + } + Py_DECREF(n); + } + Py_DECREF(v); + } + Py_DECREF(i); + } + Py_DECREF(g); + } + Py_DECREF(f); + } + Py_DECREF(m); + } +} + +static void +CompleteDict(const char *b, const char *q, const char *p, + linenoiseCompletions *c, PyObject *o) +{ + const char *s; + PyObject *k, *v; + Py_ssize_t i, m; + for (i = 0; PyDict_Next(o, &i, &k, &v);) { + if ((v != Py_None && PyUnicode_Check(k) && + (s = PyUnicode_AsUTF8AndSize(k, &m)) && + m >= q - p && !memcasecmp(s, p, q - p))) { + AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); + } + } +} + +static void +CompleteDir(const char *b, const char *q, const char *p, + linenoiseCompletions *c, PyObject *o) +{ + Py_ssize_t m; + const char *s; + PyObject *d, *i, *k; + if ((d = PyObject_Dir(o))) { + if ((i = PyObject_GetIter(d))) { + while ((k = PyIter_Next(i))) { + if (((s = PyUnicode_AsUTF8AndSize(k, &m)) && + m >= q - p && !memcasecmp(s, p, q - p) && + !(q - p == 0 && m > 4 && + (s[0+0] == '_' && s[0+1] == '_' && + s[m-1] == '_' && s[m-2] == '_')))) { + AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); + } + Py_DECREF(k); + } + Py_DECREF(i); + } + Py_DECREF(d); + } +} + +static void +Complete(const char *p, linenoiseCompletions *c) +{ + PyObject *o, *t, *i; + const char *q, *s, *b; + if (startswith(p, "import ")) { + for (q = p + 7; *q; ++q) { + if (!isalnum(*q) && *q != '_') { + return; + } + } + CompleteModule(p, p + 7, c); + return; + } + for (b = p, p += strlen(p); p > b; --p) { + if (!isalnum(p[-1]) && p[-1] != '.' && p[-1] != '_') { + break; + } + } + o = PyModule_GetDict(PyImport_AddModule("__main__")); + if (!*(q = strchrnul(p, '.'))) { + CompleteDict(b, q, p, c, o); + CompleteDir(b, q, p, c, PyDict_GetItemString(o, "__builtins__")); + } else { + s = strndup(p, q - p); + if ((t = PyDict_GetItemString(o, s))) { + Py_INCREF(t); + } else { + o = PyDict_GetItemString(o, "__builtins__"); + if (PyObject_HasAttrString(o, s)) { + t = PyObject_GetAttrString(o, s); + } + } + while ((p = q + 1), (o = t)) { + if (*(q = strchrnul(p, '.'))) { + t = PyObject_GetAttrString(o, gc(strndup(p, q - p))); + Py_DECREF(o); + } else { + CompleteDir(b, q, p, c, o); + Py_DECREF(o); + break; + } + } + free(s); + } +} + +static void +TerminalCompletion(const char *p, linenoiseCompletions *c) +{ + Complete(p, c); + if (PyErr_Occurred()) { + PyErr_Clear(); + } +} + +static char * +TerminalHint(const char *p, const char **ansi1, const char **ansi2) +{ + char *h = 0; + linenoiseCompletions c = {0}; + TerminalCompletion(p, &c); + if (c.len == 1) h = strdup(c.cvec[0] + strlen(p)); + linenoiseFreeCompletions(&c); + return h; +} + +static char * +ReinterpretCommand(const char *line) +{ + size_t n; + n = strlen(line); + if (n && line[n - 1] == '?') { + return xstrcat("help(", gc(strndup(gc(line), n - 1)), ')'); + } else { + return line; + } +} + +static char * +TerminalReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) +{ + size_t n; + char *p, *q; + PyOS_sighandler_t saint; + saint = PyOS_setsig(SIGINT, OnKeyboardInterrupt); + p = linenoiseWithHistory(prompt, "python"); + PyOS_setsig(SIGINT, saint); + if (g_gotint) { + PyOS_setsig(SIGINT, saint); + g_gotint = 0; + q = 0; + } else if (p) { + p = ReinterpretCommand(p); + n = strlen(p); + q = PyMem_RawMalloc(n + 2); + strcpy(mempcpy(q, p, n), "\n"); + clearerr(sys_stdin); + } else if ((q = PyMem_RawMalloc(1))) { + *q = 0; + } + free(p); + return q; +} + +int +RunPythonModule(int argc, char **argv) +{ + char *launchargs[4]; + wchar_t **argv_copy; + /* We need a second copy, as Python might modify the first one. */ + wchar_t **argv_copy2; + int i, res; + char *oldloc; + + if (argc == 1 && weaken(kLaunchPythonModuleName)) { + launchargs[0] = argv[0]; + launchargs[1] = strdup("-m"); + launchargs[2] = strdup(kLaunchPythonModuleName); + launchargs[3] = 0; + argc = 3; + argv = launchargs; + } + + PyOS_ReadlineFunctionPointer = TerminalReadline; + linenoiseSetCompletionCallback(TerminalCompletion); + linenoiseSetHintsCallback(TerminalHint); + linenoiseSetFreeHintsCallback(free); + +#if IsModeDbg() + /* Force malloc() allocator to bootstrap Python */ + _PyMem_SetupAllocators("malloc"); +#endif + + argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); + argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); + if (!argv_copy || !argv_copy2) { + fprintf(stderr, "out of memory\n"); + return 1; + } + + /* 754 requires that FP exceptions run in "no stop" mode by default, + * and until C vendors implement C99's ways to control FP exceptions, + * Python requires non-stop mode. Alas, some platforms enable FP + * exceptions by default. Here we disable them. + */ +#ifdef __FreeBSD__ + fedisableexcept(FE_OVERFLOW); +#endif + + oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); + if (!oldloc) { + fprintf(stderr, "out of memory\n"); + return 1; + } + + setlocale(LC_ALL, ""); + for (i = 0; i < argc; i++) { + argv_copy[i] = Py_DecodeLocale(argv[i], NULL); + if (!argv_copy[i]) { + PyMem_RawFree(oldloc); + fprintf(stderr, "Fatal Python error: " + "unable to decode the command line argument #%i\n", + i + 1); + return 1; + } + argv_copy2[i] = argv_copy[i]; + } + argv_copy2[argc] = argv_copy[argc] = NULL; + + setlocale(LC_ALL, oldloc); + PyMem_RawFree(oldloc); + + res = Py_Main(argc, argv_copy); + +#if IsModeDbg() + /* Force again malloc() allocator to release memory blocks allocated + before Py_Main() */ + _PyMem_SetupAllocators("malloc"); +#endif + + for (i = 0; i < argc; i++) { + PyMem_RawFree(argv_copy2[i]); + } + PyMem_RawFree(argv_copy); + PyMem_RawFree(argv_copy2); + return res; +} diff --git a/third_party/python/runpythonmodule.h b/third_party/python/runpythonmodule.h new file mode 100644 index 000000000..2aa150780 --- /dev/null +++ b/third_party/python/runpythonmodule.h @@ -0,0 +1,10 @@ +#ifndef COSMOPOLITAN_THIRD_PARTY_PYTHON_RUNPYTHONMODULE_H_ +#define COSMOPOLITAN_THIRD_PARTY_PYTHON_RUNPYTHONMODULE_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +int RunPythonModule(int, char **); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_THIRD_PARTY_PYTHON_RUNPYTHONMODULE_H_ */ diff --git a/third_party/quickjs/quickjs.mk b/third_party/quickjs/quickjs.mk index 8088fecce..8172f7d45 100644 --- a/third_party/quickjs/quickjs.mk +++ b/third_party/quickjs/quickjs.mk @@ -145,7 +145,7 @@ o/$(MODE)/third_party/quickjs/qjs.com.dbg: \ o/$(MODE)/third_party/quickjs/repl.o \ o/$(MODE)/third_party/quickjs/qjscalc.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/quickjs/qjs.com: \ @@ -174,7 +174,7 @@ o/$(MODE)/third_party/quickjs/run-test262.com.dbg: \ $(THIRD_PARTY_QUICKJS_A).pkg \ o/$(MODE)/third_party/quickjs/run-test262.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/quickjs/unicode_gen.com.dbg: \ @@ -183,7 +183,7 @@ o/$(MODE)/third_party/quickjs/unicode_gen.com.dbg: \ $(THIRD_PARTY_QUICKJS_A).pkg \ o/$(MODE)/third_party/quickjs/unicode_gen.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(THIRD_PARTY_QUICKJS_OBJS): \ @@ -205,8 +205,8 @@ o/$(MODE)/third_party/quickjs/quickjs.o: \ OVERRIDE_CPPFLAGS += \ -DSTACK_FRAME_UNLIMITED -o/$(MODE)/third_party/quickjs/call.o: QUOTA = -M1024m -C32 -o/$(MODE)/third_party/quickjs/quickjs.o: QUOTA = -M512m -C32 +o/$(MODE)/third_party/quickjs/call.o: QUOTA = -M1024m -C32 -L180 +o/$(MODE)/third_party/quickjs/quickjs.o: QUOTA = -M512m -C32 -L180 .PHONY: o/$(MODE)/third_party/quickjs o/$(MODE)/third_party/quickjs: \ diff --git a/third_party/smallz4/smallz4.hh b/third_party/smallz4/smallz4.hh index 310c89831..abf9b5683 100644 --- a/third_party/smallz4/smallz4.hh +++ b/third_party/smallz4/smallz4.hh @@ -1,5 +1,6 @@ #ifndef COSMOPOLITAN_THIRD_PARTY_SMALLZ4_SMALLZ4_H_ #define COSMOPOLITAN_THIRD_PARTY_SMALLZ4_SMALLZ4_H_ +#include "libc/bits/bits.h" #include "third_party/libcxx/vector" /** @@ -138,7 +139,7 @@ class smallz4 { /// return true, if the four bytes at *a and *b match inline static bool match4(const void* const a, const void* const b) { - return *(const uint32_t*)a == *(const uint32_t*)b; + return READ32LE(a) == READ32LE(b); } /// simple hash function, input: 32 bits, output: HashBits bits (by default: @@ -636,7 +637,7 @@ class smallz4 { } // read next four bytes - const uint32_t four = *(uint32_t*)(dataBlock + i); + const uint32_t four = READ32LE(dataBlock + i); // convert to a shorter hash const uint32_t hash = getHash32(four); @@ -674,10 +675,9 @@ class smallz4 { // check the hash chain while (true) { // read four bytes - currentFour = - *(uint32_t*)(&data[lastHashMatch - - dataZero]); // match may be found in the - // previous block, too + currentFour = READ32LE( + &data[lastHashMatch - dataZero]); // match may be found in the + // previous block, too // match chain found, first 4 bytes are identical if (currentFour == four) break; diff --git a/third_party/smallz4/smallz4.mk b/third_party/smallz4/smallz4.mk index aea621222..a47b7ca86 100644 --- a/third_party/smallz4/smallz4.mk +++ b/third_party/smallz4/smallz4.mk @@ -60,14 +60,14 @@ o/$(MODE)/third_party/smallz4/smallz4.com.dbg: \ $(THIRD_PARTY_SMALLZ4) \ o/$(MODE)/third_party/smallz4/smallz4.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/third_party/smallz4/smallz4cat.com.dbg: \ $(THIRD_PARTY_SMALLZ4) \ o/$(MODE)/third_party/smallz4/smallz4cat.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) THIRD_PARTY_SMALLZ4_COMS = \ diff --git a/third_party/xed/xed.mk b/third_party/xed/xed.mk index 0a45e57c8..26791595e 100644 --- a/third_party/xed/xed.mk +++ b/third_party/xed/xed.mk @@ -40,7 +40,7 @@ THIRD_PARTY_XED_A_DIRECTDEPS = \ THIRD_PARTY_XED_A_DEPS := \ $(call uniq,$(foreach x,$(THIRD_PARTY_XED_A_DIRECTDEPS),$($(x)))) -o/$(MODE)/third_party/xed/x86ild.greg.o: \ +o/$(MODE)/third_party/xed/x86ild.greg.o: \ OVERRIDE_CFLAGS += \ -mstringop-strategy=unrolled_loop @@ -53,6 +53,10 @@ $(THIRD_PARTY_XED_A).pkg: \ $(THIRD_PARTY_XED_A_OBJS) \ $(foreach x,$(THIRD_PARTY_XED_A_DIRECTDEPS),$($(x)_A).pkg) +o/$(MODE)/third_party/xed/x86ild.greg.o: \ + OVERRIDE_CFLAGS += \ + -O3 + HIRD_PARTY_XED_LIBS = $(foreach x,$(THIRD_PARTY_XED_ARTIFACTS),$($(x))) THIRD_PARTY_XED_SRCS = $(foreach x,$(THIRD_PARTY_XED_ARTIFACTS),$($(x)_SRCS)) THIRD_PARTY_XED_HDRS = $(foreach x,$(THIRD_PARTY_XED_ARTIFACTS),$($(x)_HDRS)) diff --git a/third_party/zlib/gz/gzread.c b/third_party/zlib/gz/gzread.c index 73558600f..c514a81af 100644 --- a/third_party/zlib/gz/gzread.c +++ b/third_party/zlib/gz/gzread.c @@ -1,5 +1,9 @@ #include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/limits.h" +#include "libc/str/str.h" #include "third_party/zlib/gz/gzguts.inc" +#include "third_party/zlib/zlib.h" // clang-format off /* gzread.c -- zlib functions for reading gzip files diff --git a/tool/args/args.c b/tool/args/args.c index 204341f16..aec1c73ff 100644 --- a/tool/args/args.c +++ b/tool/args/args.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/calls/calls.h" +#include "libc/errno.h" #include "libc/runtime/gc.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" @@ -28,7 +29,7 @@ STATIC_YOINK("zip_uri_support"); static struct ZipArgs { - bool registered; + bool initialized; bool loaded; int oldargc; char *data; @@ -75,15 +76,15 @@ int LoadZipArgsImpl(int *argc, char ***argv, char *data) { start = 0; } if (founddots || *argc <= 1) { - if (!g_zipargs.registered) { + if (!g_zipargs.initialized) { atexit(FreeZipArgs); - g_zipargs.registered = true; + g_zipargs.oldargc = __argc; + g_zipargs.oldargv = __argv; + g_zipargs.initialized = true; } g_zipargs.loaded = true; g_zipargs.data = data; g_zipargs.args = args; - g_zipargs.oldargc = *argc; - g_zipargs.oldargv = *argv; *argc = n; *argv = args; __argc = n; @@ -107,8 +108,16 @@ int LoadZipArgsImpl(int *argc, char ***argv, char *data) { * If the special argument `...` *is* encountered, then it'll be * replaced with whatever CLI args were specified by the user. * - * @return 0 on success, or -1 w/ errno + * @return 0 on success, or -1 if not found w/o errno clobber */ int LoadZipArgs(int *argc, char ***argv) { - return LoadZipArgsImpl(argc, argv, xslurp("/zip/.args", 0)); + int e; + char *p; + e = errno; + if ((p = xslurp("/zip/.args", 0))) { + return LoadZipArgsImpl(argc, argv, p); + } else { + errno = e; + return -1; + } } diff --git a/tool/args/args.mk b/tool/args/args.mk index 0cd6dba4f..03618a287 100644 --- a/tool/args/args.mk +++ b/tool/args/args.mk @@ -21,6 +21,7 @@ TOOL_ARGS_A_DIRECTDEPS = \ LIBC_NEXGEN32E \ LIBC_STR \ LIBC_STUBS \ + LIBC_SYSV \ LIBC_X \ LIBC_ZIPOS diff --git a/tool/build/ar.c b/tool/build/ar.c index 2f62f31eb..c33da4e07 100644 --- a/tool/build/ar.c +++ b/tool/build/ar.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/alg/arraylist2.internal.h" +#include "libc/assert.h" #include "libc/bits/bits.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" @@ -26,12 +27,16 @@ #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/fmt/itoa.h" +#include "libc/intrin/kprintf.h" #include "libc/log/check.h" +#include "libc/log/log.h" #include "libc/macros.internal.h" +#include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" +#include "libc/sysv/consts/ex.h" #include "libc/sysv/consts/madv.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" @@ -53,6 +58,8 @@ * This tool also adds a feature: it ignores directory parameters. This * is important because good Makefiles on Linux will generally have the * directory be a .a prerequisite so archives rebuild on file deletion. + * + * @see https://www.unix.com/man-page/opensolaris/3head/ar.h/ */ struct Args { @@ -80,29 +87,68 @@ struct Header { char fmag[2]; }; +static void *Realloc(void *p, size_t n) { + void *q; + if (!(q = realloc(p, n))) { + fputs("error: ar: out of memory\n", stderr); + exit(1); + } + return q; +} + +static void *Malloc(size_t n) { + return Realloc(0, n); +} + +static void NewArgs(struct Args *l, size_t n) { + l->i = 0; + l->n = MAX(2, n); + l->p = Malloc(l->n * sizeof(*l->p)); + l->p[0] = 0; +} + static void NewInts(struct Ints *l, size_t n) { l->i = 0; - l->n = n; - l->p = xmalloc(n * sizeof(int)); + l->n = MAX(2, n); + l->p = Malloc(l->n * sizeof(*l->p)); + l->p[0] = 0; } static void NewString(struct String *s, size_t n) { s->i = 0; - s->n = n; - s->p = xmalloc(n); + s->n = MAX(2, n); + s->p = Malloc(s->n * sizeof(*s->p)); + s->p[0] = 0; } static void AppendInt(struct Ints *l, int i) { - APPEND(&l->p, &l->i, &l->n, &i); + assert(l->n > 1); + if (l->i + 1 >= l->n) { + do { + l->n += l->n >> 1; + } while (l->i + 1 >= l->n); + l->p = Realloc(l->p, l->n * sizeof(*l->p)); + } + l->p[l->i++] = i; + l->p[l->i] = 0; } static void AppendArg(struct Args *l, char *s) { - APPEND(&l->p, &l->i, &l->n, &s); + assert(l->n > 1); + if (l->i + 1 >= l->n) { + do { + l->n += l->n >> 1; + } while (l->i + 1 >= l->n); + l->p = Realloc(l->p, l->n * sizeof(*l->p)); + } + l->p[l->i++] = s; + l->p[l->i] = 0; } static void MakeHeader(struct Header *h, const char *name, int ref, int mode, int size) { size_t n; + char ibuf[13], *p; memset(h, ' ', sizeof(*h)); n = strlen(name); memcpy(h->name, name, n); @@ -113,11 +159,15 @@ static void MakeHeader(struct Header *h, const char *name, int ref, int mode, h->date[0] = '0'; h->uid[0] = '0'; h->gid[0] = '0'; - FormatOctal32(h->mode, mode & 0777, false); + p = FormatOctal32(ibuf, mode & 0777, false); + CHECK_LE(p - ibuf, sizeof(h->mode)); + memcpy(h->mode, ibuf, p - ibuf); } h->fmag[0] = '`'; h->fmag[1] = '\n'; - FormatUint32(h->size, size); + p = FormatUint32(ibuf, size); + CHECK_LE(p - ibuf, sizeof(h->size)); + memcpy(h->size, ibuf, p - ibuf); } int main(int argc, char *argv[]) { @@ -151,15 +201,24 @@ int main(int argc, char *argv[]) { struct Header *header1, *header2; int i, j, fd, err, name, outfd, tablebufsize; - if (argc == 2 && !strcmp(argv[1], "-n")) exit(0); + // TODO(jart): Delete this. + if (argc == 2 && !strcmp(argv[1], "-n")) { + exit(0); + } + + // we only support one mode of operation, which is creating a new + // deterministic archive. this tool is so fast that we don't need + // database-like tools when editing static archives if (!(argc > 2 && strcmp(argv[1], "rcsD") == 0)) { - fprintf(stderr, "%s%s%s\n", "Usage: ", argv[0], " rcsD ARCHIVE FILE..."); - return 1; + fputs("usage: ", stderr); + if (argc > 0) fputs(argv[0], stderr); + fputs(" rcsD ARCHIVE FILE...", stderr); + exit(EX_USAGE); } outpath = argv[2]; - bzero(&args, sizeof(args)); - st = xmalloc(sizeof(struct stat)); + NewArgs(&args, 4); + st = Malloc(sizeof(struct stat)); NewInts(&modes, 128); NewInts(&names, 128); NewInts(&sizes, 128); @@ -206,10 +265,10 @@ int main(int argc, char *argv[]) { // compute length of output archive outsize = 0; tablebufsize = 4 + symnames.i * 4; - tablebuf = xmalloc(tablebufsize); - offsets = xmalloc(args.i * 4); - header1 = xmalloc(sizeof(struct Header)); - header2 = xmalloc(sizeof(struct Header)); + tablebuf = Malloc(tablebufsize); + offsets = Malloc(args.i * 4); + header1 = Malloc(sizeof(struct Header)); + header2 = Malloc(sizeof(struct Header)); iov[0].iov_base = "!\n"; outsize += (iov[0].iov_len = 8); iov[1].iov_base = header1; diff --git a/tool/build/build.mk b/tool/build/build.mk index 9df4dace4..e81c3f03b 100644 --- a/tool/build/build.mk +++ b/tool/build/build.mk @@ -56,9 +56,11 @@ TOOL_BUILD_DIRECTDEPS = \ THIRD_PARTY_GDTOA \ THIRD_PARTY_GETOPT \ THIRD_PARTY_MBEDTLS \ + THIRD_PARTY_MUSL \ THIRD_PARTY_STB \ THIRD_PARTY_XED \ THIRD_PARTY_ZLIB \ + THIRD_PARTY_ZLIB_GZ \ TOOL_BUILD_LIB TOOL_BUILD_DEPS := \ @@ -78,7 +80,7 @@ o/$(MODE)/tool/build/%.com.dbg: \ o/$(MODE)/tool/build/build.pkg \ o/$(MODE)/tool/build/%.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/build/blinkenlights.com.dbg: \ @@ -105,7 +107,7 @@ o/$(MODE)/tool/build/ar.com.dbg: \ o/$(MODE)/tool/build/build.pkg \ o/$(MODE)/tool/build/ar.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/build/package.com.dbg: \ @@ -113,7 +115,7 @@ o/$(MODE)/tool/build/package.com.dbg: \ o/$(MODE)/tool/build/build.pkg \ o/$(MODE)/tool/build/package.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/build/mkdeps.com.dbg: \ @@ -121,7 +123,7 @@ o/$(MODE)/tool/build/mkdeps.com.dbg: \ o/$(MODE)/tool/build/build.pkg \ o/$(MODE)/tool/build/mkdeps.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/build/compile.com.dbg: \ @@ -129,7 +131,7 @@ o/$(MODE)/tool/build/compile.com.dbg: \ o/$(MODE)/tool/build/build.pkg \ o/$(MODE)/tool/build/compile.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/build/zipobj.com.dbg: \ @@ -137,7 +139,7 @@ o/$(MODE)/tool/build/zipobj.com.dbg: \ o/$(MODE)/tool/build/build.pkg \ o/$(MODE)/tool/build/zipobj.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/build/emulator.o: \ diff --git a/tool/build/cocmd.c b/tool/build/cocmd.c new file mode 100644 index 000000000..c0e717803 --- /dev/null +++ b/tool/build/cocmd.c @@ -0,0 +1,220 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/fmt/itoa.h" +#include "libc/macros.internal.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" + +/** + * @fileoverview Cosmopolitan Command Interpreter + * + * This is a lightweight command interpreter for GNU Make. It has just + * enough shell script language support to support our build config. + */ + +#define STATE_SHELL 0 +#define STATE_STR 1 + +char *p; +char *q; +char *cmd; +char *args[8192]; +const char *prog; +char argbuf[ARG_MAX]; +bool unsupported[256]; + +wontreturn void UnsupportedSyntax(unsigned char c) { + char ibuf[13]; + FormatOctal32(ibuf, c, true); + fputs(prog, stderr); + fputs(": unsupported shell syntax '", stderr); + fputc(c, stderr); + fputs("' (", stderr); + fputs(ibuf, stderr); + fputs("): ", stderr); + fputs(cmd, stderr); + fputs("\n", stderr); + exit(1); +} + +void Open(const char *path, int fd, int flags) { + const char *err; + close(fd); + if (open(path, flags, 0644) == -1) { + err = strerdoc(errno); + fputs(prog, stderr); + fputs(": failed to open '", stderr); + fputs(path, stderr); + fputs("': ", stderr); + fputs(err, stderr); + fputs("\n", stderr); + exit(1); + } +} + +char *Tokenize(void) { + int t; + char *r; + while (*p == ' ' || *p == '\t' || *p == '\n' || + (p[0] == '\\' && p[1] == '\n')) { + ++p; + } + if (!*p) return 0; + t = STATE_SHELL; + for (r = q;; ++p) { + switch (t) { + + case STATE_SHELL: + if (unsupported[*p & 255]) { + UnsupportedSyntax(*p); + } + if (!*p || *p == ' ' || *p == '\t') { + *q++ = 0; + return r; + } else if (*p == '\'') { + t = STATE_STR; + } else if (*p == '\\') { + if (!p[1]) UnsupportedSyntax(*p); + *q++ = *++p; + } else { + *q++ = *p; + } + break; + + case STATE_STR: + if (!*p) { + fputs("cmd: error: unterminated string\n", stderr); + exit(1); + } + if (*p == '\'') { + t = STATE_SHELL; + } else { + *q++ = *p; + } + break; + + default: + unreachable; + } + } +} + +int main(int argc, char *argv[]) { + char *s, *arg; + size_t i, j, n; + prog = argc > 0 ? argv[0] : "cocmd.com"; + + for (i = 1; i < 32; ++i) { + unsupported[i] = true; + } + unsupported['\t'] = false; + unsupported[0177] = true; + unsupported['~'] = true; + unsupported['`'] = true; + unsupported['#'] = true; + unsupported['$'] = true; + unsupported['*'] = true; + unsupported['('] = true; + unsupported[')'] = true; + unsupported['|'] = true; + unsupported['['] = true; + unsupported[']'] = true; + unsupported['{'] = true; + unsupported['}'] = true; + unsupported[';'] = true; + unsupported['"'] = true; + unsupported['?'] = true; + unsupported['!'] = true; + + if (argc != 3) { + fputs(prog, stderr); + fputs(": error: wrong number of args\n", stderr); + return 1; + } + + if (strcmp(argv[1], "-c")) { + fputs(prog, stderr); + fputs(": error: argv[1] should -c\n", stderr); + return 1; + } + + p = cmd = argv[2]; + if (strlen(cmd) >= ARG_MAX) { + fputs(prog, stderr); + fputs(": error: cmd too long: ", stderr); + fputs(cmd, stderr); + fputs("\n", stderr); + return 1; + } + + n = 0; + q = argbuf; + while ((arg = Tokenize())) { + if (n + 1 < ARRAYLEN(args)) { + if (!strcmp(arg, "2>&1")) { + close(1); + dup(2); + } else if (!strcmp(arg, ">&2")) { + close(2); + dup(1); + } else if (arg[0] == '2' && arg[1] == '>' && arg[2] == '>') { + Open(arg + 3, 2, O_WRONLY | O_CREAT | O_APPEND); + } else if (arg[0] == '>' && arg[1] == '>') { + Open(arg + 2, 1, O_WRONLY | O_CREAT | O_APPEND); + } else if (arg[0] == '2' && arg[1] == '>') { + Open(arg + 2, 2, O_WRONLY | O_CREAT | O_TRUNC); + } else if (arg[0] == '>') { + Open(arg + 1, 1, O_WRONLY | O_CREAT | O_TRUNC); + } else if (arg[0] == '<') { + Open(arg + 1, 0, O_RDONLY); + } else { + args[n++] = arg; + } + } else { + fputs(prog, stderr); + fputs(": error: too many args\n", stderr); + return 1; + } + } + + if (!n) { + fputs(prog, stderr); + fputs(": error: too few args\n", stderr); + return 1; + } + + execv(args[0], args); + if (!n) { + s = strerdoc(errno); + fputs(prog, stderr); + fputs(": execve '", stderr); + fputs(args[0], stderr); + fputs("' failed: ", stderr); + fputs(s, stderr); + fputs("\n", stderr); + return 1; + } + + return 127; +} diff --git a/tool/build/compile.c b/tool/build/compile.c index 4088fc917..7705c048d 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -32,6 +32,7 @@ #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/fmt/itoa.h" +#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/log/color.internal.h" #include "libc/log/log.h" @@ -170,9 +171,7 @@ char *output; char *outpath; char *command; char *shortened; -char *cachedcmd; char *colorflag; -char *originalcmd; char ccpath[PATH_MAX]; struct stat st; @@ -582,7 +581,7 @@ int Launch(void) { timer.it_interval.tv_sec = timeout; setitimer(ITIMER_REAL, &timer, 0); } - pid = fork(); + pid = vfork(); #if 0 int fd; @@ -665,6 +664,8 @@ int Launch(void) { kill(pid, SIGKILL); gotalrm = 1; } + } else if (errno == ECHILD) { + break; } else { /* this should never happen */ PrintRed(); @@ -1040,44 +1041,6 @@ int main(int argc, char *argv[]) { } } - /* - * help error reporting code find symbol table - */ - if (startswith(cmd, "o/")) { - if (endswith(cmd, ".com")) { - s = xstrcat(cmd, ".dbg"); - } else { - s = xstrcat(cmd, ".com.dbg"); - } - if (fileexists(s)) { - AddEnv(xstrcat("COMDBG=", getcwd(0, 0), '/', s)); - } - } - - /* - * create assimilated atomic copies of ape binaries - */ - if (!IsWindows() && endswith(cmd, ".com")) { - if (!startswith(cmd, "o/")) { - cachedcmd = xstrcat("o/", cmd); - } else { - cachedcmd = xstrcat(xstripext(cmd), ".elf"); - } - if (FileExistsAndIsNewerThan(cachedcmd, cmd)) { - cmd = cachedcmd; - } else { - originalcmd = cmd; - FormatInt64(buf, getpid()); - cmd = xstrcat(originalcmd, ".tmp.", buf); - if (copyfile(originalcmd, cmd, COPYFILE_PRESERVE_TIMESTAMPS) == -1) { - fputs("error: compile.com failed to copy ape executable\n", stderr); - unlink(cmd); - exit(97); - } - } - args.p[0] = cmd; - } - /* * make sense of standard i/o file descriptors * we want to permit pipelines but prevent talking to terminal @@ -1117,26 +1080,6 @@ int main(int argc, char *argv[]) { * run command */ ws = Launch(); - if (ws != -1 && WIFEXITED(ws) && WEXITSTATUS(ws) == 127) { - if (startswith(cmd, "o/third_party/gcc") && - fileexists("third_party/gcc/unbundle.sh")) { - system("third_party/gcc/unbundle.sh"); - ws = Launch(); - } - } - - /* - * cleanup temporary copy of ape executable - */ - if (originalcmd) { - if (cachedcmd && WIFEXITED(ws) && !WEXITSTATUS(ws) && - IsNativeExecutable(cmd)) { - makedirs(xdirname(cachedcmd), 0755); - rename(cmd, cachedcmd); - } else { - unlink(cmd); - } - } /* * propagate exit diff --git a/tool/build/cp.c b/tool/build/cp.c new file mode 100644 index 000000000..f8c41dac7 --- /dev/null +++ b/tool/build/cp.c @@ -0,0 +1,234 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/copyfile.h" +#include "libc/calls/struct/stat.h" +#include "libc/errno.h" +#include "libc/fmt/conv.h" +#include "libc/fmt/fmt.h" +#include "libc/intrin/kprintf.h" +#include "libc/runtime/gc.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/at.h" +#include "libc/sysv/consts/ex.h" +#include "libc/sysv/consts/exit.h" +#include "libc/sysv/consts/ok.h" +#include "libc/x/x.h" +#include "third_party/getopt/getopt.h" +#include "third_party/musl/ftw.h" + +#define USAGE \ + " SRC... DST\n\ +\n\ +SYNOPSIS\n\ +\n\ + Copies Files\n\ +\n\ +FLAGS\n\ +\n\ + -?\n\ + -h help\n\ + -f force\n\ + -r recursive\n\ + -n no clobber\n\ + -a preserve all\n\ + -p preserve owner and timestamps\n\ +\n" + +int flags; +bool force; +int striplen; +bool recursive; +const char *prog; +char mkbuf[PATH_MAX]; +char srcdir[PATH_MAX]; +char dstdir[PATH_MAX]; +char srcfile[PATH_MAX]; +char dstfile[PATH_MAX]; +char linkbuf[PATH_MAX]; + +void Cp(char *, char *); + +bool IsDirectory(const char *path) { + int e; + bool res; + struct stat st; + e = errno; + res = stat(path, &st) != -1 && S_ISDIR(st.st_mode); + errno = e; + return res; +} + +bool IsSymlink(const char *path) { + int e; + bool res; + struct stat st; + e = errno; + res = fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1 && + S_ISLNK(st.st_mode); + errno = e; + return res; +} + +wontreturn void PrintUsage(int rc, FILE *f) { + fputs("usage: ", f); + fputs(prog, f); + fputs(USAGE, f); + exit(rc); +} + +void GetOpts(int argc, char *argv[]) { + int opt; + while ((opt = getopt(argc, argv, "?hfnaprR")) != -1) { + switch (opt) { + case 'f': + force = true; + break; + case 'r': + case 'R': + recursive = true; + break; + case 'n': + flags |= COPYFILE_NOCLOBBER; + break; + case 'a': + case 'p': + flags |= COPYFILE_PRESERVE_OWNER; + flags |= COPYFILE_PRESERVE_TIMESTAMPS; + break; + case 'h': + case '?': + PrintUsage(EXIT_SUCCESS, stdout); + default: + PrintUsage(EX_USAGE, stderr); + } + } +} + +int Visit(const char *fpath, const struct stat *sb, int tflag, + struct FTW *ftwbuf) { + char *src; + strcpy(srcfile, fpath); + src = srcfile + striplen; + strcpy(dstfile, dstdir); + if (!endswith(dstfile, "/")) { + strcat(dstfile, "/"); + } + strcat(dstfile, src); + strcpy(srcfile, fpath); + switch (tflag) { + case FTW_D: + return 0; + case FTW_F: + case FTW_SL: + case FTW_SLN: + Cp(srcfile, dstfile); + return 0; + default: + fputs(fpath, stderr); + fputs(": can't handle file type\n", stderr); + exit(1); + } +} + +char *Join(const char *a, const char *b) { + size_t n, m; + n = strlen(a); + m = strlen(b); + if (n + 1 + m + 1 > sizeof(dstfile)) { + fputs("error: cp: path too long\n", stderr); + exit(1); + } + stpcpy(stpcpy(stpcpy(dstfile, a), "/"), b); + return dstfile; +} + +void Cp(char *src, char *dst) { + ssize_t rc; + const char *s; + if (strlen(src) + 1 > PATH_MAX) _Exit(2); + if (strlen(dst) + 1 > PATH_MAX) _Exit(2); + basename(src); + basename(dst); + if (IsDirectory(src)) { + if (!recursive) { + fputs(prog, stderr); + fputs(": won't copy directory without -r flag.\n", stderr); + exit(1); + } + strcpy(dstdir, dst); + if (IsDirectory(dst)) { + strcpy(srcdir, src); + basename(srcdir); + striplen = 0; + strcpy(srcdir, basename(src)); + } else { + strcpy(srcdir, src); + basename(srcdir); + striplen = strlen(srcdir); + strcpy(srcdir, ""); + } + if (nftw(src, Visit, 20, 0) == -1) { + fputs(prog, stderr); + fputs(": nftw failed: ", stderr); + fputs(strerdoc(errno), stderr); + fputs("\n", stderr); + exit(1); + } + return; + } + if (IsDirectory(dst)) { + dst = Join(dst, basename(src)); + } + if (!force && access(dst, W_OK) == -1 && errno != ENOENT) goto OnFail; + strcpy(mkbuf, dst); + if (makedirs(dirname(mkbuf), 0755) == -1) goto OnFail; + if (IsSymlink(src)) { + if ((rc = readlink(src, linkbuf, sizeof(linkbuf) - 1)) == -1) goto OnFail; + linkbuf[rc] = 0; + if (symlink(linkbuf, dst) == -1) goto OnFail; + } else { + if (copyfile(src, dst, flags) == -1) goto OnFail; + } + return; +OnFail: + s = strerdoc(errno); + fputs(prog, stderr); + fputs(": ", stderr); + fputs(src, stderr); + fputs(" ", stderr); + fputs(dst, stderr); + fputs(": ", stderr); + fputs(s, stderr); + fputs("\n", stderr); + exit(1); +} + +int main(int argc, char *argv[]) { + int i; + prog = argc > 0 ? argv[0] : "cp.com"; + GetOpts(argc, argv); + if (argc - optind < 2) PrintUsage(EX_USAGE, stderr); + for (i = optind; i < argc - 1; ++i) { + Cp(argv[i], argv[argc - 1]); + } + return 0; +} diff --git a/tool/build/echo.c b/tool/build/echo.c new file mode 100644 index 000000000..4cc0fe8e8 --- /dev/null +++ b/tool/build/echo.c @@ -0,0 +1,46 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" + +int main(int argc, char *argv[]) { + int i, j; + FILE *stream = stdout; + bool wantnewline = true; + + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-n")) { + wantnewline = false; + } else if (!strcmp(argv[i], "-2")) { + stream = stderr; + } else { + break; + } + } + + for (j = 0; i + j < argc; ++j) { + if (j) fputc(' ', stream); + fputs(argv[i + j], stream); + } + if (wantnewline) { + fputc('\n', stream); + } + + return 0; +} diff --git a/tool/build/gzip.c b/tool/build/gzip.c new file mode 100644 index 000000000..ce86f8217 --- /dev/null +++ b/tool/build/gzip.c @@ -0,0 +1,310 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/ex.h" +#include "libc/sysv/consts/exit.h" +#include "libc/sysv/consts/ok.h" +#include "third_party/getopt/getopt.h" +#include "third_party/zlib/zlib.h" + +#define USAGE \ + " PATH...\n\ +\n\ +SYNOPSIS\n\ +\n\ + Compress Files\n\ +\n\ +FLAGS\n\ +\n\ + -?\n\ + -h help\n\ + -f force\n\ + -c use stdout\n\ + -d decompress\n\ + -A append mode\n\ + -x exclusive mode\n\ + -k keep input file\n\ + -0 disable compression\n\ + -1 fastest compression\n\ + -4 coolest compression\n\ + -9 maximum compression\n\ + -a ascii mode (ignored)\n\ + -F fixed strategy (advanced)\n\ + -L filtered strategy (advanced)\n\ + -R run length strategy (advanced)\n\ + -H huffman only strategy (advanced)\n\ +\n" + +bool opt_keep; +bool opt_force; +char opt_level; +bool opt_append; +char opt_strategy; +bool opt_exclusive; +bool opt_usestdout; +bool opt_decompress; + +const char *prog; +char databuf[32768]; +char pathbuf[PATH_MAX]; + +wontreturn void PrintUsage(int rc, FILE *f) { + fputs("usage: ", f); + fputs(prog, f); + fputs(USAGE, f); + exit(rc); +} + +void GetOpts(int argc, char *argv[]) { + int opt; + while ((opt = getopt(argc, argv, "?hfcdakxALFRHF0123456789")) != -1) { + switch (opt) { + case 'k': + opt_keep = true; + break; + case 'f': + opt_force = true; + break; + case 'A': + opt_append = true; + break; + case 'c': + opt_usestdout = true; + break; + case 'x': + opt_exclusive = true; + break; + case 'd': + opt_decompress = true; + break; + case 'F': + opt_strategy = 'F'; // Z_FIXED + break; + case 'L': + opt_strategy = 'f'; // Z_FILTERED + break; + case 'R': + opt_strategy = 'R'; // Z_RLE + break; + case 'H': + opt_strategy = 'h'; // Z_HUFFMAN_ONLY + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + opt_level = opt; + break; + case 'h': + case '?': + PrintUsage(EXIT_SUCCESS, stdout); + default: + PrintUsage(EX_USAGE, stderr); + } + } +} + +void Compress(const char *inpath) { + FILE *input; + gzFile output; + int rc, n, errnum; + const char *outpath; + char *p, openflags[5]; + outpath = 0; + if (inpath) { + input = fopen(inpath, "rb"); + } else if (opt_usestdout && (opt_force || !isatty(1))) { + opt_usestdout = true; + inpath = "/dev/stdin"; + input = stdin; + } else { + fputs(prog, stderr); + fputs(": compressed data not written to a terminal." + " Use -f to force compression.\n", + stderr); + exit(1); + } + p = openflags; + *p++ = opt_append ? 'a' : 'w'; + *p++ = 'b'; + if (opt_exclusive) *p++ = 'x'; + if (opt_level) *p++ = opt_level; + if (opt_strategy) *p++ = opt_strategy; + *p = 0; + if (opt_usestdout) { + outpath = "/dev/stdout"; + output = gzdopen(0, openflags); + } else { + if (strlen(inpath) + 3 + 1 > PATH_MAX) _Exit(2); + stpcpy(stpcpy(pathbuf, inpath), ".gz"); + outpath = pathbuf; + output = gzopen(outpath, openflags); + } + if (!output) { + fputs(outpath, stderr); + fputs(": gzopen() failed\n", stderr); + fputs(strerdoc(errno), stderr); + fputs("\n", stderr); + exit(1); + } + do { + rc = fread(databuf, 1, sizeof(databuf), input); + if (rc == -1) { + errnum = 0; + fputs(inpath, stderr); + fputs(": read failed: ", stderr); + fputs(strerdoc(ferror(input)), stderr); + fputs("\n", stderr); + _Exit(1); + } + if (!gzwrite(output, databuf, rc)) { + fputs(outpath, stderr); + fputs(": gzwrite failed: ", stderr); + fputs(gzerror(output, &errnum), stderr); + fputs("\n", stderr); + _Exit(1); + } + } while (rc == sizeof(databuf)); + if (input != stdin) { + if (fclose(input)) { + fputs(inpath, stderr); + fputs(": close failed\n", stderr); + _Exit(1); + } + } + if (gzclose(output)) { + fputs(outpath, stderr); + fputs(": gzclose failed\n", stderr); + _Exit(1); + } + if (!opt_keep && !opt_usestdout && (opt_force || !access(inpath, W_OK))) { + unlink(inpath); + } +} + +void Decompress(const char *inpath) { + FILE *output; + gzFile input; + int rc, n, errnum; + const char *outpath; + outpath = 0; + if (inpath) { + input = gzopen(inpath, "rb"); + } else { + opt_usestdout = true; + inpath = "/dev/stdin"; + input = gzdopen(0, "rb"); + } + if (!input) { + fputs(inpath, stderr); + fputs(": gzopen() failed\n", stderr); + fputs(strerdoc(errno), stderr); + fputs("\n", stderr); + exit(1); + } + if (opt_usestdout) { + output = stdout; + outpath = "/dev/stdout"; + } else if (endswith(inpath, ".gz")) { + n = strlen(inpath); + if (n - 3 + 1 > PATH_MAX) _Exit(2); + memcpy(pathbuf, inpath, n - 3); + pathbuf[n - 3] = 0; + outpath = pathbuf; + if (!(output = fopen(outpath, opt_append ? "wa" : "wb"))) { + fputs(outpath, stderr); + fputs(": open failed: ", stderr); + fputs(strerdoc(errno), stderr); + fputs("\n", stderr); + _Exit(1); + } + } else { + fputs(inpath, stderr); + fputs(": needs to end with .gz unless -c is passed\n", stderr); + _Exit(1); + } + do { + rc = gzread(input, databuf, sizeof(databuf)); + if (rc == -1) { + errnum = 0; + fputs(inpath, stderr); + fputs(": gzread failed: ", stderr); + fputs(gzerror(input, &errnum), stderr); + fputs("\n", stderr); + _Exit(1); + } + if (fwrite(databuf, rc, 1, output) != 1) { + fputs(outpath, stderr); + fputs(": write failed: ", stderr); + fputs(strerdoc(ferror(output)), stderr); + fputs("\n", stderr); + _Exit(1); + } + } while (rc == sizeof(databuf)); + if (gzclose(input)) { + fputs(inpath, stderr); + fputs(": gzclose failed\n", stderr); + _Exit(1); + } + if (output != stdout) { + if (fclose(output)) { + fputs(outpath, stderr); + fputs(": close failed\n", stderr); + _Exit(1); + } + } + if (!opt_keep && !opt_usestdout && (opt_force || !access(inpath, W_OK))) { + unlink(inpath); + } +} + +int main(int argc, char *argv[]) { + int i; + prog = argc > 0 ? argv[0] : "cp.com"; + GetOpts(argc, argv); + if (opt_decompress) { + if (optind == argc) { + Decompress(0); + } else { + for (i = optind; i < argc; ++i) { + Decompress(argv[i]); + } + } + } else { + if (optind == argc) { + Compress(0); + } else { + for (i = optind; i < argc; ++i) { + Compress(argv[i]); + } + } + } + return 0; +} diff --git a/libc/calls/virtualmax.c b/tool/build/lib/apetest.c similarity index 91% rename from libc/calls/virtualmax.c rename to tool/build/lib/apetest.c index 92df148c7..99e91c535 100644 --- a/libc/calls/virtualmax.c +++ b/tool/build/lib/apetest.c @@ -18,11 +18,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" -/** - * Maximum amount of virtual memory in bytes. - * - * mmap() will return ENOMEM once this is reached. - * - * By default no limit is imposed. - */ -size_t __virtualmax = -1; +int main(int argc, char *argv[]) { + write(1, "success\n", 8); +} diff --git a/tool/build/lib/buildlib.mk b/tool/build/lib/buildlib.mk index 383200cab..06b287a6d 100644 --- a/tool/build/lib/buildlib.mk +++ b/tool/build/lib/buildlib.mk @@ -9,7 +9,9 @@ TOOL_BUILD_LIB_A = o/$(MODE)/tool/build/lib/buildlib.a TOOL_BUILD_LIB_A_FILES := $(wildcard tool/build/lib/*) TOOL_BUILD_LIB_A_HDRS = $(filter %.h,$(TOOL_BUILD_LIB_A_FILES)) TOOL_BUILD_LIB_A_SRCS_S = $(filter %.S,$(TOOL_BUILD_LIB_A_FILES)) -TOOL_BUILD_LIB_A_SRCS_C = $(filter %.c,$(TOOL_BUILD_LIB_A_FILES)) + +TOOL_BUILD_LIB_A_SRCS_C = \ + $(filter-out tool/build/lib/apetest.c,$(filter %.c,$(TOOL_BUILD_LIB_A_FILES))) TOOL_BUILD_LIB_A_CHECKS = \ $(TOOL_BUILD_LIB_A_HDRS:%=o/$(MODE)/%.ok) \ @@ -19,9 +21,15 @@ TOOL_BUILD_LIB_A_SRCS = \ $(TOOL_BUILD_LIB_A_SRCS_S) \ $(TOOL_BUILD_LIB_A_SRCS_C) +TOOL_BUILD_LIB_COMS = \ + o/$(MODE)/tool/build/lib/apetest.com \ + o/$(MODE)/tool/build/lib/apetest2.com + TOOL_BUILD_LIB_A_OBJS = \ $(TOOL_BUILD_LIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \ - $(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o) + $(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o) \ + o/$(MODE)/tool/build/lib/apetest.com.zip.o \ + o/$(MODE)/tool/build/lib/apetest2.com.zip.o TOOL_BUILD_LIB_A_DIRECTDEPS = \ LIBC_ALG \ @@ -67,6 +75,25 @@ o/$(MODE)/tool/build/lib/ssefloat.o: \ TARGET_ARCH += \ -msse3 +o/$(MODE)/tool/build/lib/apetest.com.dbg: \ + $(TOOL_BUILD_LIB_A_DEPS) \ + o/$(MODE)/tool/build/lib/apetest.o \ + $(CRT) \ + $(APE_NO_MODIFY_SELF) + @$(APELINK) + +o/$(MODE)/tool/build/lib/apetest2.com.dbg: \ + $(TOOL_BUILD_LIB_A_DEPS) \ + o/$(MODE)/tool/build/lib/apetest.o \ + $(CRT) \ + $(APE_COPY_SELF) + @$(APELINK) + +o/$(MODE)/tool/build/lib/apetest.com.zip.o \ +o/$(MODE)/tool/build/lib/apetest2.com.zip.o: \ + ZIPOBJ_FLAGS += \ + -B + TOOL_BUILD_LIB_LIBS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x))) TOOL_BUILD_LIB_SRCS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_SRCS)) TOOL_BUILD_LIB_HDRS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_HDRS)) @@ -76,4 +103,6 @@ TOOL_BUILD_LIB_OBJS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_OBJS)) TOOL_BUILD_LIB_TESTS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_TESTS)) .PHONY: o/$(MODE)/tool/build/lib -o/$(MODE)/tool/build/lib: $(TOOL_BUILD_LIB_CHECKS) +o/$(MODE)/tool/build/lib: \ + $(TOOL_BUILD_LIB_COMS) \ + $(TOOL_BUILD_LIB_CHECKS) diff --git a/tool/build/lib/errnos.S b/tool/build/lib/errnos.S index d665d880e..7f09f1759 100644 --- a/tool/build/lib/errnos.S +++ b/tool/build/lib/errnos.S @@ -18,7 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" - .macro .errno local:req linux:req + .macro .e local:req linux:req .globl \local .long \local-kLinuxErrnos .byte \linux @@ -30,94 +30,94 @@ .rodata .align 4 kLinuxErrnos: - .errno EPERM,1 - .errno ENOENT,2 - .errno ESRCH,3 - .errno EINTR,4 - .errno EIO,5 - .errno ENXIO,6 - .errno E2BIG,7 - .errno ENOEXEC,8 - .errno EBADF,9 - .errno ECHILD,10 - .errno EAGAIN,11 - .errno ENOMEM,12 - .errno EACCES,13 - .errno EFAULT,14 - .errno ENOTBLK,15 - .errno EBUSY,16 - .errno EEXIST,17 - .errno EXDEV,18 - .errno ENODEV,19 - .errno ENOTDIR,20 - .errno EISDIR,21 - .errno EINVAL,22 - .errno ENFILE,23 - .errno EMFILE,24 - .errno ENOTTY,25 - .errno ETXTBSY,26 - .errno EFBIG,27 - .errno ENOSPC,28 - .errno ESPIPE,29 - .errno EROFS,30 - .errno EMLINK,31 - .errno EPIPE,32 - .errno EDOM,33 - .errno ERANGE,34 - .errno EDEADLK,35 - .errno ENAMETOOLONG,36 - .errno ENOLCK,37 - .errno ENOSYS,38 - .errno ENOTEMPTY,39 - .errno ELOOP,40 - .errno ENOMSG,42 - .errno EIDRM,43 - .errno EUSERS,87 - .errno ENOTSOCK,88 - .errno EDESTADDRREQ,89 - .errno EMSGSIZE,90 - .errno EPROTOTYPE,91 - .errno ENOPROTOOPT,92 - .errno EPROTONOSUPPORT,93 - .errno ESOCKTNOSUPPORT,94 - .errno EOPNOTSUPP,95 - .errno EPFNOSUPPORT,96 - .errno EAFNOSUPPORT,97 - .errno EADDRINUSE,98 - .errno EADDRNOTAVAIL,99 - .errno EL2NSYNC,45 - .errno EL3HLT,46 - .errno EL3RST,47 - .errno ELNRNG,48 - .errno ETIME,62 - .errno ENONET,64 - .errno EREMOTE,66 - .errno EPROTO,71 - .errno EBADMSG,74 - .errno EOVERFLOW,75 - .errno EILSEQ,84 - .errno ERESTART,85 - .errno ENETDOWN,100 - .errno ENETUNREACH,101 - .errno ENETRESET,102 - .errno ECONNABORTED,103 - .errno ECONNRESET,104 - .errno ENOBUFS,105 - .errno EISCONN,106 - .errno ENOTCONN,107 - .errno ESHUTDOWN,108 - .errno ETOOMANYREFS,109 - .errno ETIMEDOUT,110 - .errno ECONNREFUSED,111 - .errno EHOSTDOWN,112 - .errno EHOSTUNREACH,113 - .errno EALREADY,114 - .errno EINPROGRESS,115 - .errno ESTALE,116 - .errno EDQUOT,122 - .errno ECANCELED,125 - .errno EOWNERDEAD,130 - .errno ENOTRECOVERABLE,131 + .e EPERM,1 + .e ENOENT,2 + .e ESRCH,3 + .e EINTR,4 + .e EIO,5 + .e ENXIO,6 + .e E2BIG,7 + .e ENOEXEC,8 + .e EBADF,9 + .e ECHILD,10 + .e EAGAIN,11 + .e ENOMEM,12 + .e EACCES,13 + .e EFAULT,14 + .e ENOTBLK,15 + .e EBUSY,16 + .e EEXIST,17 + .e EXDEV,18 + .e ENODEV,19 + .e ENOTDIR,20 + .e EISDIR,21 + .e EINVAL,22 + .e ENFILE,23 + .e EMFILE,24 + .e ENOTTY,25 + .e ETXTBSY,26 + .e EFBIG,27 + .e ENOSPC,28 + .e ESPIPE,29 + .e EROFS,30 + .e EMLINK,31 + .e EPIPE,32 + .e EDOM,33 + .e ERANGE,34 + .e EDEADLK,35 + .e ENAMETOOLONG,36 + .e ENOLCK,37 + .e ENOSYS,38 + .e ENOTEMPTY,39 + .e ELOOP,40 + .e ENOMSG,42 + .e EIDRM,43 + .e EUSERS,87 + .e ENOTSOCK,88 + .e EDESTADDRREQ,89 + .e EMSGSIZE,90 + .e EPROTOTYPE,91 + .e ENOPROTOOPT,92 + .e EPROTONOSUPPORT,93 + .e ESOCKTNOSUPPORT,94 + .e EOPNOTSUPP,95 + .e EPFNOSUPPORT,96 + .e EAFNOSUPPORT,97 + .e EADDRINUSE,98 + .e EADDRNOTAVAIL,99 + .e EL2NSYNC,45 + .e EL3HLT,46 + .e EL3RST,47 + .e ELNRNG,48 + .e ETIME,62 + .e ENONET,64 + .e EREMOTE,66 + .e EPROTO,71 + .e EBADMSG,74 + .e EOVERFLOW,75 + .e EILSEQ,84 + .e ERESTART,85 + .e ENETDOWN,100 + .e ENETUNREACH,101 + .e ENETRESET,102 + .e ECONNABORTED,103 + .e ECONNRESET,104 + .e ENOBUFS,105 + .e EISCONN,106 + .e ENOTCONN,107 + .e ESHUTDOWN,108 + .e ETOOMANYREFS,109 + .e ETIMEDOUT,110 + .e ECONNREFUSED,111 + .e EHOSTDOWN,112 + .e EHOSTUNREACH,113 + .e EALREADY,114 + .e EINPROGRESS,115 + .e ESTALE,116 + .e EDQUOT,122 + .e ECANCELED,125 + .e EOWNERDEAD,130 + .e ENOTRECOVERABLE,131 .long 0 .byte 0 .endobj kLinuxErrnos,globl diff --git a/tool/build/lib/eztls.c b/tool/build/lib/eztls.c index dc6b6a35a..18093329a 100644 --- a/tool/build/lib/eztls.c +++ b/tool/build/lib/eztls.c @@ -29,6 +29,7 @@ #include "third_party/mbedtls/ctr_drbg.h" #include "third_party/mbedtls/ecp.h" #include "third_party/mbedtls/error.h" +#include "third_party/mbedtls/net_sockets.h" #include "third_party/mbedtls/platform.h" #include "third_party/mbedtls/ssl.h" #include "tool/build/lib/eztls.h" @@ -62,8 +63,11 @@ static ssize_t EzWritevAll(int fd, struct iovec *iov, int iovlen) { wrote = 0; } } while (wrote); - } else if (errno != EINTR) { - return total ? total : -1; + } else { + WARNF("writev() failed %m"); + if (errno != EINTR) { + return total ? total : -1; + } } } while (i < iovlen); return total; @@ -120,6 +124,7 @@ static int EzTlsRecvImpl(void *ctx, unsigned char *p, size_t n, uint32_t o) { v[1].iov_base = bio->t; v[1].iov_len = sizeof(bio->t); while ((r = readv(bio->fd, v, 2)) == -1) { + WARNF("tls read() error %s", strerror(errno)); if (errno == EINTR) { return MBEDTLS_ERR_SSL_WANT_READ; } else if (errno == EAGAIN) { @@ -127,7 +132,6 @@ static int EzTlsRecvImpl(void *ctx, unsigned char *p, size_t n, uint32_t o) { } else if (errno == EPIPE || errno == ECONNRESET || errno == ENETRESET) { return MBEDTLS_ERR_NET_CONN_RESET; } else { - WARNF("tls read() error %s", strerror(errno)); return MBEDTLS_ERR_NET_RECV_FAILED; } } diff --git a/tool/build/mkdeps.c b/tool/build/mkdeps.c index 0cf8faff9..a49b4cfc2 100644 --- a/tool/build/mkdeps.c +++ b/tool/build/mkdeps.c @@ -28,6 +28,7 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" +#include "libc/intrin/kprintf.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.internal.h" @@ -225,7 +226,7 @@ wontreturn void OnMissingFile(const char *list, const char *src) { * automatically restart itself. */ if (list) { - fprintf(stderr, "%s %s...\n", "Refreshing", list); + kprintf("%s %s...\n", "Refreshing", list); unlink(list); } exit(1); @@ -249,7 +250,9 @@ void LoadRelationships(int argc, char *argv[]) { while ((src = getargs_next(&ga))) { if (ShouldSkipSource(src)) continue; srcid = GetSourceId(src, strlen(src)); - if ((fd = open(src, O_RDONLY)) == -1) OnMissingFile(ga.path, src); + if ((fd = open(src, O_RDONLY)) == -1) { + OnMissingFile(ga.path, src); + } CHECK_NE(-1, (rc = read(fd, buf, MAX_READ))); close(fd); size = rc; @@ -282,13 +285,13 @@ void GetOpts(int argc, char *argv[]) { buildroot = optarg; break; default: - fprintf(stderr, "%s: %s [-r %s] [-o %s] [%s...]\n", "Usage", argv[0], + kprintf("%s: %s [-r %s] [-o %s] [%s...]\n", "Usage", argv[0], "BUILDROOT", "OUTPUT", "PATHSFILE"); exit(1); } } - if (isempty(out)) fprintf(stderr, "need -o FILE"), exit(1); - if (isempty(buildroot)) fprintf(stderr, "need -r o/$(MODE)"), exit(1); + if (isempty(out)) kprintf("need -o FILE"), exit(1); + if (isempty(buildroot)) kprintf("need -r o/$(MODE)"), exit(1); } const char *StripExt(const char *s) { @@ -311,6 +314,9 @@ bool IsObjectSource(const char *name) { for (i = 0; i < ARRAYLEN(kSourceExts); ++i) { if (endswith(name, kSourceExts[i])) return true; } + if (strstr(name, "/libcxx/")) { + return true; + } return false; } @@ -349,7 +355,7 @@ bool HasSameContent(void) { s = GetFileSizeOrZero(out); if (s == appendz(bout).i) { if (s) { - CHECK_NE(-1, (fd = open(out, O_RDONLY))); + CHECK_NE(-1, (fd = open(out, O_RDONLY)), "open(%#s)", out); CHECK_NE(MAP_FAILED, (m = mmap(0, s, PROT_READ, MAP_SHARED, fd, 0))); r = !bcmp(bout, m, s); munmap(m, s); @@ -391,7 +397,7 @@ int main(int argc, char *argv[]) { appendw(&bout, '\n'); } /* if (!fileexists(out) || !HasSameContent()) { */ - CHECK_NE(-1, (fd = open(out, O_CREAT | O_WRONLY, 0644))); + CHECK_NE(-1, (fd = open(out, O_CREAT | O_WRONLY, 0644)), "open(%#s)", out); CHECK_NE(-1, ftruncate(fd, appendz(bout).i)); CHECK_NE(-1, xwrite(fd, bout, appendz(bout).i)); CHECK_NE(-1, close(fd)); diff --git a/tool/build/mkdir.c b/tool/build/mkdir.c new file mode 100644 index 000000000..45b1d5bdc --- /dev/null +++ b/tool/build/mkdir.c @@ -0,0 +1,82 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/fmt/conv.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/ex.h" +#include "libc/x/x.h" +#include "third_party/getopt/getopt.h" + +#define USAGE \ + " [-p] [-m MODE] DIR...\n\ +Utility for creating directories.\n\ +\n\ +FLAGS\n\ +\n\ + -h Help\n\ + -m MODE Octal mode\n\ + -p Make parent directories\n" + +const char *prog; + +wontreturn void PrintUsage(int rc, FILE *f) { + fputs("Usage: ", f); + fputs(prog, f); + fputs(USAGE, f); + exit(rc); +} + +int main(int argc, char *argv[]) { + int i, mode = 0755; + int (*mkdirp)(const char *, unsigned) = mkdir; + prog = argc > 0 ? argv[0] : "mkdir.com"; + + while ((i = getopt(argc, argv, "?hpm:")) != -1) { + switch (i) { + case 'p': + mkdirp = makedirs; + break; + case 'm': + mode = strtol(optarg, 0, 8); + break; + case '?': + case 'h': + PrintUsage(0, stdout); + default: + PrintUsage(EX_USAGE, stderr); + } + } + + if (optind == argc) { + fputs(prog, stderr); + fputs(": missing argument\n", stderr); + fputs("Try '", stderr); + fputs(prog, stderr); + fputs(" -h' for more information.\n", stderr); + exit(1); + } + + for (i = optind; i < argc; ++i) { + if (mkdirp(argv[i], mode) == -1) { + fputs(prog, stderr); + fputs(": cannot create directory '", stderr); + fputs(argv[i], stderr); + fputs("' ", stderr); + fputs(strerdoc(errno), stderr); + fputc('\n', stderr); + exit(1); + } + } + + return 0; +} diff --git a/tool/build/pwd.c b/tool/build/pwd.c new file mode 100644 index 000000000..2b7f59f01 --- /dev/null +++ b/tool/build/pwd.c @@ -0,0 +1,37 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/stdio/stdio.h" + +/** + * @fileoverview Tool for printing current directory. + */ + +char path[PATH_MAX]; + +int main(int argc, char *argv[]) { + char *p; + if ((p = getcwd(path, sizeof(path)))) { + fputs(p, stdout); + fputc('\n', stdout); + return 0; + } else { + return 1; + } +} diff --git a/tool/build/rm.c b/tool/build/rm.c new file mode 100644 index 000000000..a3d808f19 --- /dev/null +++ b/tool/build/rm.c @@ -0,0 +1,103 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/errno.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/ex.h" +#include "libc/sysv/consts/exit.h" +#include "libc/sysv/consts/ok.h" +#include "third_party/getopt/getopt.h" + +#define USAGE \ + " FILE...\n\ +\n\ +SYNOPSIS\n\ +\n\ + Removes Files\n\ +\n\ +FLAGS\n\ +\n\ + -?\n\ + -h help\n\ + -f force\n\ +\n" + +bool force; +const char *prog; + +wontreturn void PrintUsage(int rc, FILE *f) { + fputs("usage: ", f); + fputs(prog, f); + fputs(USAGE, f); + exit(rc); +} + +void GetOpts(int argc, char *argv[]) { + int opt; + while ((opt = getopt(argc, argv, "?hf")) != -1) { + switch (opt) { + case 'f': + force = true; + break; + case 'h': + case '?': + PrintUsage(EXIT_SUCCESS, stdout); + default: + PrintUsage(EX_USAGE, stderr); + } + } +} + +void Remove(const char *path) { + const char *s; + if (!force && access(path, W_OK) == -1) goto OnFail; + if (unlink(path) == -1) goto OnFail; + return; +OnFail: + if (force && errno == ENOENT) return; + s = strerdoc(errno); + fputs(prog, stderr); + fputs(": cannot remove '", stderr); + fputs(path, stderr); + fputs("': ", stderr); + fputs(s, stderr); + fputs("\n", stderr); + exit(1); +} + +int main(int argc, char *argv[]) { + int i; + prog = argc > 0 ? argv[0] : "rm.com"; + + if (argc < 2) { + fputs(prog, stderr); + fputs(": missing operand\n" + "Try 'rm -h' for more information.\n", + stderr); + exit(1); + } + + GetOpts(argc, argv); + + for (i = optind; i < argc; ++i) { + Remove(argv[i]); + } +} diff --git a/tool/build/runit.c b/tool/build/runit.c index 60e9e905e..7ab830fed 100644 --- a/tool/build/runit.c +++ b/tool/build/runit.c @@ -30,6 +30,7 @@ #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.internal.h" +#include "libc/mem/mem.h" #include "libc/nexgen32e/crc32.h" #include "libc/runtime/gc.internal.h" #include "libc/runtime/runtime.h" @@ -50,7 +51,9 @@ #include "libc/time/time.h" #include "libc/x/x.h" #include "net/https/https.h" +#include "third_party/mbedtls/net_sockets.h" #include "third_party/mbedtls/ssl.h" +#include "third_party/zlib/zlib.h" #include "tool/build/lib/eztls.h" #include "tool/build/lib/psk.h" #include "tool/build/runit.h" @@ -110,6 +113,7 @@ static const struct addrinfo kResolvHints = {.ai_family = AF_INET, int g_sock; char *g_prog; +long g_backoff; char *g_runitd; jmp_buf g_jmpbuf; uint16_t g_sshport; @@ -306,7 +310,35 @@ TryAgain: freeaddrinfo(ai); } -void SendRequest(void) { +static bool Send(const void *output, size_t outputsize) { + int rc, have; + static bool once; + static z_stream zs; + static char zbuf[4096]; + if (!once) { + CHECK_EQ(Z_OK, deflateInit2(&zs, 4, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY)); + once = true; + } + zs.next_in = output; + zs.avail_in = outputsize; + do { + zs.avail_out = sizeof(zbuf); + zs.next_out = (unsigned char *)zbuf; + rc = deflate(&zs, Z_SYNC_FLUSH); + CHECK_NE(Z_STREAM_ERROR, rc); + have = sizeof(zbuf) - zs.avail_out; + rc = mbedtls_ssl_write(&ezssl, zbuf, have); + if (rc == MBEDTLS_ERR_NET_CONN_RESET) { + usleep((g_backoff = (g_backoff + 1000) * 2)); + return false; + } + CHECK_EQ(have, rc); + } while (!zs.avail_out); + return true; +} + +int SendRequest(void) { int fd; char *p; size_t i; @@ -316,7 +348,7 @@ void SendRequest(void) { const char *name; unsigned char *hdr, *q; size_t progsize, namesize, hdrsize; - DEBUGF("running %s on %s", g_prog, g_hostname); + unsigned have; CHECK_NE(-1, (fd = open(g_prog, O_RDONLY))); CHECK_NE(-1, fstat(fd, &st)); CHECK_NE(MAP_FAILED, (p = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0))); @@ -332,24 +364,31 @@ void SendRequest(void) { q = WRITE32BE(q, crc); q = mempcpy(q, name, namesize); assert(hdrsize == q - hdr); - CHECK_EQ(hdrsize, mbedtls_ssl_write(&ezssl, hdr, hdrsize)); - for (i = 0; i < progsize; i += rc) { - CHECK_GT((rc = mbedtls_ssl_write(&ezssl, p + i, progsize - i)), 0); + DEBUGF("running %s on %s", g_prog, g_hostname); + if (Send(hdr, hdrsize) && Send(p, progsize)) { + if (!(rc = EzTlsFlush(&ezbio, 0, 0))) { + rc = 0; + } else if (rc == MBEDTLS_ERR_NET_CONN_RESET) { + rc = -1; + } else { + CHECK_EQ(0, rc); + } + } else { + rc = -1; } - CHECK_EQ(0, EzTlsFlush(&ezbio, 0, 0)); CHECK_NE(-1, munmap(p, st.st_size)); CHECK_NE(-1, close(fd)); + return rc; } bool Recv(unsigned char *p, size_t n) { size_t i, rc; - static long backoff; for (i = 0; i < n; i += rc) { do { rc = mbedtls_ssl_read(&ezssl, p + i, n - i); } while (rc == MBEDTLS_ERR_SSL_WANT_READ); if (!rc || rc == MBEDTLS_ERR_NET_CONN_RESET) { - usleep((backoff = (backoff + 1000) * 2)); + usleep((g_backoff = (g_backoff + 1000) * 2)); return false; } else if (rc < 0) { TlsDie("read response failed", rc); @@ -419,8 +458,7 @@ int RunOnHost(char *spec) { WARNF("warning: got connection reset in handshake"); close(g_sock); } - SendRequest(); - } while ((rc = ReadResponse()) == -1); + } while ((rc = SendRequest()) == -1 || (rc = ReadResponse()) == -1); return rc; } diff --git a/tool/build/runitd.c b/tool/build/runitd.c index 71d4bb3c6..0d0d54cee 100644 --- a/tool/build/runitd.c +++ b/tool/build/runitd.c @@ -42,6 +42,7 @@ #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sock.h" #include "libc/sysv/consts/sol.h" @@ -51,6 +52,7 @@ #include "net/https/https.h" #include "third_party/getopt/getopt.h" #include "third_party/mbedtls/ssl.h" +#include "third_party/zlib/zlib.h" #include "tool/build/lib/eztls.h" #include "tool/build/lib/psk.h" #include "tool/build/runit.h" @@ -109,7 +111,12 @@ void OnInterrupt(int sig) { void OnChildTerminated(int sig) { int ws, pid; + sigset_t ss, oldss; + sigfillset(&ss); + sigdelset(&ss, SIGTERM); + sigprocmask(SIG_BLOCK, &ss, &oldss); for (;;) { + INFOF("waitpid"); if ((pid = waitpid(-1, &ws, WNOHANG)) != -1) { if (pid) { if (WIFEXITED(ws)) { @@ -126,6 +133,7 @@ void OnChildTerminated(int sig) { FATALF("waitpid failed in sigchld"); } } + sigprocmask(SIG_SETMASK, &oldss, 0); } wontreturn void ShowUsage(FILE *f, int rc) { @@ -228,6 +236,7 @@ void SendExitMessage(int rc) { msg[0 + 3] = (RUNITD_MAGIC & 0x000000ff) >> 000; msg[4] = kRunitExit; msg[5] = rc; + INFOF("mbedtls_ssl_write"); CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg))); CHECK_EQ(0, EzTlsFlush(&ezbio, 0, 0)); } @@ -246,6 +255,7 @@ void SendOutputFragmentMessage(enum RunitCommand kind, unsigned char *buf, msg[5 + 1] = (size & 0x00ff0000) >> 020; msg[5 + 2] = (size & 0x0000ff00) >> 010; msg[5 + 3] = (size & 0x000000ff) >> 000; + INFOF("mbedtls_ssl_write"); CHECK_EQ(sizeof(msg), mbedtls_ssl_write(&ezssl, msg, sizeof(msg))); while (size) { CHECK_NE(-1, (rc = mbedtls_ssl_write(&ezssl, buf, size))); @@ -256,16 +266,80 @@ void SendOutputFragmentMessage(enum RunitCommand kind, unsigned char *buf, CHECK_EQ(0, EzTlsFlush(&ezbio, 0, 0)); } -void Recv(void *p, size_t n) { - size_t i, rc; - for (i = 0; i < n; i += rc) { - do { - rc = mbedtls_ssl_read(&ezssl, (char *)p + i, n - i); - DEBUGF("read(%ld)", rc); - } while (rc == MBEDTLS_ERR_SSL_WANT_READ); - if (rc <= 0) TlsDie("read failed", rc); +void Recv(void *output, size_t outputsize) { + int rc; + ssize_t tx, chunk, received; + static bool once; + static int zstatus; + static char buf[4096]; + static z_stream zs; + static struct { + size_t off; + size_t len; + size_t cap; + char *data; + } rbuf; + if (!once) { + CHECK_EQ(Z_OK, inflateInit(&zs)); + once = true; + } + for (;;) { + if (rbuf.len >= outputsize) { + tx = MIN(outputsize, rbuf.len); + memcpy(output, rbuf.data + rbuf.off, outputsize); + rbuf.len -= outputsize; + rbuf.off += outputsize; + // trim dymanic buffer once it empties + if (!rbuf.len) { + rbuf.off = 0; + rbuf.cap = 4096; + rbuf.data = realloc(rbuf.data, rbuf.cap); + } + return; + } + if (zstatus == Z_STREAM_END) { + FATALF("recv zlib unexpected eof"); + } + // get another fixed-size data packet from network + // pass along error conditions to caller + // pass along eof condition to zlib + INFOF("mbedtls_ssl_read"); + received = mbedtls_ssl_read(&ezssl, buf, sizeof(buf)); + if (!received) TlsDie("got unexpected eof", received); + if (received < 0) TlsDie("read failed", received); + // decompress packet completely + // into a dynamical size buffer + zs.avail_in = received; + zs.next_in = (unsigned char *)buf; + CHECK_EQ(Z_OK, zstatus); + do { + // make sure we have a reasonable capacity for zlib output + if (rbuf.cap - (rbuf.off + rbuf.len) < sizeof(buf)) { + rbuf.cap += sizeof(buf); + rbuf.data = realloc(rbuf.data, rbuf.cap); + } + // inflate packet, which naturally can be much larger + // permit zlib no delay flushes that come from sender + zs.next_out = (unsigned char *)rbuf.data + (rbuf.off + rbuf.len); + zs.avail_out = chunk = rbuf.cap - (rbuf.off + rbuf.len); + zstatus = inflate(&zs, Z_SYNC_FLUSH); + CHECK_NE(Z_STREAM_ERROR, zstatus); + switch (zstatus) { + case Z_NEED_DICT: + zstatus = Z_DATA_ERROR; // make negative + // fallthrough + case Z_DATA_ERROR: + case Z_MEM_ERROR: + FATALF("tls recv zlib hard error %d", zstatus); + case Z_BUF_ERROR: + zstatus = Z_OK; // harmless? nothing for inflate to do + break; // it probably just our wraparound eof + default: + rbuf.len += chunk - zs.avail_out; + break; + } + } while (!zs.avail_out); } - DEBUGF("Recv(%ld)", n); } void HandleClient(void) { @@ -284,15 +358,18 @@ void HandleClient(void) { /* read request to run program */ addrsize = sizeof(addr); + INFOF("accept"); CHECK_NE(-1, (g_clifd = accept4(g_servfd, &addr, &addrsize, SOCK_CLOEXEC))); if (fork()) { close(g_clifd); return; } EzFd(g_clifd); + INFOF("EzHandshake"); EzHandshake(); addrstr = gc(DescribeAddress(&addr)); DEBUGF("%s %s %s", gc(DescribeAddress(&g_servaddr)), "accepted", addrstr); + Recv(msg, sizeof(msg)); CHECK_EQ(RUNITD_MAGIC, READ32BE(msg)); CHECK_EQ(kRunitExecute, msg[4]); @@ -312,6 +389,7 @@ void HandleClient(void) { } CHECK_NE(-1, (g_exefd = creat(g_exepath, 0700))); LOGIFNEG1(ftruncate(g_exefd, filesize)); + INFOF("xwrite"); CHECK_NE(-1, xwrite(g_exefd, exe, filesize)); LOGIFNEG1(close(g_exefd)); @@ -361,6 +439,7 @@ void HandleClient(void) { fds[0].events = POLLIN; fds[1].fd = pipefds[0]; fds[1].events = POLLIN; + INFOF("poll"); events = poll(fds, ARRAYLEN(fds), (deadline - now) * 1000); CHECK_NE(-1, events); // EINTR shouldn't be possible if (fds[0].revents) { @@ -368,7 +447,7 @@ void HandleClient(void) { WARNF("%s got unexpected input event from client %#x", exename, fds[0].revents); } - WARNF("%s client disconnected so killing worker", exename); + WARNF("%s client disconnected so killing worker %d", exename, child); LOGIFNEG1(kill(child, 9)); LOGIFNEG1(waitpid(child, 0, 0)); LOGIFNEG1(close(g_clifd)); @@ -376,6 +455,7 @@ void HandleClient(void) { LOGIFNEG1(unlink(g_exepath)); _exit(1); } + INFOF("read"); got = read(pipefds[0], g_buf, sizeof(g_buf)); CHECK_NE(-1, got); // EINTR shouldn't be possible if (!got) { @@ -385,6 +465,7 @@ void HandleClient(void) { fwrite(g_buf, got, 1, stderr); SendOutputFragmentMessage(kRunitStderr, g_buf, got); } + INFOF("waitpid"); CHECK_NE(-1, waitpid(child, &wstatus, 0)); // EINTR shouldn't be possible if (WIFEXITED(wstatus)) { if (WEXITSTATUS(wstatus)) { @@ -399,6 +480,7 @@ void HandleClient(void) { } LOGIFNEG1(unlink(g_exepath)); SendExitMessage(exitcode); + INFOF("mbedtls_ssl_close_notify"); mbedtls_ssl_close_notify(&ezssl); LOGIFNEG1(close(g_clifd)); _exit(0); @@ -459,9 +541,8 @@ void Daemonize(void) { int main(int argc, char *argv[]) { int i; - ShowCrashReports(); SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER, GetRunitPsk()); - /* __log_level = kLogDebug; */ + __log_level = kLogInfo; GetOpts(argc, argv); for (i = 3; i < 16; ++i) close(i); errno = 0; diff --git a/libc/sock/stdinworker.c b/tool/build/touch.c similarity index 76% rename from libc/sock/stdinworker.c rename to tool/build/touch.c index 0dc32fe94..f9be6e8b7 100644 --- a/libc/sock/stdinworker.c +++ b/tool/build/touch.c @@ -16,29 +16,31 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" -#include "libc/calls/strace.internal.h" +#include "libc/calls/calls.h" +#include "libc/errno.h" #include "libc/runtime/runtime.h" -#include "libc/sock/ntstdin.internal.h" -#include "libc/sock/sock.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" -/* STATIC_YOINK("StdinWorker"); */ +/** + * @fileoverview Command for updating timestamps on files. + */ -static textexit void StdinWorkerFree(void) { +int main(int argc, char *argv[]) { int i; - NTTRACE("StdinWorkerFree()"); - for (i = g_fds.n; i--;) { - if (g_fds.p[i].kind && g_fds.p[i].worker) { - close(i); + const char *s, *prog; + prog = argc > 0 ? argv[0] : "touch.com"; + for (i = 1; i < argc; ++i) { + if (touch(argv[i], 0666) == -1) { + s = strerdoc(errno); + fputs(prog, stderr); + fputs(": cannot touch '", stderr); + fputs(argv[i], stderr); + fputs("': ", stderr); + fputs(s, stderr); + fputs("\n", stderr); + exit(1); } } + return 0; } - -static textstartup void StdinWorkerInit(void) { - g_fds.p[0].worker = NewNtStdinWorker(0); - atexit(StdinWorkerFree); -} - -const void *const StdinWorker[] initarray = { - StdinWorkerInit, -}; diff --git a/tool/build/unbundle.c b/tool/build/unbundle.c new file mode 100644 index 000000000..7614af4ac --- /dev/null +++ b/tool/build/unbundle.c @@ -0,0 +1,89 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/struct/stat.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/fmt/itoa.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/x/x.h" +#include "third_party/musl/ftw.h" + +const char *prog; +char tmpdir[PATH_MAX]; +char binpath[PATH_MAX]; + +bool IsDirectory(const char *path) { + int e; + bool res; + struct stat st; + e = errno; + res = stat(path, &st) != -1 && S_ISDIR(st.st_mode); + errno = e; + return res; +} + +void Execute(char *argv[]) { + int ws; + if (!vfork()) { + execv(argv[0], argv); + _Exit(127); + } + wait(&ws); + if (!WIFEXITED(ws) || WEXITSTATUS(ws)) { + fputs(argv[0], stderr); + fputs(": command failed\n", stderr); + exit(1); + } +} + +int Visit(const char *fpath, const struct stat *sb, int tflag, + struct FTW *ftwbuf) { + if (tflag == FTW_F && endswith(fpath, ".gz")) { + Execute((char *[]){"build/bootstrap/gzip.com", "-d", fpath, 0}); + strcpy(binpath, fpath); + binpath[strlen(binpath) - 3] = 0; + chmod(binpath, 0755); + } else if (tflag == FTW_F && endswith(fpath, ".sym")) { + strcpy(binpath, fpath); + binpath[strlen(binpath) - 4] = 0; + symlink(xslurp(fpath, 0), binpath); + } + return 0; +} + +int main(int argc, char *argv[]) { + if (!IsLinux()) return 0; + prog = argc > 0 ? argv[0] : "unbundle.com"; + if (IsDirectory("o/third_party/gcc")) return 0; + makedirs("o/third_party", 0755); + FormatInt32(stpcpy(tmpdir, "o/third_party/gcc."), getpid()); + Execute( + (char *[]){"build/bootstrap/cp.com", "-r", "third_party/gcc", tmpdir, 0}); + if (nftw(tmpdir, Visit, 20, 0) == -1) { + fputs(prog, stderr); + fputs(": nftw failed: ", stderr); + fputs(strerdoc(errno), stderr); + fputs("\n", stderr); + exit(1); + } + rename(tmpdir, "o/third_party/gcc"); +} diff --git a/tool/build/zipobj.c b/tool/build/zipobj.c index bdaa29025..1d92c2c1f 100644 --- a/tool/build/zipobj.c +++ b/tool/build/zipobj.c @@ -20,6 +20,7 @@ #include "libc/calls/struct/stat.h" #include "libc/elf/def.h" #include "libc/fmt/conv.h" +#include "libc/intrin/kprintf.h" #include "libc/limits.h" #include "libc/log/check.h" #include "libc/log/log.h" @@ -51,8 +52,8 @@ const char *path_prefix_; struct timespec timestamp; size_t kZipCdirHdrLinkableSizeBootstrap; -wontreturn void PrintUsage(int rc, FILE *f) { - fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name, +wontreturn void PrintUsage(int rc) { + kprintf("%s%s%s\n", "Usage: ", program_invocation_name, " [-n] [-B] [-C INT] [-P PREFIX] [-o FILE] [-s SYMBOL] [-y YOINK] " "[FILE...]"); exit(rc); @@ -99,9 +100,9 @@ void GetOpts(int *argc, char ***argv) { break; case '?': case 'h': - PrintUsage(EXIT_SUCCESS, stdout); + PrintUsage(EXIT_SUCCESS); default: - PrintUsage(EX_USAGE, stderr); + PrintUsage(EX_USAGE); } } *argc -= optind; @@ -137,7 +138,7 @@ void ProcessFile(struct ElfWriter *elf, const char *path) { if (S_ISDIR(st.st_mode)) { st.st_size = 0; if (!endswith(name, "/")) { - name = gc(xasprintf("%s/", name)); + name = gc(xstrcat(name, '/')); } } elfwriter_zip(elf, name, name, strlen(name), map, st.st_size, st.st_mode, diff --git a/tool/decode/ar.c b/tool/decode/ar.c index f27f3b983..1066ef70a 100644 --- a/tool/decode/ar.c +++ b/tool/decode/ar.c @@ -20,6 +20,7 @@ #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" #include "libc/fmt/conv.h" +#include "libc/intrin/kprintf.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/mem/mem.h" @@ -50,7 +51,7 @@ static void PrintString(uint8_t *p, long n, const char *name) { s = xmalloc(n + 1); s[n] = '\0'; memcpy(s, p, n); - printf("\t.ascii\t%`'.*s\t\t\t# %s\n", n, s, name); + printf("\t.ascii\t%-`'*.*s# %s\n", 35, n, s, name); free(s); } @@ -94,8 +95,8 @@ static void PrintHeader(uint8_t *p) { static void Print(void) { int arsize; - uint8_t *b, *p; uint64_t offset; + uint8_t *b, *p, *e; uint32_t i, n, o, table, entries, symbols, symbolslen; arsize = atoi((char *)(data + 8 + 48)); CHECK_LE(4, arsize); @@ -107,18 +108,19 @@ static void Print(void) { PrintHeader(data + 8); printf("\n"); - printf("\t.long\t%u\t\t\t# %s\n", entries, "symbol table entries"); + printf("\t.long\t%-*.u# %s\n", 35, entries, "symbol table entries"); table = 8 + 60 + 4; for (i = 0; i < entries; ++i) { - printf("\t.long\t%#x\t\t\t\t# %u\n", READ32BE(data + table + i * 4), i); + printf("\t.long\t%#-*.x# %u\n", 35, READ32BE(data + table + i * 4), i); } symbols = table + entries * 4; - symbolslen = arsize - (4 + entries * 4); + symbolslen = arsize - (entries + 1) * 4; for (i = o = 0; o < symbolslen; ++i, o += n + 1) { b = data + symbols + o; - CHECK_NOTNULL((p = memchr(b, '\0', symbolslen - (symbols + o)))); + CHECK_NOTNULL((p = memchr(b, '\0', symbolslen - o)), "%p %p %p %p %`.s", b, + data, symbols, o, b); n = p - b; - printf("\t.asciz\t%#`'.*s\t\t\t# %u\n", n, b, i); + printf("\t.asciz\t%#-`'*.*s# %u\n", 35, n, b, i); } offset = 8 + 60 + arsize; diff --git a/tool/decode/decode.mk b/tool/decode/decode.mk index 6ecf4d2e0..997b22a79 100644 --- a/tool/decode/decode.mk +++ b/tool/decode/decode.mk @@ -56,7 +56,7 @@ o/$(MODE)/tool/decode/%.com.dbg: \ o/$(MODE)/tool/decode/%.o \ o/$(MODE)/tool/decode/decode.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TOOL_DECODE_OBJS): \ diff --git a/tool/decode/elf.c b/tool/decode/elf.c index 4a6a4b6e3..82262c124 100644 --- a/tool/decode/elf.c +++ b/tool/decode/elf.c @@ -157,7 +157,8 @@ static void printelfsectionheader(int i, char *shstrtab) { static void printelfsectionheaders(void) { Elf64_Half i; - char *shstrtab = GetElfSectionNameStringTable(elf, st->st_size); + char *shstrtab; + shstrtab = GetElfSectionNameStringTable(elf, st->st_size); if (shstrtab) { printf("\n"); printf("\t.org\t%#x\n", elf->e_shoff); @@ -341,7 +342,6 @@ int main(int argc, char *argv[]) { fprintf(stderr, "error: not an elf executable: %'s\n", path); exit(1); } - elf = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR); startfile(); printelfehdr(); printelfsegmentheaders(); diff --git a/tool/decode/zip.c b/tool/decode/zip.c index 69acdc2c6..c735143b3 100644 --- a/tool/decode/zip.c +++ b/tool/decode/zip.c @@ -57,7 +57,6 @@ dontdiscard char *FormatDosTime(uint16_t dostime) { } void AdvancePosition(uint8_t *map, size_t *pos, size_t off) { - CHECK_GE(off, *pos); if (off > *pos) { printf("\n/\t<%s>\n", "LIMBO"); disassemblehex(&map[*pos], off - *pos, stdout); diff --git a/tool/emacs/cosmo-asm-mode.el b/tool/emacs/cosmo-asm-mode.el index 0ff490313..c96524f61 100644 --- a/tool/emacs/cosmo-asm-mode.el +++ b/tool/emacs/cosmo-asm-mode.el @@ -108,6 +108,7 @@ "protip" "nxbitsafe" "vforksafe" + "threadsafe" "preinitsafe" "asyncsignalsafe" "notasyncsignalsafe" diff --git a/tool/emacs/cosmo-c-keywords.el b/tool/emacs/cosmo-c-keywords.el index 441b7c977..11ee51b9f 100644 --- a/tool/emacs/cosmo-c-keywords.el +++ b/tool/emacs/cosmo-c-keywords.el @@ -99,7 +99,8 @@ "_Vector_size")) (gnu - '("__inline" + '("__extension__" + "__inline" "__thread" "__alignof" "__typeof" diff --git a/tool/emacs/cosmo-stuff.el b/tool/emacs/cosmo-stuff.el index c47eb24ab..30c9d8f48 100644 --- a/tool/emacs/cosmo-stuff.el +++ b/tool/emacs/cosmo-stuff.el @@ -213,6 +213,15 @@ "scp $f $f.dbg win10:" "ssh win10 ./%s.com")) mode name (file-name-nondirectory name))) + ((eq kind 'run-xnu) + (format + (cosmo-join + " && " + `("m=%s; f=o/$m/%s.com" + ,(concat "make -j12 -O $f MODE=$m") + "scp $f $f.dbg xnu:" + "ssh xnu ./%s.com")) + mode name (file-name-nondirectory name))) ((and (equal suffix "") (cosmo-contains "_test." (buffer-file-name))) (format "m=%s; make -j12 -O MODE=$m %s" diff --git a/tool/hash/hash.mk b/tool/hash/hash.mk index 2e7c4628b..456c76c9f 100644 --- a/tool/hash/hash.mk +++ b/tool/hash/hash.mk @@ -37,7 +37,7 @@ o/$(MODE)/tool/hash/%.com.dbg: \ o/$(MODE)/tool/hash/%.o \ o/$(MODE)/tool/hash/hash.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) $(TOOL_HASH_OBJS): \ diff --git a/tool/lambda/lambda.mk b/tool/lambda/lambda.mk index c8cfdcc49..c7ede2705 100644 --- a/tool/lambda/lambda.mk +++ b/tool/lambda/lambda.mk @@ -44,7 +44,7 @@ o/$(MODE)/tool/lambda/%.com.dbg: \ o/$(MODE)/tool/lambda/%.o \ o/$(MODE)/tool/lambda/lambda.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/lambda/tromp.o: \ diff --git a/tool/net/counters.inc b/tool/net/counters.inc index 96b3579a0..4f55e94f8 100644 --- a/tool/net/counters.inc +++ b/tool/net/counters.inc @@ -1,4 +1,5 @@ C(accepterrors) +C(acceptflakes) C(acceptinterrupts) C(acceptresets) C(badlengths) @@ -74,6 +75,7 @@ C(sslunknownca) C(sslunknowncert) C(sslupgrades) C(sslverifyfailed) +C(stackuse) C(statfails) C(staticrequests) C(stats) diff --git a/tool/net/help.txt b/tool/net/help.txt index 1c74ead80..dd5430e40 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -54,6 +54,7 @@ FLAGS -Z log worker system calls -f log worker function calls -B only use stronger cryptography + -X disable ssl server and client support -s increase silence [repeatable] -v increase verbosity [repeatable] -V increase ssl verbosity [repeatable] @@ -224,10 +225,16 @@ USAGE Your redbean is an actually portable executable, that's able to run on six different operating systems. To do that, it needs to - overwrite its own MZ header at startup, with ELF or Mach-O, and - then puts the original back once the program loads. If you want - your redbean to follow the platform-local executable convention - then delete the /.ape file from zip. + extract a 4kb loader program to ${TMPDIR:-/tmp}/ape that'll map + your redbean into memory. It does however check to see if `ape` + is on the system path beforehand. You can also "assimilate" any + redbean into the platform-local executable format by running: + + $ file redbean.com + redbean.com: DOS/MBR boot sector + $ ./redbean.com --assimilate + $ file redbean.com + redbean.com: ELF 64-bit LSB executable redbean contains software licensed ISC, MIT, BSD-2, BSD-3, zlib which makes it a permissively licensed gift to anyone who might @@ -330,18 +337,22 @@ REPL #!/usr/bin/redbean -i print('hello world') - However operating systems like Linux usually require that script - interperters be in the local executable format. You can "assimilate" - and install your redbean using the following commands: + However UNIX operating systems usually require that interperters be + encoded in its preferred executable format. You can assimilate your + redbean into the local format using the following commands: - zip -d redbean.com .ape # remove the ape header - ./redbean.com -h >/dev/null # assimilate the binary - sudo cp redbean.com /usr/bin/redbean + $ file redbean.com + redbean.com: DOS/MBR boot sector + $ ./redbean.com --assimilate + $ file redbean.com + redbean.com: ELF 64-bit LSB executable + $ sudo cp redbean.com /usr/bin/redbean By following the above steps, redbean can be installed systemwide for multiple user accounts. It's also possible to chmod the binary to have - setuid privileges, provided it's configured to drop privileges in the - most appropriate manner; see the UNIX section for further details. + setuid privileges. Please note that, if you do this, the UNIX section + provides further details on APIs like `unix.setuid` that will help you + remove root privileges from the process in the appropriate manner. ──────────────────────────────────────────────────────────────────────────────── @@ -1308,6 +1319,57 @@ FUNCTIONS the density of information. Cryptographic random should be in the ballpark of 7.9 whereas plaintext will be more like 4.5. + Compress(uncompdata:str[, level:int[, raw:bool]]) → compdata:str + + Compresses data using DEFLATE algorithm. The compression + format here is defined to be quick and handy for things like + database fields. For example: + + >: Compress('hello') + "\x05\x86\xa6\x106x\x9c\xcbH\xcd\xc9\xc9\x07\x00\x06,\x02\x15" + >: Uncompress(Compress('hello')) + "hello" + + The binary wire format is defined as follows: + + 1. uleb64 uncompressed byte size (1 to 10 bytes) + 2. uint32_t crc32 (4 bytes; zlib polynomial) + 3. data (created by zlib compress function) + + `level` is the compression level, which defaults to 7. The max + is 10. Lower numbers go faster. Higher numbers go slower, but + have better compression ratios. + + `raw` may be set to true if you only want `data` (3) to be + returned. In this case, it's assumed the caller will take + responsibility for storing the length (and optionall crc) + separately. See the redbean Crc32() API. + + >: a = 'hello' + >: b = Compress(a, 9, true) + >: Uncompress(b, #a) + "hello" + + Uncompress(compdata:str[, uncomplen:int]) → uncompdata:str + + Uncompresses data using DEFLATE algorithm. This applies the + inverse transform of the Compress() function. See its docs for + further details on usage and encoding. + + This function throws exceptions in the event that the value + couldn't be decoded. There's a crc32 check to make our check + of validity iron-clad. It's implemented using Intel CLMUL so + it has ludicrous speed performance as well. + + If you used the `raw` parameter when calling Compress() i.e. + `compdata` doesn't have the redbean header described above, + then the `uncomplen` parameter may be supplied. IN that case + your data is handed over directly to zlib `uncompress()`. In + this case an exception will be raised if the value couldn't be + decoded, or if the resulting length differed from the supplied + length. It's recommended that Crc32() check still be performed + manually after using this method. + Benchmark(func[, count[, maxattempts]]) └─→ nanos:real, ticks:int, overhead-ticks:int, tries:int @@ -1726,7 +1788,7 @@ UNIX MODULE Creates fifo which enables communication between processes. - `flags` can have any of + `flags` may have any combination (using bitwise OR) of: - `O_CLOEXEC`: Automatically close file descriptor upon execve() @@ -1929,13 +1991,15 @@ UNIX MODULE Makes directories. + Unlike mkdir() this convenience wrapper will automatically create + parent parent directories as needed. If the directory already exists + then, unlike mkdir() which returns EEXIST, the makedirs() function + will return success. + `path` is the path of the directory you wish to create. `mode` is octal permission bits, e.g. `0755`. - Unlike mkdir() this convenience wrapper will automatically create - parent parent directories as needed. - unix.chdir(path:str) ├─→ true └─→ nil, unix.Errno @@ -2328,7 +2392,7 @@ UNIX MODULE - `SOCK_RDM` - `SOCK_SEQPACKET` - You may bitwise or any of the following into `type`: + You may bitwise OR any of the following into `type`: - `SOCK_CLOEXEC` - `SOCK_NONBLOCK` @@ -2355,7 +2419,7 @@ UNIX MODULE - `SOCK_DGRAM` - `SOCK_SEQPACKET` - You may bitwise or any of the following into `type`: + You may bitwise OR any of the following into `type`: - `SOCK_CLOEXEC` - `SOCK_NONBLOCK` @@ -2484,7 +2548,7 @@ UNIX MODULE Returns `EINVAL` if settings other than the above are used. - Returns `ENOSYS` if setting isn't supported by the host o/s. + Returns `ENOSYS` if setting isn't supported by the host OS. unix.poll({[fd:int]=events:int, ...}[, timeoutms:int]) ├─→ {[fd:int]=revents:int, ...} @@ -2519,7 +2583,7 @@ UNIX MODULE Accepts new client socket descriptor for a listening tcp socket. - `flags` can have any of: + `flags` may have any combination (using bitwise OR) of: - `SOCK_CLOEXEC` - `SOCK_NONBLOCK` @@ -2550,7 +2614,7 @@ UNIX MODULE ├─→ data:str └─→ nil, unix.Errno - `flags` can have: + `flags` may have any combination (using bitwise OR) of: - `MSG_WAITALL` - `MSG_DONTROUTE` @@ -2561,7 +2625,7 @@ UNIX MODULE ├─→ data:str, ip:uint32, port:uint16 └─→ nil, unix.Errno - `flags` can have: + `flags` may have any combination (using bitwise OR) of: - `MSG_WAITALL` - `MSG_DONTROUTE` @@ -2575,7 +2639,7 @@ UNIX MODULE This is the same as `write` except it has a `flags` argument that's intended for sockets. - `flags` may have any of: + `flags` may have any combination (using bitwise OR) of: - `MSG_OOB` - `MSG_DONTROUTE` @@ -2588,7 +2652,7 @@ UNIX MODULE This is useful for sending messages over UDP sockets to specific addresses. - `flags` may have any of: + `flags` may have any combination (using bitwise OR) of: - `MSG_OOB` - `MSG_DONTROUTE` @@ -2617,7 +2681,7 @@ UNIX MODULE `how` can be one of: - - `SIG_BLOCK`: bitwise ors `mask` into set of blocked signals + - `SIG_BLOCK`: applies `mask` to set of blocked signals using bitwise OR - `SIG_UNBLOCK`: removes bits in `mask` from set of blocked signals - `SIG_SETMASK`: replaces process signal mask with `mask` @@ -2737,6 +2801,9 @@ UNIX MODULE unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND) unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0) + `intns` needs to be on the interval `[0,1000000000)` + `valuens` needs to be on the interval `[0,1000000000)` + unix.strsignal(sig:int) → str Turns platform-specific `sig` code into its symbolic name. @@ -2766,11 +2833,11 @@ UNIX MODULE - `RLIMIT_CPU` causes `SIGXCPU` to be sent to the process when the soft limit on CPU time is exceeded, and the process is destroyed when the hard limit is exceeded. It works everywhere but Windows - where it should be possible to poll getrusage() with setitimer() + where it should be possible to poll getrusage() with setitimer(). - `RLIMIT_FSIZE` causes `SIGXFSZ` to sent to the process when the soft limit on file size is exceeded and the process is destroyed - when the hard limit is exceeded. It works everywhere but Windows + when the hard limit is exceeded. It works everywhere but Windows. - `RLIMIT_NPROC` limits the number of simultaneous processes and it should work on all platforms except Windows. Please be advised it @@ -2778,7 +2845,7 @@ UNIX MODULE as a whole. - `RLIMIT_NOFILE` limits the number of open file descriptors and it - should work on all platforms except Windows (TODO) + should work on all platforms except Windows (TODO). If a limit isn't supported by the host platform, it'll be set to 127. On most platforms these limits are enforced by the kernel and diff --git a/tool/net/lfuncs.c b/tool/net/lfuncs.c index 503fb899f..74a4f989c 100644 --- a/tool/net/lfuncs.c +++ b/tool/net/lfuncs.c @@ -17,10 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "dsp/scale/cdecimate2xuint8x8.h" +#include "libc/bits/bits.h" #include "libc/bits/popcnt.h" #include "libc/calls/calls.h" #include "libc/calls/struct/rusage.h" #include "libc/fmt/itoa.h" +#include "libc/fmt/leb128.h" #include "libc/intrin/kprintf.h" #include "libc/log/check.h" #include "libc/log/log.h" @@ -55,6 +57,7 @@ #include "third_party/mbedtls/sha1.h" #include "third_party/mbedtls/sha256.h" #include "third_party/mbedtls/sha512.h" +#include "third_party/zlib/zlib.h" #include "tool/net/lfuncs.h" static int Rdpid(void) { @@ -155,7 +158,7 @@ int LuaDecimate(lua_State *L) { unsigned char *p; s = luaL_checklstring(L, 1, &n); m = ROUNDUP(n, 16); - p = xmalloc(m); + CHECK_NOTNULL((p = LuaAlloc(L, m))); bzero(p + n, m - n); cDecimate2xUint8x8(m, p, (signed char[8]){-1, -3, 3, 17, 17, 3, -3, -1}); lua_pushlstring(L, (char *)p, (n + 1) >> 1); @@ -405,7 +408,7 @@ int LuaGetRandomBytes(lua_State *L) { luaL_argerror(L, 1, "not in range 1..256"); unreachable; } - p = xmalloc(n); + CHECK_NOTNULL((p = LuaAlloc(L, n))); CHECK_EQ(n, getrandom(p, n, 0)); lua_pushlstring(L, p, n); free(p); @@ -678,3 +681,69 @@ int LuaBenchmark(lua_State *L) { lua_pushinteger(L, attempts); return 4; } + +int LuaCompress(lua_State *L) { + bool raw; + size_t n, m; + char *q, *e; + uint32_t crc; + const char *p; + int level, hdrlen; + p = luaL_checklstring(L, 1, &n); + level = luaL_optinteger(L, 2, Z_DEFAULT_COMPRESSION); + m = compressBound(n); + if (lua_toboolean(L, 3)) { + // raw mode + CHECK_NOTNULL((q = LuaAlloc(L, m))); + CHECK_EQ(Z_OK, + compress2((unsigned char *)q, &m, (unsigned char *)p, n, level)); + lua_pushlstring(L, q, m); + } else { + // easy mode + CHECK_NOTNULL((q = LuaAlloc(L, 10 + 4 + m))); + crc = crc32_z(0, p, n); + e = uleb64(q, n); + e = WRITE32LE(e, crc); + hdrlen = e - q; + CHECK_EQ(Z_OK, compress2((unsigned char *)(q + hdrlen), &m, + (unsigned char *)p, n, level)); + lua_pushlstring(L, q, hdrlen + m); + } + free(q); + return 1; +} + +int LuaUncompress(lua_State *L) { + char *q; + uint32_t crc; + int rc, level; + const char *p; + size_t n, m, len; + p = luaL_checklstring(L, 1, &n); + if (lua_isnoneornil(L, 2)) { + if ((rc = unuleb64(p, n, &m)) == -1 || n < rc + 4) { + luaL_error(L, "compressed value too short to be valid"); + unreachable; + } + len = m; + crc = READ32LE(p + rc); + CHECK_NOTNULL((q = LuaAlloc(L, m))); + if (uncompress((void *)q, &m, (unsigned char *)p + rc + 4, n) != Z_OK || + m != len || crc32_z(0, q, m) != crc) { + free(q); + luaL_error(L, "compressed value is corrupted"); + unreachable; + } + } else { + len = m = luaL_checkinteger(L, 2); + CHECK_NOTNULL((q = LuaAlloc(L, m))); + if (uncompress((void *)q, &m, (void *)p, n) != Z_OK || m != len) { + free(q); + luaL_error(L, "compressed value is corrupted"); + unreachable; + } + } + lua_pushlstring(L, q, m); + free(q); + return 1; +} diff --git a/tool/net/lfuncs.h b/tool/net/lfuncs.h index 301c8a49e..816081929 100644 --- a/tool/net/lfuncs.h +++ b/tool/net/lfuncs.h @@ -11,11 +11,15 @@ int LuaUnix(lua_State *); int luaopen_argon2(lua_State *); int luaopen_lsqlite3(lua_State *); +void *LuaRealloc(lua_State *, void *, size_t); +void *LuaAlloc(lua_State *, size_t); + int LuaBenchmark(lua_State *); int LuaBin(lua_State *); int LuaBsf(lua_State *); int LuaBsr(lua_State *); int LuaCategorizeIp(lua_State *); +int LuaCompress(lua_State *); int LuaCrc32(lua_State *); int LuaCrc32c(lua_State *); int LuaDecimate(lua_State *); @@ -78,6 +82,7 @@ int LuaSha384(lua_State *); int LuaSha512(lua_State *); int LuaSleep(lua_State *); int LuaSlurp(lua_State *); +int LuaUncompress(lua_State *); int LuaUnderlong(lua_State *); int LuaVisualizeControlCodes(lua_State *); diff --git a/tool/net/lunix.c b/tool/net/lunix.c index 11ef20ff8..f3c175dc7 100644 --- a/tool/net/lunix.c +++ b/tool/net/lunix.c @@ -96,14 +96,14 @@ */ struct UnixErrno { - int errno; + int errno_; int winerr; const char *call; }; static lua_State *GL; -static void *LuaUnixRealloc(lua_State *L, void *p, size_t n) { +void *LuaRealloc(lua_State *L, void *p, size_t n) { void *p2; if ((p2 = realloc(p, n))) { return p2; @@ -116,16 +116,8 @@ static void *LuaUnixRealloc(lua_State *L, void *p, size_t n) { return p2; } -static void *LuaUnixAllocRaw(lua_State *L, size_t n) { - return LuaUnixRealloc(L, 0, n); -} - -static void *LuaUnixAlloc(lua_State *L, size_t n) { - void *p; - if ((p = LuaUnixAllocRaw(L, n))) { - bzero(p, n); - } - return p; +void *LuaAlloc(lua_State *L, size_t n) { + return LuaRealloc(L, 0, n); } static lua_Integer FixLimit(long x) { @@ -185,7 +177,7 @@ static int SysretErrno(lua_State *L, const char *call, int olderr) { lua_pushnil(L); ep = lua_newuserdatauv(L, sizeof(*ep), 1); luaL_setmetatable(L, "unix.Errno"); - ep->errno = unixerr; + ep->errno_ = unixerr; ep->winerr = winerr; ep->call = call; errno = olderr; @@ -241,7 +233,7 @@ static char **ConvertLuaArrayToStringList(lua_State *L, int i) { lua_len(L, i); n = lua_tointeger(L, -1); lua_pop(L, 1); - if ((p = LuaUnixAllocRaw(L, (n + 1) * sizeof(*p)))) { + if ((p = LuaAlloc(L, (n + 1) * sizeof(*p)))) { for (j = 1; j <= n; ++j) { lua_geti(L, i, j); s = strdup(lua_tostring(L, -1)); @@ -442,7 +434,7 @@ static int LuaUnixReadlink(lua_State *L) { size_t got, bufsiz = 8192; path = luaL_checkstring(L, 1); dirfd = luaL_optinteger(L, 2, AT_FDCWD); - if ((buf = LuaUnixAllocRaw(L, bufsiz))) { + if ((buf = LuaAlloc(L, bufsiz))) { if ((rc = readlinkat(dirfd, path, buf, bufsiz)) != -1) { got = rc; if (got < bufsiz) { @@ -543,7 +535,7 @@ static int LuaUnixCommandv(lua_State *L) { char *pathbuf, *resolved; olderr = errno; prog = luaL_checkstring(L, 1); - if ((pathbuf = LuaUnixAllocRaw(L, PATH_MAX))) { + if ((pathbuf = LuaAlloc(L, PATH_MAX))) { if ((resolved = commandv(prog, pathbuf, PATH_MAX))) { lua_pushstring(L, resolved); free(pathbuf); @@ -913,7 +905,7 @@ static int LuaUnixRead(lua_State *L) { bufsiz = luaL_optinteger(L, 2, BUFSIZ); offset = luaL_optinteger(L, 3, -1); bufsiz = MIN(bufsiz, 0x7ffff000); - if ((buf = LuaUnixAllocRaw(L, bufsiz))) { + if ((buf = LuaAlloc(L, bufsiz))) { if (offset == -1) { rc = read(fd, buf, bufsiz); } else { @@ -1246,7 +1238,7 @@ static int LuaUnixSiocgifconf(lua_State *L) { struct ifreq *ifr; struct ifconf conf; olderr = errno; - if (!(data = LuaUnixAllocRaw(L, (n = 4096)))) { + if (!(data = LuaAlloc(L, (n = 4096)))) { return SysretErrno(L, "siocgifconf", olderr); } if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) { @@ -1345,7 +1337,7 @@ static int LuaUnixPoll(lua_State *L) { lua_pushnil(L); for (fds = 0, nfds = 0; lua_next(L, 1);) { if (lua_isinteger(L, -2)) { - if ((fds2 = LuaUnixRealloc(L, fds, (nfds + 1) * sizeof(*fds)))) { + if ((fds2 = LuaRealloc(L, fds, (nfds + 1) * sizeof(*fds)))) { fds2[nfds].fd = lua_tointeger(L, -2); fds2[nfds].events = lua_tointeger(L, -1); fds = fds2; @@ -1392,7 +1384,7 @@ static int LuaUnixRecvfrom(lua_State *L) { bufsiz = luaL_optinteger(L, 2, 1500); bufsiz = MIN(bufsiz, 0x7ffff000); flags = luaL_optinteger(L, 3, 0); - if ((buf = LuaUnixAllocRaw(L, bufsiz))) { + if ((buf = LuaAlloc(L, bufsiz))) { rc = recvfrom(fd, buf, bufsiz, flags, &sa, &addrsize); if (rc != -1) { got = rc; @@ -1423,7 +1415,7 @@ static int LuaUnixRecv(lua_State *L) { bufsiz = luaL_optinteger(L, 2, 1500); bufsiz = MIN(bufsiz, 0x7ffff000); flags = luaL_optinteger(L, 3, 0); - if ((buf = LuaUnixAllocRaw(L, bufsiz))) { + if ((buf = LuaAlloc(L, bufsiz))) { rc = recv(fd, buf, bufsiz, flags); if (rc != -1) { got = rc; @@ -2047,7 +2039,7 @@ static struct UnixErrno *GetUnixErrno(lua_State *L) { // unix.Errno:errno() // └─→ errno:int static int LuaUnixErrnoErrno(lua_State *L) { - return ReturnInteger(L, GetUnixErrno(L)->errno); + return ReturnInteger(L, GetUnixErrno(L)->errno_); } static int LuaUnixErrnoWinerr(lua_State *L) { @@ -2055,11 +2047,11 @@ static int LuaUnixErrnoWinerr(lua_State *L) { } static int LuaUnixErrnoName(lua_State *L) { - return ReturnString(L, strerrno(GetUnixErrno(L)->errno)); + return ReturnString(L, strerrno(GetUnixErrno(L)->errno_)); } static int LuaUnixErrnoDoc(lua_State *L) { - return ReturnString(L, strerdoc(GetUnixErrno(L)->errno)); + return ReturnString(L, strerdoc(GetUnixErrno(L)->errno_)); } static int LuaUnixErrnoCall(lua_State *L) { @@ -2071,10 +2063,10 @@ static int LuaUnixErrnoToString(lua_State *L) { struct UnixErrno *e; e = GetUnixErrno(L); if (e->call) { - strerror_wr(e->errno, e->winerr, msg, sizeof(msg)); + strerror_wr(e->errno_, e->winerr, msg, sizeof(msg)); lua_pushfstring(L, "%s() failed: %s", e->call, msg); } else { - lua_pushstring(L, strerrno(e->errno)); + lua_pushstring(L, strerrno(e->errno_)); } return 1; } diff --git a/tool/net/net.mk b/tool/net/net.mk index 6332a72b1..15b075934 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -21,7 +21,6 @@ TOOL_NET_COMS = \ o/$(MODE)/tool/net/redbean-static.com \ o/$(MODE)/tool/net/redbean-unsecure.com \ o/$(MODE)/tool/net/redbean-original.com \ - o/$(MODE)/tool/net/redbean-assimilate.com \ o/$(MODE)/tool/net/wb.com TOOL_NET_CHECKS = \ @@ -82,7 +81,7 @@ o/$(MODE)/tool/net/%.com.dbg: \ o/$(MODE)/tool/net/%.o \ o/$(MODE)/tool/net/net.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) # REDBEAN.COM @@ -100,7 +99,7 @@ o/$(MODE)/tool/net/redbean.com.dbg: \ o/$(MODE)/tool/net/largon2.o \ o/$(MODE)/tool/net/net.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) ifneq ($(MODE),tiny) @@ -115,13 +114,11 @@ o/$(MODE)/tool/net/redbean.com: \ tool/net/favicon.ico \ tool/net/redbean.png @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean @$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com -o o/$(MODE)/tool/net/.redbean/.symtab $< @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \ o/$(MODE)/tool/net/.redbean/.symtab @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \ - o/$(MODE)/tool/net/.redbean/.ape \ tool/net/help.txt \ tool/net/.init.lua \ tool/net/favicon.ico \ @@ -138,10 +135,8 @@ o/tiny/tool/net/redbean.com: \ tool/net/favicon.ico \ tool/net/redbean.png @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/tiny/tool/net/.redbean - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/tiny/tool/net/.redbean/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/tiny/tool/net/.redbean @$(COMPILE) -AZIP -T$@ o/tiny/third_party/zip/zip.com -9qj $@ \ - o/tiny/tool/net/.redbean/.ape \ tool/net/tiny/help.txt \ tool/net/.init.lua \ tool/net/favicon.ico \ @@ -156,10 +151,8 @@ o/tinylinux/tool/net/redbean.com: \ tool/net/favicon.ico \ tool/net/redbean.png @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/tinylinux/tool/net/.redbean - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/tinylinux/tool/net/.redbean/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/tinylinux/tool/net/.redbean @$(COMPILE) -AZIP -T$@ o/tinylinux/third_party/zip/zip.com -9qj $@ \ - o/tinylinux/tool/net/.redbean/.ape \ tool/net/tiny/help.txt \ tool/net/.init.lua \ tool/net/favicon.ico \ @@ -255,7 +248,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \ o/$(MODE)/tool/net/demo/.reload.lua.zip.o \ o/$(MODE)/tool/net/demo/.init.lua.zip.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/net/redbean-demo.com: \ @@ -264,14 +257,12 @@ o/$(MODE)/tool/net/redbean-demo.com: \ o/$(MODE)/third_party/zip/zip.com \ tool/net/help.txt @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-demo - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-demo/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean-demo @$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \ -o o/$(MODE)/tool/net/.redbean-demo/.symtab $< @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \ o/$(MODE)/tool/net/.redbean-demo/.symtab @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \ - o/$(MODE)/tool/net/.redbean-demo/.ape \ tool/net/help.txt # REDBEAN-STATIC.COM @@ -287,14 +278,12 @@ o/$(MODE)/tool/net/redbean-static.com: \ tool/net/favicon.ico \ tool/net/redbean.png @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-static - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-static/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean-static @$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \ -o o/$(MODE)/tool/net/.redbean-static/.symtab $< @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \ o/$(MODE)/tool/net/.redbean-static/.symtab @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \ - o/$(MODE)/tool/net/.redbean-static/.ape \ tool/net/help.txt \ tool/net/favicon.ico \ tool/net/redbean.png @@ -304,7 +293,7 @@ o/$(MODE)/tool/net/redbean-static.com.dbg: \ o/$(MODE)/tool/net/redbean-static.o \ o/$(MODE)/tool/net/net.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/net/redbean-static.o: tool/net/redbean.c o/$(MODE)/tool/net/redbean.o @@ -324,14 +313,12 @@ o/$(MODE)/tool/net/redbean-unsecure.com: \ tool/net/favicon.ico \ tool/net/redbean.png @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-unsecure - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-unsecure/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean-unsecure @$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \ -o o/$(MODE)/tool/net/.redbean-unsecure/.symtab $< @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \ o/$(MODE)/tool/net/.redbean-unsecure/.symtab @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \ - o/$(MODE)/tool/net/.redbean-unsecure/.ape \ tool/net/help.txt \ tool/net/favicon.ico \ tool/net/redbean.png @@ -346,7 +333,7 @@ o/$(MODE)/tool/net/redbean-unsecure.com.dbg: \ o/$(MODE)/tool/net/lsqlite3.o \ o/$(MODE)/tool/net/net.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/net/redbean-unsecure.o: tool/net/redbean.c o/$(MODE)/tool/net/redbean.o @@ -368,14 +355,12 @@ o/$(MODE)/tool/net/redbean-original.com: \ tool/net/favicon.ico \ tool/net/redbean.png @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-original - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/$(MODE)/tool/net/.redbean-original/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/net/.redbean-original @$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \ -o o/$(MODE)/tool/net/.redbean-original/.symtab $< @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \ o/$(MODE)/tool/net/.redbean-original/.symtab @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \ - o/$(MODE)/tool/net/.redbean-original/.ape \ tool/net/help.txt \ tool/net/favicon.ico \ tool/net/redbean.png @@ -389,10 +374,8 @@ o/tiny/tool/net/redbean-original.com: \ tool/net/favicon.ico \ tool/net/redbean.png @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/tiny/tool/net/.redbean-original - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/tiny/tool/net/.redbean-original/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/tiny/tool/net/.redbean-original @$(COMPILE) -AZIP -T$@ o/tiny/third_party/zip/zip.com -9qj $@ \ - o/tiny/tool/net/.redbean-original/.ape \ tool/net/tiny/help.txt \ tool/net/favicon.ico \ tool/net/redbean.png @@ -404,10 +387,8 @@ o/tinylinux/tool/net/redbean-original.com: \ tool/net/favicon.ico \ tool/net/redbean.png @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/tinylinux/tool/net/.redbean-original - @$(COMPILE) -ADD -T$@ dd if=$@ of=o/tinylinux/tool/net/.redbean-original/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/tinylinux/tool/net/.redbean-original @$(COMPILE) -AZIP -T$@ o/tinylinux/third_party/zip/zip.com -9qj $@ \ - o/tinylinux/tool/net/.redbean-original/.ape \ tool/net/tiny/help.txt \ tool/net/favicon.ico \ tool/net/redbean.png @@ -417,7 +398,7 @@ o/$(MODE)/tool/net/redbean-original.com.dbg: \ o/$(MODE)/tool/net/redbean-original.o \ o/$(MODE)/tool/net/net.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/net/redbean-original.o: tool/net/redbean.c o/$(MODE)/tool/net/redbean.o @@ -426,35 +407,6 @@ o/$(MODE)/tool/net/redbean-original.o: tool/net/redbean.c o/$(MODE)/tool/net/red o/$(MODE)/tool/net/redbean-original.s: tool/net/redbean.c o/$(MODE)/tool/net/redbean.o @$(COMPILE) -AOBJECTIFY.c $(COMPILE.c) -DSTATIC -DUNSECURE -DREDBEAN=\"redbean-original\" $(OUTPUT_OPTION) $< -# REDBEAN-ASSIMILATE.COM -# -# Same as REDBEAN.COM except without no-modify-self behavior. - -o/$(MODE)/tool/net/redbean-assimilate.com.dbg: \ - o/$(MODE)/tool/net/redbean.com.dbg - @cp -f $< $@ - -o/$(MODE)/tool/net/redbean-assimilate.com: \ - o/$(MODE)/tool/net/redbean-assimilate.com.dbg \ - o/$(MODE)/third_party/zip/zip.com \ - o/$(MODE)/tool/build/symtab.com \ - tool/net/net.mk \ - tool/net/help.txt \ - tool/net/.init.lua \ - tool/net/favicon.ico \ - tool/net/redbean.png - @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-assimilate - @$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com -o o/$(MODE)/tool/net/.redbean-assimilate/.symtab $< - @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \ - o/$(MODE)/tool/net/.redbean-assimilate/.symtab - @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -9qj $@ \ - o/$(MODE)/tool/net/.redbean-assimilate/.symtab \ - tool/net/help.txt \ - tool/net/.init.lua \ - tool/net/favicon.ico \ - tool/net/redbean.png - .PHONY: o/$(MODE)/tool/net o/$(MODE)/tool/net: \ $(TOOL_NET_BINS) \ diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 4063fef3a..105130002 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -16,146 +16,92 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "dsp/scale/cdecimate2xuint8x8.h" -#include "libc/bits/bits.h" -#include "libc/bits/likely.h" -#include "libc/bits/popcnt.h" +#include "libc/bits/atomic.h" #include "libc/bits/safemacros.internal.h" #include "libc/calls/calls.h" #include "libc/calls/ioctl.h" #include "libc/calls/math.h" #include "libc/calls/sigbits.h" -#include "libc/calls/strace.internal.h" -#include "libc/calls/struct/dirent.h" #include "libc/calls/struct/filter.h" #include "libc/calls/struct/flock.h" +#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/rusage.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/termios.h" -#include "libc/calls/ttydefaults.h" -#include "libc/dce.h" #include "libc/dns/dns.h" #include "libc/dns/hoststxt.h" #include "libc/dos.h" -#include "libc/errno.h" #include "libc/fmt/conv.h" -#include "libc/fmt/fmt.h" #include "libc/fmt/itoa.h" #include "libc/intrin/nomultics.internal.h" -#include "libc/intrin/spinlock.h" -#include "libc/log/backtrace.internal.h" #include "libc/log/check.h" #include "libc/log/log.h" -#include "libc/macros.internal.h" #include "libc/math.h" #include "libc/mem/alloca.h" -#include "libc/mem/fmt.h" -#include "libc/mem/mem.h" -#include "libc/nexgen32e/bsf.h" #include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/crc32.h" #include "libc/nexgen32e/nt2sysv.h" #include "libc/nexgen32e/rdtsc.h" -#include "libc/nexgen32e/rdtscp.h" +#include "libc/nexgen32e/threaded.h" +#include "libc/nexgen32e/x86feature.h" #include "libc/nt/enum/fileflagandattributes.h" -#include "libc/nt/runtime.h" #include "libc/nt/thread.h" -#include "libc/nt/version.h" #include "libc/rand/rand.h" #include "libc/runtime/clktck.h" -#include "libc/runtime/directmap.internal.h" #include "libc/runtime/gc.h" #include "libc/runtime/gc.internal.h" -#include "libc/runtime/internal.h" -#include "libc/runtime/memtrack.internal.h" -#include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" -#include "libc/runtime/symbols.internal.h" #include "libc/sock/goodsocket.internal.h" #include "libc/sock/sock.h" #include "libc/stdio/append.internal.h" #include "libc/stdio/hex.internal.h" -#include "libc/stdio/stdio.h" #include "libc/str/slice.h" -#include "libc/str/str.h" #include "libc/str/undeflate.h" #include "libc/sysv/consts/af.h" -#include "libc/sysv/consts/audit.h" -#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/clone.h" #include "libc/sysv/consts/dt.h" #include "libc/sysv/consts/ex.h" #include "libc/sysv/consts/exit.h" #include "libc/sysv/consts/f.h" -#include "libc/sysv/consts/grnd.h" #include "libc/sysv/consts/inaddr.h" #include "libc/sysv/consts/ipproto.h" -#include "libc/sysv/consts/lock.h" -#include "libc/sysv/consts/madv.h" #include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/msync.h" -#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/pr.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/rusage.h" -#include "libc/sysv/consts/s.h" -#include "libc/sysv/consts/shut.h" +#include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" -#include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sock.h" -#include "libc/sysv/consts/sol.h" -#include "libc/sysv/consts/tcp.h" #include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/w.h" #include "libc/sysv/errfuns.h" -#include "libc/testlib/testlib.h" -#include "libc/time/time.h" #include "libc/x/x.h" #include "libc/zip.h" #include "net/http/escape.h" #include "net/http/http.h" #include "net/http/ip.h" -#include "net/http/url.h" #include "net/https/https.h" #include "third_party/getopt/getopt.h" -#include "third_party/linenoise/linenoise.h" #include "third_party/lua/cosmo.h" #include "third_party/lua/lauxlib.h" #include "third_party/lua/lrepl.h" -#include "third_party/lua/ltests.h" -#include "third_party/lua/lua.h" -#include "third_party/lua/luaconf.h" #include "third_party/lua/lualib.h" -#include "third_party/mbedtls/asn1.h" -#include "third_party/mbedtls/asn1write.h" -#include "third_party/mbedtls/cipher.h" -#include "third_party/mbedtls/config.h" #include "third_party/mbedtls/ctr_drbg.h" #include "third_party/mbedtls/debug.h" -#include "third_party/mbedtls/ecp.h" -#include "third_party/mbedtls/entropy.h" -#include "third_party/mbedtls/entropy_poll.h" -#include "third_party/mbedtls/error.h" #include "third_party/mbedtls/iana.h" -#include "third_party/mbedtls/md.h" -#include "third_party/mbedtls/md5.h" +#include "third_party/mbedtls/net_sockets.h" #include "third_party/mbedtls/oid.h" -#include "third_party/mbedtls/pk.h" -#include "third_party/mbedtls/rsa.h" #include "third_party/mbedtls/san.h" -#include "third_party/mbedtls/sha1.h" #include "third_party/mbedtls/ssl.h" #include "third_party/mbedtls/ssl_ticket.h" #include "third_party/mbedtls/x509.h" #include "third_party/mbedtls/x509_crt.h" -#include "third_party/regex/regex.h" #include "third_party/zlib/zlib.h" #include "tool/args/args.h" #include "tool/build/lib/case.h" -#include "tool/build/lib/psk.h" #include "tool/net/lfuncs.h" #include "tool/net/luacheck.h" #include "tool/net/sandbox.h" @@ -202,34 +148,26 @@ STATIC_YOINK("zip_uri_support"); #define HeaderEqualCase(H, S) \ SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H)) -#define TRACE_BEGIN \ - do { \ - if (!IsTiny()) { \ - if (funtrace) { \ - __atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \ - } \ - if (systrace) { \ - __atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED); \ - } \ - } \ +#define TRACE_BEGIN \ + do { \ + if (!IsTiny()) { \ + if (funtrace) ++__ftrace; \ + if (systrace) ++__strace; \ + } \ } while (0) -#define TRACE_END \ - do { \ - if (!IsTiny()) { \ - if (funtrace) { \ - __atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \ - } \ - if (systrace) { \ - __atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED); \ - } \ - } \ +#define TRACE_END \ + do { \ + if (!IsTiny()) { \ + if (funtrace) --__ftrace; \ + if (systrace) --__strace; \ + } \ } while (0) -// letters not used: EIJNOQXYnoqwxy +// letters not used: EIJNOQYnoqwxy // digits not used: 0123456789 // puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~ -#define GETOPTS "BSVZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:W:c:e:l:p:r:t:" +#define GETOPTS "BSVXZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:W:c:e:l:p:r:t:" extern unsigned long long __kbirth; @@ -401,6 +339,7 @@ static bool branded; static bool funtrace; static bool systrace; static bool meltdown; +static bool unsecure; static bool printport; static bool daemonize; static bool logrusage; @@ -410,7 +349,6 @@ static bool sslcliused; static bool loglatency; static bool terminated; static bool uniprocess; -static bool memmonalive; static bool invalidated; static bool logmessages; static bool isinitialized; @@ -423,7 +361,6 @@ static bool sslclientverify; static bool connectionclose; static bool hasonworkerstop; static bool isexitingworker; -static bool terminatemonitor; static bool hasonworkerstart; static bool leakcrashreports; static bool hasonhttprequest; @@ -435,6 +372,7 @@ static bool loggednetworkorigin; static bool ishandlingconnection; static bool hasonclientconnection; static bool evadedragnetsurveillance; +_Atomic(bool) static terminatemonitor; static int zfd; static int frags; @@ -449,6 +387,9 @@ static int statuscode; static int shutdownsig; static int sslpskindex; static int oldloglevel; +static int *monitortid; +static char *monitortls; +static char *monitorstack; static int maxpayloadsize; static int messageshandled; static int sslticketlifetime; @@ -1211,7 +1152,7 @@ static void CallSimpleHookIfDefined(const char *s) { static void ReportWorkerExit(int pid, int ws) { int workers; - workers = __atomic_sub_fetch(&shared->workers, 1, __ATOMIC_SEQ_CST); + workers = atomic_fetch_sub(&shared->workers, 1) - 1; if (WIFEXITED(ws)) { if (WEXITSTATUS(ws)) { LockInc(&shared->c.failedchildren); @@ -1464,6 +1405,21 @@ static ssize_t SslRead(int fd, void *buf, size_t size) { errno = EINTR; rc = -1; errno = 0; + } else if (rc == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) { + WARNF("(ssl) %s SslRead error -0x%04x (%s)", DescribeClient(), -rc, + "fatal alert message"); + errno = EIO; + rc = -1; + } else if (rc == MBEDTLS_ERR_SSL_INVALID_RECORD) { + WARNF("(ssl) %s SslRead error -0x%04x (%s)", DescribeClient(), -rc, + "invalid record"); + errno = EIO; + rc = -1; + } else if (rc == MBEDTLS_ERR_SSL_INVALID_MAC) { + WARNF("(ssl) %s SslRead error -0x%04x (%s)", DescribeClient(), -rc, + "hmac verification failed"); + errno = EIO; + rc = -1; } else { WARNF("(ssl) %s SslRead error -0x%04x", DescribeClient(), -rc); errno = EIO; @@ -1485,6 +1441,12 @@ static ssize_t SslWrite(int fd, struct iovec *iov, int iovlen) { if ((rc = mbedtls_ssl_write(&ssl, p, n)) > 0) { p += rc; n -= rc; + } else if (rc == MBEDTLS_ERR_NET_CONN_RESET) { + errno = ECONNRESET; + return -1; + } else if (rc == MBEDTLS_ERR_SSL_TIMEOUT) { + errno = ETIMEDOUT; + return -1; } else { WARNF("(ssl) %s SslWrite error -0x%04x", DescribeClient(), -rc); errno = EIO; @@ -2465,13 +2427,28 @@ static ssize_t YieldGenerator(struct iovec v[3]) { return contentlength; } +static void OnLuaServerPageCtrlc(int i) { + lua_sigint(GL, i); +} + static int LuaCallWithYield(lua_State *L) { int status; // since yield may happen in OnHttpRequest and in ServeLua, // need to fully restart the yield generator; // the second set of headers is not going to be sent + struct sigaction sa, saold; lua_State *co = lua_newthread(L); - if ((status = LuaCallWithTrace(L, 0, 0, co)) == LUA_YIELD) { + if (__replmode) { + sa.sa_flags = SA_RESETHAND; + sa.sa_handler = OnLuaServerPageCtrlc; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, &saold); + } + status = LuaCallWithTrace(L, 0, 0, co); + if (__replmode) { + sigaction(SIGINT, &saold, 0); + } + if (status == LUA_YIELD) { CHECK_GT(lua_gettop(L), 0); // make sure that coroutine is anchored YL = co; generator = YieldGenerator; @@ -3658,6 +3635,7 @@ static int LuaStoreAsset(lua_State *L) { static void ReseedRng(mbedtls_ctr_drbg_context *r, const char *s) { #ifndef UNSECURE + if (unsecure) return; CHECK_EQ(0, mbedtls_ctr_drbg_reseed(r, (void *)s, strlen(s))); #endif } @@ -3810,7 +3788,8 @@ static int LuaFetch(lua_State *L) { usessl = false; if (url.scheme.n) { #ifndef UNSECURE - if (url.scheme.n == 5 && !memcasecmp(url.scheme.p, "https", 5)) { + if (!unsecure && url.scheme.n == 5 && + !memcasecmp(url.scheme.p, "https", 5)) { usessl = true; } else #endif @@ -3820,14 +3799,20 @@ static int LuaFetch(lua_State *L) { } } +#ifndef UNSECURE if (usessl && !sslinitialized) TlsInit(); +#endif if (url.host.n) { host = gc(strndup(url.host.p, url.host.n)); if (url.port.n) { port = gc(strndup(url.port.p, url.port.n)); +#ifndef UNSECURE + } else if (usessl) { + port = "443"; +#endif } else { - port = usessl ? "443" : "80"; + port = "80"; } } else { ip = servers.n ? ntohl(servers.p[0].addr.sin_addr.s_addr) : INADDR_LOOPBACK; @@ -3894,6 +3879,7 @@ static int LuaFetch(lua_State *L) { unreachable; } +#ifndef UNSECURE if (usessl) { if (sslcliused) { mbedtls_ssl_session_reset(&sslcli); @@ -3928,11 +3914,13 @@ static int LuaFetch(lua_State *L) { mbedtls_ssl_get_ciphersuite(&sslcli), mbedtls_ssl_get_version(&sslcli)); } +#endif /* UNSECURE */ /* * Send HTTP Message. */ DEBUGF("(ftch) client sending %s request", method); +#ifndef UNSECURE if (usessl) { ret = mbedtls_ssl_write(&sslcli, request, requestlen); if (ret != requestlen) { @@ -3941,7 +3929,9 @@ static int LuaFetch(lua_State *L) { LuaThrowTlsError(L, "write", ret); unreachable; } - } else if (WRITE(sock, request, requestlen) != requestlen) { + } else +#endif + if (WRITE(sock, request, requestlen) != requestlen) { close(sock); luaL_error(L, "write error: %s", strerror(errno)); unreachable; @@ -3962,6 +3952,7 @@ static int LuaFetch(lua_State *L) { inbuf.p = realloc(inbuf.p, inbuf.c); } NOISEF("(ftch) client reading"); +#ifndef UNSECURE if (usessl) { if ((rc = mbedtls_ssl_read(&sslcli, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) < 0) { @@ -3975,7 +3966,9 @@ static int LuaFetch(lua_State *L) { unreachable; } } - } else if ((rc = READ(sock, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) == -1) { + } else +#endif + if ((rc = READ(sock, inbuf.p + inbuf.n, inbuf.c - inbuf.n)) == -1) { close(sock); free(inbuf.p); DestroyHttpMessage(&msg); @@ -4125,6 +4118,7 @@ TransportError: close(sock); luaL_error(L, "transport error"); unreachable; +#ifndef UNSECURE VerifyFailed: LockInc(&shared->c.sslverifyfailed); close(sock); @@ -4132,6 +4126,7 @@ VerifyFailed: L, gc(DescribeSslVerifyFailure(sslcli.session_negotiate->verify_result)), ret); unreachable; +#endif #undef ssl } @@ -4790,8 +4785,11 @@ static int LuaEvadeDragnetSurveillance(lua_State *L) { static int LuaProgramSslCompression(lua_State *L) { #ifndef UNSECURE - OnlyCallFromInitLua(L, "ProgramSslCompression"); - conf.disable_compression = confcli.disable_compression = !lua_toboolean(L, 1); + if (!unsecure) { + OnlyCallFromInitLua(L, "ProgramSslCompression"); + conf.disable_compression = confcli.disable_compression = + !lua_toboolean(L, 1); + } #endif return 0; } @@ -4924,10 +4922,10 @@ static int LuaLaunchBrowser(lua_State *L) { } static bool LuaRunAsset(const char *path, bool mandatory) { + int status; struct Asset *a; const char *code; size_t pathlen, codelen; - int status; pathlen = strlen(path); if ((a = GetAsset(path, pathlen))) { if ((code = FreeLater(LoadAsset(a, &codelen)))) { @@ -5012,6 +5010,7 @@ static const luaL_Reg kLuaFuncs[] = { {"Bsf", LuaBsf}, // {"Bsr", LuaBsr}, // {"CategorizeIp", LuaCategorizeIp}, // + {"Compress", LuaCompress}, // {"Crc32", LuaCrc32}, // {"Crc32c", LuaCrc32c}, // {"Decimate", LuaDecimate}, // @@ -5032,6 +5031,7 @@ static const luaL_Reg kLuaFuncs[] = { {"EscapePath", LuaEscapePath}, // {"EscapeSegment", LuaEscapeSegment}, // {"EscapeUser", LuaEscapeUser}, // + {"Fetch", LuaFetch}, // {"FormatHttpDateTime", LuaFormatHttpDateTime}, // {"FormatIp", LuaFormatIp}, // {"GetAssetComment", LuaGetAssetComment}, // @@ -5147,6 +5147,7 @@ static const luaL_Reg kLuaFuncs[] = { {"Sleep", LuaSleep}, // {"Slurp", LuaSlurp}, // {"StoreAsset", LuaStoreAsset}, // + {"Uncompress", LuaUncompress}, // {"Underlong", LuaUnderlong}, // {"VisualizeControlCodes", LuaVisualizeControlCodes}, // {"Write", LuaWrite}, // @@ -5154,7 +5155,6 @@ static const luaL_Reg kLuaFuncs[] = { {"hex", LuaHex}, // {"oct", LuaOct}, // #ifndef UNSECURE - {"Fetch", LuaFetch}, // {"EvadeDragnetSurveillance", LuaEvadeDragnetSurveillance}, // {"GetSslIdentity", LuaGetSslIdentity}, // {"ProgramSslCiphersuite", LuaProgramSslCiphersuite}, // @@ -5310,7 +5310,7 @@ static void LuaInterpreter(lua_State *L) { if (status == -2) { if (errno == EINTR) { if ((sig = linenoiseGetInterrupt())) { - raise(sig); + kill(0, sig); } } fprintf(stderr, "i/o error: %m\n"); @@ -5387,7 +5387,7 @@ static void LogClose(const char *reason) { INFOF("(stat) %s %s with %,ld unprocessed and %,d handled (%,d workers)", DescribeClient(), reason, amtread, messageshandled, shared->workers); } else { - DEBUGF("(stat) %s %s with %,d requests handled", DescribeClient(), reason, + DEBUGF("(stat) %s %s with %,d messages handled", DescribeClient(), reason, messageshandled); } } @@ -5500,6 +5500,11 @@ static char *HandleMapFailed(struct Asset *a, int fd) { return ServeError(500, "Internal Server Error"); } +static void LogAcceptError(const char *s) { + LockInc(&shared->c.accepterrors); + WARNF("(srvr) %s accept error: %s", DescribeServer(), s); +} + static char *HandleOpenFail(struct Asset *a) { LockInc(&shared->c.openfails); WARNF("(srvr) open(%`'s) error: %m", a->file->path); @@ -6158,8 +6163,6 @@ static bool HandleMessageActual(void) { p = stpcpy(p, referrerpolicy); p = stpcpy(p, "\r\n"); } - LockInc(&shared->c.messageshandled); - ++messageshandled; if (loglatency || LOGGABLE(kLogDebug)) { now = nowl(); LOGF(kLogDebug, "(stat) %`'.*s latency r: %,ldµs c: %,ldµs", @@ -6228,14 +6231,16 @@ static void HandleMessages(void) { #ifndef UNSECURE if (!once) { once = true; - if (IsSsl(inbuf.p[0])) { - if (TlsSetup()) { - continue; + if (!unsecure) { + if (IsSsl(inbuf.p[0])) { + if (TlsSetup()) { + continue; + } else { + return; + } } else { - return; + WipeServingKeys(); } - } else { - WipeServingKeys(); } } #endif @@ -6258,15 +6263,15 @@ static void HandleMessages(void) { LockInc(&shared->c.readtimeouts); if (amtread) SendTimeout(); NotifyClose(); - LogClose("timeout"); + LogClose("readtimeout"); return; } else if (errno == ECONNRESET) { LockInc(&shared->c.readresets); - LogClose("reset"); + LogClose("readreset"); return; } else { LockInc(&shared->c.readerrors); - WARNF("(clnt) %s read error: %m", DescribeClient()); + WARNF("(clnt) %s readerror: %m", DescribeClient()); return; } if (killed || (terminated && !amtread) || @@ -6297,7 +6302,7 @@ static void HandleMessages(void) { } else { CHECK_LT(msgsize, amtread); LockInc(&shared->c.pipelinedrequests); - DEBUGF("(stat) %,ld pipelined bytes", amtread - msgsize); + DEBUGF("(stat) %,ld pipelinedrequest bytes", amtread - msgsize); memmove(inbuf.p, inbuf.p + msgsize, amtread - msgsize); amtread -= msgsize; if (killed) { @@ -6331,7 +6336,7 @@ static int ExitWorker(void) { } if (monitortty) { terminatemonitor = true; - _spinlock(&memmonalive); + _spinlock(monitortid); } _Exit(0); } @@ -6445,8 +6450,7 @@ static int MemoryMonitor(void *arg) { struct MemoryInterval *mi, *mi2; long i, j, k, n, x, y, pi, gen, pages; int rc, id, color, color2, workers; - _spinlock(&memmonalive); - __atomic_load(&shared->workers, &id, __ATOMIC_SEQ_CST); + id = atomic_load_explicit(&shared->workers, memory_order_relaxed); DEBUGF("(memv) started for pid %d on tid %d", getpid(), gettid()); sigemptyset(&ss); @@ -6478,10 +6482,8 @@ static int MemoryMonitor(void *arg) { _spunlock(&shared->montermlock); if (tty != -1) { - for (gen = 0, mi = 0, b = 0;;) { - __atomic_load(&terminatemonitor, &done, __ATOMIC_SEQ_CST); - if (done) break; - __atomic_load(&shared->workers, &workers, __ATOMIC_SEQ_CST); + for (gen = 0, mi = 0, b = 0; !terminatemonitor;) { + workers = atomic_load_explicit(&shared->workers, memory_order_relaxed); if (id) id = MAX(1, MIN(id, workers)); if (!id && workers) { usleep(50000); @@ -6489,15 +6491,18 @@ static int MemoryMonitor(void *arg) { } ++gen; - __atomic_load(&_mmi.i, &intervals, __ATOMIC_SEQ_CST); + intervals = atomic_load_explicit(&_mmi.i, memory_order_relaxed); if ((mi2 = realloc(mi, (intervals += 3) * sizeof(*mi)))) { mi = mi2; mi[0].x = (intptr_t)_base >> 16; mi[0].size = _etext - _base; + mi[0].flags = 0; mi[1].x = (intptr_t)_etext >> 16; mi[1].size = _edata - _etext; + mi[1].flags = 0; mi[2].x = (intptr_t)_edata >> 16; mi[2].size = _end - _edata; + mi[2].flags = 0; _spinlock(&_mmi.lock); if (_mmi.i == intervals - 3) { memcpy(mi + 3, _mmi.p, _mmi.i * sizeof(*mi)); @@ -6507,7 +6512,7 @@ static int MemoryMonitor(void *arg) { } _spunlock(&_mmi.lock); if (!ok) { - WARNF("(memv) retrying due to contention on mmap table"); + VERBOSEF("(memv) retrying due to contention on mmap table"); continue; } @@ -6527,7 +6532,11 @@ static int MemoryMonitor(void *arg) { rc = mincore(addr + j * PAGESIZE, PAGESIZE, &rez); if (!rc) { if (rez & 1) { - color2 = 42; + if (mi[i].flags & MAP_SHARED) { + color2 = 105; + } else { + color2 = 42; + } } else { color2 = 41; } @@ -6539,7 +6548,11 @@ static int MemoryMonitor(void *arg) { color = color2; appendf(&b, "\e[%dm", color); } - appendw(&b, ' '); + if (mi[i].flags & MAP_ANONYMOUS) { + appendw(&b, ' '); + } else { + appendw(&b, '/'); + } } } @@ -6573,18 +6586,29 @@ static int MemoryMonitor(void *arg) { free(mi); free(b); } - _spunlock(&memmonalive); + DEBUGF("(memv) done"); return 0; } -static int MonitorMemory(void) { - return clone(MemoryMonitor, - mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE, - MAP_STACK | MAP_ANONYMOUS, -1, 0), - FRAMESIZE, - CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - 0, 0, 0, 0, 0); +static void MonitorMemory(void) { + if ((monitortls = __initialize_tls(malloc(64)))) { + if ((monitorstack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, + MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { + monitortid = (int *)(monitortls + 0x38); + if ((*monitortid = + clone(MemoryMonitor, monitorstack, GetStackSize(), + CLONE_VM | CLONE_THREAD | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_SETTLS | CLONE_CHILD_CLEARTID, + 0, 0, monitortls, 64, monitortid)) != -1) { + return; + } + munmap(monitorstack, GetStackSize()); + } + free(monitortls); + } + WARNF("(memv) failed to start memory monitor %m"); + monitortty = 0; } static int HandleConnection(size_t i) { @@ -6606,7 +6630,6 @@ static int HandleConnection(size_t i) { switch ((pid = fork())) { case 0: if (monitortty) { - memmonalive = false; MonitorMemory(); } meltdown = false; @@ -6671,35 +6694,39 @@ static int HandleConnection(size_t i) { LockInc(&shared->c.acceptinterrupts); } else if (errno == ENFILE) { LockInc(&shared->c.enfiles); - WARNF("(srvr) too many open files"); + LogAcceptError("enfile: too many open files"); meltdown = true; } else if (errno == EMFILE) { LockInc(&shared->c.emfiles); - WARNF("(srvr) ran out of open file quota"); + LogAcceptError("emfile: ran out of open file quota"); meltdown = true; } else if (errno == ENOMEM) { LockInc(&shared->c.enomems); - WARNF("(srvr) ran out of memory"); + LogAcceptError("enomem: ran out of memory"); meltdown = true; } else if (errno == ENOBUFS) { LockInc(&shared->c.enobufs); - WARNF("(srvr) ran out of buffer"); + LogAcceptError("enobuf: ran out of buffer"); meltdown = true; } else if (errno == ENONET) { LockInc(&shared->c.enonets); - WARNF("(srvr) %s network gone", DescribeServer()); + LogAcceptError("enonet: network gone"); polls[i].fd = -polls[i].fd; } else if (errno == ENETDOWN) { LockInc(&shared->c.enetdowns); - WARNF("(srvr) %s network down", DescribeServer()); + LogAcceptError("enetdown: network down"); polls[i].fd = -polls[i].fd; } else if (errno == ECONNABORTED) { + LockInc(&shared->c.accepterrors); LockInc(&shared->c.acceptresets); - WARNF("(srvr) %s connection reset before accept"); + WARNF("(srvr) %S accept error: %s", DescribeServer(), + "acceptreset: connection reset before accept"); } else if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENOPROTOOPT || errno == EPROTO) { LockInc(&shared->c.accepterrors); - WARNF("(srvr) %s ephemeral accept error: %m", DescribeServer()); + LockInc(&shared->c.acceptflakes); + WARNF("(srvr) accept error: %s ephemeral accept error: %m", + DescribeServer()); } else { DIEF("(srvr) %s accept error: %m", DescribeServer()); } @@ -6708,24 +6735,24 @@ static int HandleConnection(size_t i) { return rc; } -static void RestoreApe(void) { - char *p; +static void MakeExecutableModifiable(void) { + int ft; size_t n; - struct Asset *a; extern char ape_rom_vaddr[] __attribute__((__weak__)); if (!(SUPPORT_VECTOR & (METAL | WINDOWS | XNU))) return; if (IsWindows()) return; // TODO if (IsOpenbsd()) return; // TODO if (IsNetbsd()) return; // TODO if (endswith(zpath, ".com.dbg")) return; - if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) { - close(zfd); - if ((zfd = OpenExecutable()) == -1 || WRITE(zfd, p, n) == -1) { - WARNF("(srvr) can't restore .ape"); - } - free(p); - } else { - DEBUGF("(srvr) /.ape not found"); + close(zfd); + ft = __ftrace; + if ((zfd = OpenExecutable()) == -1) { + WARNF("(srvr) can't restore .ape"); + } + if (ft > 0) { + __ftrace = 0; + ftrace_install(); + __ftrace = ft; } } @@ -6742,13 +6769,17 @@ static int HandleReadline(void) { } else if (errno == EINTR) { errno = 0; VERBOSEF("(repl) interrupt"); + shutdownsig = SIGINT; + OnInt(SIGINT); + kill(0, SIGINT); return -1; } else if (errno == EAGAIN) { errno = 0; return 0; } else { - OnTerm(SIGIO); // error - return -1; + WARNF("unexpected terminal error %d% m", status); + errno = 0; + return 0; } } linenoiseDisableRawMode(); @@ -6812,7 +6843,7 @@ static int HandlePoll(int ms) { LockInc(&shared->c.pollinterrupts); } else if (errno == ENOMEM) { LockInc(&shared->c.enomems); - WARNF("(srvr) %s ran out of memory"); + WARNF("(srvr) poll error: ran out of memory"); meltdown = true; } else { DIEF("(srvr) poll error: %m"); @@ -6989,6 +7020,11 @@ static void SigInit(void) { static void TlsInit(void) { #ifndef UNSECURE int suite; + if (unsecure) return; + + if (suiteb && !X86_HAVE(AES)) { + WARNF("you're using suite b crypto but don't have aes-ni"); + } if (!sslinitialized) { InitializeRng(&rng); @@ -7048,6 +7084,7 @@ static void TlsInit(void) { static void TlsDestroy(void) { #ifndef UNSECURE + if (unsecure) return; mbedtls_ssl_free(&ssl); mbedtls_ssl_free(&sslcli); mbedtls_ctr_drbg_free(&rng); @@ -7092,6 +7129,7 @@ static void GetOpts(int argc, char *argv[]) { CASE('S', ++sandboxed); CASE('v', ++__log_level); CASE('s', --__log_level); + CASE('X', unsecure = true); CASE('Z', systrace = true); CASE('b', logbodies = true); CASE('z', printport = true); @@ -7164,7 +7202,7 @@ void RedBean(int argc, char *argv[]) { CHECK_NE(-1, (zfd = open(zpath, O_RDONLY))); CHECK_NE(-1, fstat(zfd, &zst)); OpenZip(true); - RestoreApe(); + MakeExecutableModifiable(); SetDefaults(); LuaStart(); GetOpts(argc, argv); @@ -7229,7 +7267,9 @@ void RedBean(int argc, char *argv[]) { } if (monitortty) { terminatemonitor = true; - _spinlock(&memmonalive); + _spinlock(monitortid); + munmap(monitorstack, GetStackSize()); + free(monitortls); } INFOF("(srvr) shutdown complete"); } diff --git a/tool/net/wb.c b/tool/net/wb.c index 7ad4f960c..62979fe68 100644 --- a/tool/net/wb.c +++ b/tool/net/wb.c @@ -52,6 +52,7 @@ #include "third_party/mbedtls/ctr_drbg.h" #include "third_party/mbedtls/debug.h" #include "third_party/mbedtls/error.h" +#include "third_party/mbedtls/net_sockets.h" #include "third_party/mbedtls/ssl.h" #define OPTS "BIqksvzX:H:C:m:" diff --git a/tool/plinko/lib/plinko.c b/tool/plinko/lib/plinko.c index 5f6e6379c..5035420b3 100644 --- a/tool/plinko/lib/plinko.c +++ b/tool/plinko/lib/plinko.c @@ -674,9 +674,9 @@ struct T DispatchTrace(dword ea, dword tm, dword r, dword p1, dword p2, struct T DispatchFtrace(dword ea, dword tm, dword r, dword p1, dword p2, dword d) { ftrace_install(); - ++g_ftrace; + ++__ftrace; ea = MAKE(recurse(MAKE(Cadr(LO(ea)), HI(ea)), p1, p2), 0); - --g_ftrace; + --__ftrace; return Ret(ea, tm, r); } diff --git a/tool/plinko/lib/printf.c b/tool/plinko/lib/printf.c index 839ef7216..43fceab34 100644 --- a/tool/plinko/lib/printf.c +++ b/tool/plinko/lib/printf.c @@ -80,7 +80,7 @@ int Vfnprintf(const char *f, va_list va, int fd, int n) { int b, c, i, x, y, si, prec, cols, sign; gotr = false; t = rdtsc(); - --g_ftrace; + --__ftrace; --__strace; ++recursive; for (ansi = 0;;) { @@ -290,7 +290,7 @@ int Vfnprintf(const char *f, va_list va, int fd, int n) { } } --recursive; - ++g_ftrace; + ++__ftrace; ++__strace; if (!recursive) { u = rdtsc(); diff --git a/tool/plinko/lib/read.c b/tool/plinko/lib/read.c index f35c06a6f..ac0a7b76c 100644 --- a/tool/plinko/lib/read.c +++ b/tool/plinko/lib/read.c @@ -280,10 +280,10 @@ static int Read1(int fd) { int Read(int fd) { int r; - --g_ftrace; + --__ftrace; --__strace; r = Read1(fd); - ++g_ftrace; + ++__ftrace; ++__strace; return r; } diff --git a/tool/plinko/plinko.c b/tool/plinko/plinko.c index eaa47a2ce..90158369e 100644 --- a/tool/plinko/plinko.c +++ b/tool/plinko/plinko.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/intrin/kprintf.h" #include "libc/log/log.h" +#include "libc/stdio/stdio.h" #include "tool/plinko/lib/plinko.h" STATIC_YOINK("__zipos_get"); diff --git a/tool/plinko/plinko.mk b/tool/plinko/plinko.mk index f841c1c40..21684cb10 100644 --- a/tool/plinko/plinko.mk +++ b/tool/plinko/plinko.mk @@ -43,7 +43,7 @@ o/$(MODE)/tool/plinko/%.com.dbg: \ o/$(MODE)/tool/plinko/plinko.pkg \ o/$(MODE)/tool/plinko/lib/library.lisp.zip.o \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) .PRECIOUS: o/$(MODE)/tool/plinko/plinko.com @@ -53,7 +53,7 @@ o/$(MODE)/tool/plinko/plinko.com: \ o/$(MODE)/tool/build/symtab.com \ tool/plinko/plinko.mk @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ - @$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/plinko/.redbean + @$(COMPILE) -AMKDIR -T$@ $(MKDIR) o/$(MODE)/tool/plinko/.redbean @$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com -o o/$(MODE)/tool/plinko/.plinko/.symtab $< @$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \ o/$(MODE)/tool/plinko/.plinko/.symtab diff --git a/tool/viz/cpuid.c b/tool/viz/cpuid.c index d10c36394..3ba6ab3ba 100644 --- a/tool/viz/cpuid.c +++ b/tool/viz/cpuid.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +#include "libc/intrin/kprintf.h" #include "libc/log/color.internal.h" #include "libc/log/log.h" #include "libc/nexgen32e/cpuid4.internal.h" @@ -92,6 +93,7 @@ void showcachesizes(void) { int main(int argc, char *argv[]) { int x; long tsc_aux; + ShowCrashReports(); showvendor(); showmodel(); @@ -106,14 +108,19 @@ int main(int argc, char *argv[]) { } if (X86_HAVE(HYPERVISOR)) { - unsigned eax, ebx, ecx, edx; - asm("push\t%%rbx\n\t" - "cpuid\n\t" - "mov\t%%ebx,%1\n\t" + int ax, cx; + char s[4 * 3 + 1]; + asm("push\t%%rbx\r\n" + "cpuid\r\n" + "mov\t%%ebx,0+%2\r\n" + "mov\t%%ecx,4+%2\r\n" + "mov\t%%edx,8+%2\r\n" + "movb\t$0,12+%2\r\n" "pop\t%%rbx" - : "=a"(eax), "=rm"(ebx), "=c"(ecx), "=d"(edx) - : "0"(0x40000000), "2"(0)); - printf("Running inside %.4s%.4s%.4s (eax=%#x)\n", &ebx, &ecx, &edx, eax); + : "=a"(ax), "=c"(cx), "=o"(s) + : "0"(0x40000000), "1"(0) + : "rdx"); + kprintf("Running inside %s (eax=%#x)\n", s, ax); } printf("\n"); diff --git a/tool/viz/echoctl.c b/tool/viz/echoctl.c new file mode 100644 index 000000000..281909034 --- /dev/null +++ b/tool/viz/echoctl.c @@ -0,0 +1,28 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/struct/termios.h" +#include "libc/calls/termios.h" +#include "libc/sysv/consts/termios.h" + +int main(int argc, char *argv[]) { + struct termios t; + if (tcgetattr(0, &t) == -1) return 1; + t.c_lflag ^= ECHOCTL; + if (tcsetattr(0, TCSANOW, &t) == -1) return 2; +} diff --git a/tool/viz/vdsodump.c b/tool/viz/vdsodump.c new file mode 100644 index 000000000..f5042a241 --- /dev/null +++ b/tool/viz/vdsodump.c @@ -0,0 +1,81 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/sysv/consts/auxv.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" +#include "third_party/xed/x86.h" + +#define OUTPATH "vdso.elf" + +volatile bool finished; + +void OnSegmentationFault(int sig, siginfo_t *si, ucontext_t *ctx) { + struct XedDecodedInst xedd; + xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); + xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); + ctx->uc_mcontext.rip += xedd.length; + finished = true; +} + +int main(int argc, char *argv[]) { + FILE *f; + int byte; + volatile unsigned char *vdso, *p; + + vdso = (unsigned char *)getauxval(AT_SYSINFO_EHDR); + if (vdso) { + fprintf(stderr, "vdso found at address %p\n", vdso); + } else { + fprintf(stderr, "error: AT_SYSINFO_EHDR was not in auxiliary values\n"); + return 1; + } + + f = fopen(OUTPATH, "wb"); + if (!f) { + fprintf(stderr, "error: fopen(%`'s) failed\n", OUTPATH); + return 1; + } + + struct sigaction sa = { + .sa_sigaction = OnSegmentationFault, + .sa_flags = SA_SIGINFO, + }; + sigaction(SIGSEGV, &sa, 0); + sigaction(SIGBUS, &sa, 0); + + p = vdso; + for (;;) { + byte = *p++; + if (!finished) { + fputc(byte, f); + } else { + break; + } + } + + fclose(f); + fprintf(stderr, "%zu bytes dumped to %s\n", p - vdso, OUTPATH); + + return 0; +} diff --git a/tool/viz/vdsosyms.c b/tool/viz/vdsosyms.c new file mode 100644 index 000000000..39fecbfd2 --- /dev/null +++ b/tool/viz/vdsosyms.c @@ -0,0 +1,166 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/strace.internal.h" +#include "libc/elf/def.h" +#include "libc/elf/scalar.h" +#include "libc/elf/struct/ehdr.h" +#include "libc/elf/struct/phdr.h" +#include "libc/elf/struct/sym.h" +#include "libc/elf/struct/verdaux.h" +#include "libc/elf/struct/verdef.h" +#include "libc/intrin/kprintf.h" +#include "libc/runtime/runtime.h" +#include "libc/sysv/consts/auxv.h" + +static inline void PrintDsoSymbolVersions(Elf64_Verdef *vd, int sym, + char *strtab) { + Elf64_Verdaux *aux; + for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) { + if (!(vd->vd_flags & VER_FLG_BASE) && + (vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) { + aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux); + kprintf(" %s", strtab + aux->vda_name); + } + if (!vd->vd_next) { + break; + } + } +} + +int PrintVdsoSymbols(void) { + void *p; + size_t i; + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + char *strtab = 0; + size_t *dyn, base; + unsigned long *ap; + Elf64_Sym *symtab = 0; + uint16_t *versym = 0; + Elf_Symndx *hashtab = 0; + Elf64_Verdef *verdef = 0; + const char *typename, *bindname; + + for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) { + if (ap[0] == AT_SYSINFO_EHDR) { + ehdr = (void *)ap[1]; + break; + } + } + if (!ehdr) { + kprintf("error: AT_SYSINFO_EHDR not found\n"); + return 1; + } + + phdr = (void *)((char *)ehdr + ehdr->e_phoff); + for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum; + i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) { + switch (phdr->p_type) { + case PT_LOAD: + // modern linux uses the base address zero, but elders + // e.g. rhel7 uses the base address 0xffffffffff700000 + base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr; + break; + case PT_DYNAMIC: + dyn = (void *)((char *)ehdr + phdr->p_offset); + break; + default: + break; + } + } + if (!dyn || base == -1) { + kprintf("error: missing program headers\n"); + return 2; + } + + for (i = 0; dyn[i]; i += 2) { + p = (void *)(base + dyn[i + 1]); + switch (dyn[i]) { + case DT_STRTAB: + strtab = p; + break; + case DT_SYMTAB: + symtab = p; + break; + case DT_HASH: + hashtab = p; + break; + case DT_VERSYM: + versym = p; + break; + case DT_VERDEF: + verdef = p; + break; + } + } + if (!verdef) { + versym = 0; + } + + if (!strtab || !symtab || !hashtab) { + kprintf("error: strtab/symtab/hashtab not found\n"); + return 3; + } + + for (i = 0; i < hashtab[1]; i++) { + if (!symtab[i].st_shndx) { + continue; + } + + switch (ELF64_ST_BIND(symtab[i].st_info)) { + case STB_LOCAL: + bindname = "locl"; + break; + case STB_GLOBAL: + bindname = "glob"; + break; + case STB_WEAK: + bindname = "weak"; + break; + default: + bindname = "????"; + break; + } + + switch (ELF64_ST_TYPE(symtab[i].st_info)) { + case STT_FUNC: + typename = "func"; + break; + case STT_OBJECT: + typename = " obj"; + break; + case STT_NOTYPE: + typename = "none"; + break; + default: + typename = "????"; + break; + } + + kprintf("%s %s %-40s", bindname, typename, strtab + symtab[i].st_name); + PrintDsoSymbolVersions(verdef, versym[i], strtab); + kprintf("\n"); + } + + return 0; +} + +int main(int argc, char *argv[]) { + return PrintVdsoSymbols(); +} diff --git a/tool/viz/viz.mk b/tool/viz/viz.mk index 744f644f8..17861744c 100644 --- a/tool/viz/viz.mk +++ b/tool/viz/viz.mk @@ -69,7 +69,7 @@ o/$(MODE)/tool/viz/%.com.dbg: \ o/$(MODE)/tool/viz/%.o \ o/$(MODE)/tool/viz/viz.pkg \ $(CRT) \ - $(APE) + $(APE_NO_MODIFY_SELF) @$(APELINK) o/$(MODE)/tool/viz/printimage.com.dbg: \