mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Make build hermetic without shell scripts
- Fix some minor issues in ar.com - Have execve() look for `ape` command - Rewrite NT paths using /c/ rather /??/c:/ - Replace broken GCC symlinks with .sym files - Rewrite $PATH environment variables on startup - Make $(APE_NO_MODIFY_SELF) the default bootloader - Add all build command dependencies to build/bootstrap - Get the repository mostly building from source on non-Linux
This commit is contained in:
parent
d44ff6ce1f
commit
d230a01222
160 changed files with 2754 additions and 1342 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -11,4 +11,3 @@ __pycache__
|
||||||
/TAGS
|
/TAGS
|
||||||
/bx_enh_dbg.ini
|
/bx_enh_dbg.ini
|
||||||
/tool/emacs/*.elc
|
/tool/emacs/*.elc
|
||||||
/usr/share/dict/words
|
|
||||||
|
|
18
Makefile
18
Makefile
|
@ -59,9 +59,9 @@
|
||||||
#
|
#
|
||||||
# build/config.mk
|
# build/config.mk
|
||||||
|
|
||||||
SHELL = /bin/sh
|
SHELL = build/bootstrap/cocmd.com
|
||||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win7 win10 xnu
|
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win7 win10 xnu
|
||||||
SANITY := $(shell build/sanitycheck $$PPID)
|
#SANITY := $(shell build/sanitycheck $$PPID)
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.DELETE_ON_ERROR:
|
.DELETE_ON_ERROR:
|
||||||
|
@ -229,7 +229,7 @@ depend: o/$(MODE)/depend
|
||||||
tags: TAGS HTAGS
|
tags: TAGS HTAGS
|
||||||
|
|
||||||
o/$(MODE)/.x:
|
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))))
|
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||||
$(file >$@,$(SRCS))
|
$(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)))
|
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||||
|
|
||||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
|
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
|
||||||
@rm -f $@
|
@$(RM) $@
|
||||||
@$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@
|
@$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@
|
||||||
|
|
||||||
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
|
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
|
||||||
@rm -f $@
|
@$(RM) $@
|
||||||
@$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@
|
@$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@
|
||||||
|
|
||||||
loc: o/$(MODE)/tool/build/summy.com
|
loc: o/$(MODE)/tool/build/summy.com
|
||||||
|
@ -390,9 +390,9 @@ $(SRCS):
|
||||||
$(HDRS):
|
$(HDRS):
|
||||||
$(INCS):
|
$(INCS):
|
||||||
.DEFAULT:
|
.DEFAULT:
|
||||||
@echo >&2
|
@$(ECHO) >&2
|
||||||
@echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2
|
@$(ECHO) NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2
|
||||||
@echo >&2
|
@$(ECHO) >&2
|
||||||
rm -f o/$(MODE)/depend
|
$(RM) o/$(MODE)/depend
|
||||||
|
|
||||||
-include o/$(MODE)/depend
|
-include o/$(MODE)/depend
|
||||||
|
|
82
README.md
82
README.md
|
@ -64,15 +64,19 @@ that, you can use the following flag to turn your binary into the
|
||||||
platform local format (ELF or Mach-O):
|
platform local format (ELF or Mach-O):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
$ file hello.com
|
||||||
|
hello.com: DOS/MBR boot sector
|
||||||
./hello.com --assimilate
|
./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
|
There's also some other useful flags that get baked into your binary by
|
||||||
default:
|
default:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./hello.com --strace
|
./hello.com --strace # log system calls to stderr
|
||||||
./hello.com --ftrace
|
./hello.com --ftrace # log function calls to stderr
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want your `hello.com` program to be much tinier, more on the
|
If you want your `hello.com` program to be much tinier, more on the
|
||||||
|
@ -100,22 +104,85 @@ Windows](https://justine.lol/cosmopolitan/windows-compiling.html)
|
||||||
tutorial. It's needed because the ELF object format is what makes
|
tutorial. It's needed because the ELF object format is what makes
|
||||||
universal binaries possible.
|
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
|
## Source Builds
|
||||||
|
|
||||||
Cosmopolitan can be compiled from source on any Linux distro. GNU make
|
Cosmopolitan can be compiled from source on any Linux distro. First, you
|
||||||
needs to be installed beforehand. This is a freestanding hermetic
|
need to download or clone the repository.
|
||||||
repository that bootstraps using a vendored static gcc9 executable.
|
|
||||||
No further dependencies are required.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz
|
wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz
|
||||||
tar xf cosmopolitan.tar.gz # see releases page
|
tar xf cosmopolitan.tar.gz # see releases page
|
||||||
cd cosmopolitan
|
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
|
o//examples/hello.com
|
||||||
find o -name \*.com | xargs ls -rShal | less
|
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
|
## GDB
|
||||||
|
|
||||||
Here's the recommended `~/.gdbinit` config:
|
Here's the recommended `~/.gdbinit` config:
|
||||||
|
@ -159,4 +226,3 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||||
| FreeBSD | 12 | 2018 |
|
| FreeBSD | 12 | 2018 |
|
||||||
| OpenBSD | 6.4 | 2018 |
|
| OpenBSD | 6.4 | 2018 |
|
||||||
| NetBSD | 9.1 | 2020 |
|
| NetBSD | 9.1 | 2020 |
|
||||||
| GNU Make | 4.0 | 2015 |
|
|
||||||
|
|
109
ape/ape.mk
109
ape/ape.mk
|
@ -15,38 +15,38 @@
|
||||||
|
|
||||||
PKGS += APE
|
PKGS += APE
|
||||||
|
|
||||||
APE = o/$(MODE)/ape/ape.o \
|
APE = o/$(MODE)/ape/ape.o \
|
||||||
o/$(MODE)/ape/ape.lds
|
o/$(MODE)/ape/ape.lds
|
||||||
|
|
||||||
APE_NO_MODIFY_SELF = \
|
APE_NO_MODIFY_SELF = \
|
||||||
o/$(MODE)/ape/ape.lds \
|
o/$(MODE)/ape/ape.lds \
|
||||||
o/$(MODE)/ape/ape-no-modify-self.o
|
o/$(MODE)/ape/ape-no-modify-self.o
|
||||||
|
|
||||||
APE_COPY_SELF = \
|
APE_COPY_SELF = \
|
||||||
o/$(MODE)/ape/ape.lds \
|
o/$(MODE)/ape/ape.lds \
|
||||||
o/$(MODE)/ape/ape-copy-self.o
|
o/$(MODE)/ape/ape-copy-self.o
|
||||||
|
|
||||||
APELINK = \
|
APELINK = \
|
||||||
$(COMPILE) \
|
$(COMPILE) \
|
||||||
-ALINK.ape \
|
-ALINK.ape \
|
||||||
$(LINK) \
|
$(LINK) \
|
||||||
$(LINKARGS) \
|
$(LINKARGS) \
|
||||||
$(OUTPUT_OPTION)
|
$(OUTPUT_OPTION)
|
||||||
|
|
||||||
APE_LOADER_FLAGS = \
|
APE_LOADER_FLAGS = \
|
||||||
-DNDEBUG \
|
-DNDEBUG \
|
||||||
-iquote. \
|
-iquote. \
|
||||||
-Wall \
|
-Wall \
|
||||||
-Wextra \
|
-Wextra \
|
||||||
-fpie \
|
-fpie \
|
||||||
-Os \
|
-Os \
|
||||||
-ffreestanding \
|
-ffreestanding \
|
||||||
-mgeneral-regs-only \
|
-mgeneral-regs-only \
|
||||||
-mno-red-zone \
|
-mno-red-zone \
|
||||||
-fno-ident \
|
-fno-ident \
|
||||||
-fno-gnu-unique \
|
-fno-gnu-unique \
|
||||||
-c \
|
-c \
|
||||||
$(OUTPUT_OPTION) \
|
$(OUTPUT_OPTION) \
|
||||||
$<
|
$<
|
||||||
|
|
||||||
APE_FILES := $(wildcard ape/*.*)
|
APE_FILES := $(wildcard ape/*.*)
|
||||||
|
@ -58,32 +58,32 @@ APE_SRCS = $(APE_SRCS_C) $(APE_SRCS_S)
|
||||||
APE_OBJS = $(APE_SRCS_S:%.S=o/$(MODE)/%.o)
|
APE_OBJS = $(APE_SRCS_S:%.S=o/$(MODE)/%.o)
|
||||||
APE_CHECKS = $(APE_HDRS:%=o/%.ok)
|
APE_CHECKS = $(APE_HDRS:%=o/%.ok)
|
||||||
|
|
||||||
o/$(MODE)/ape/ape.lds: \
|
o/$(MODE)/ape/ape.lds: \
|
||||||
ape/ape.lds \
|
ape/ape.lds \
|
||||||
ape/macros.internal.h \
|
ape/macros.internal.h \
|
||||||
libc/dce.h \
|
libc/dce.h \
|
||||||
libc/zip.h
|
libc/zip.h
|
||||||
|
|
||||||
o/ape/idata.inc: \
|
o/ape/idata.inc: \
|
||||||
ape/idata.internal.h \
|
ape/idata.internal.h \
|
||||||
ape/relocations.h
|
ape/relocations.h
|
||||||
|
|
||||||
o/$(MODE)/ape/ape-no-modify-self.o: \
|
o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||||
ape/ape.S \
|
ape/ape.S \
|
||||||
o/$(MODE)/ape/ape.elf
|
o/$(MODE)/ape/ape.elf
|
||||||
@$(COMPILE) \
|
@$(COMPILE) \
|
||||||
-AOBJECTIFY.S \
|
-AOBJECTIFY.S \
|
||||||
$(OBJECTIFY.S) \
|
$(OBJECTIFY.S) \
|
||||||
$(OUTPUT_OPTION) \
|
$(OUTPUT_OPTION) \
|
||||||
-DAPE_NO_MODIFY_SELF \
|
-DAPE_NO_MODIFY_SELF \
|
||||||
-DAPE_LOADER="\"o/$(MODE)/ape/ape.elf\"" $<
|
-DAPE_LOADER='"o/$(MODE)/ape/ape.elf"' $<
|
||||||
|
|
||||||
o/$(MODE)/ape/ape-copy-self.o: \
|
o/$(MODE)/ape/ape-copy-self.o: \
|
||||||
ape/ape.S
|
ape/ape.S
|
||||||
@$(COMPILE) \
|
@$(COMPILE) \
|
||||||
-AOBJECTIFY.S \
|
-AOBJECTIFY.S \
|
||||||
$(OBJECTIFY.S) \
|
$(OBJECTIFY.S) \
|
||||||
$(OUTPUT_OPTION) \
|
$(OUTPUT_OPTION) \
|
||||||
-DAPE_NO_MODIFY_SELF $<
|
-DAPE_NO_MODIFY_SELF $<
|
||||||
|
|
||||||
o/$(MODE)/ape/loader.o: ape/loader.c
|
o/$(MODE)/ape/loader.o: ape/loader.c
|
||||||
|
@ -103,22 +103,23 @@ o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c
|
||||||
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
|
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.macho: o/$(MODE)/ape/ape.macho.dbg
|
||||||
|
|
||||||
o/$(MODE)/ape/ape.elf.dbg: \
|
o/$(MODE)/ape/ape.elf.dbg: \
|
||||||
o/$(MODE)/ape/loader.o \
|
o/$(MODE)/ape/loader.o \
|
||||||
o/$(MODE)/ape/loader-elf.o \
|
o/$(MODE)/ape/loader-elf.o \
|
||||||
ape/loader.lds
|
ape/loader.lds
|
||||||
@$(ELFLINK) -z max-page-size=0x10
|
@$(ELFLINK) -z max-page-size=0x10
|
||||||
|
|
||||||
o/$(MODE)/ape/ape.macho.dbg: \
|
o/$(MODE)/ape/ape.macho.dbg: \
|
||||||
o/$(MODE)/ape/loader-xnu.o \
|
o/$(MODE)/ape/loader-xnu.o \
|
||||||
o/$(MODE)/ape/loader-macho.o \
|
o/$(MODE)/ape/loader-macho.o \
|
||||||
ape/loader-macho.lds
|
ape/loader-macho.lds
|
||||||
@$(ELFLINK) -z max-page-size=0x10
|
@$(ELFLINK) -z max-page-size=0x10
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/ape
|
.PHONY: o/$(MODE)/ape
|
||||||
o/$(MODE)/ape: $(APE) \
|
o/$(MODE)/ape: $(APE_CHECKS) \
|
||||||
$(APE_CHECKS) \
|
o/$(MODE)/ape/ape.o \
|
||||||
o/$(MODE)/ape/ape.elf \
|
o/$(MODE)/ape/ape.lds \
|
||||||
o/$(MODE)/ape/ape.macho \
|
o/$(MODE)/ape/ape.elf \
|
||||||
o/$(MODE)/ape/ape-copy-self.o \
|
o/$(MODE)/ape/ape.macho \
|
||||||
|
o/$(MODE)/ape/ape-copy-self.o \
|
||||||
o/$(MODE)/ape/ape-no-modify-self.o
|
o/$(MODE)/ape/ape-no-modify-self.o
|
||||||
|
|
Binary file not shown.
BIN
build/bootstrap/cocmd.com
Executable file
BIN
build/bootstrap/cocmd.com
Executable file
Binary file not shown.
Binary file not shown.
BIN
build/bootstrap/cp.com
Executable file
BIN
build/bootstrap/cp.com
Executable file
Binary file not shown.
BIN
build/bootstrap/echo.com
Executable file
BIN
build/bootstrap/echo.com
Executable file
Binary file not shown.
BIN
build/bootstrap/gzip.com
Executable file
BIN
build/bootstrap/gzip.com
Executable file
Binary file not shown.
BIN
build/bootstrap/make.com
Executable file
BIN
build/bootstrap/make.com
Executable file
Binary file not shown.
Binary file not shown.
BIN
build/bootstrap/mkdir.com
Executable file
BIN
build/bootstrap/mkdir.com
Executable file
Binary file not shown.
Binary file not shown.
BIN
build/bootstrap/pwd.com
Executable file
BIN
build/bootstrap/pwd.com
Executable file
Binary file not shown.
BIN
build/bootstrap/rm.com
Executable file
BIN
build/bootstrap/rm.com
Executable file
Binary file not shown.
BIN
build/bootstrap/touch.com
Executable file
BIN
build/bootstrap/touch.com
Executable file
Binary file not shown.
BIN
build/bootstrap/unbundle.com
Executable file
BIN
build/bootstrap/unbundle.com
Executable file
Binary file not shown.
Binary file not shown.
|
@ -50,15 +50,42 @@ ARFLAGS = rcsD
|
||||||
ZFLAGS ?=
|
ZFLAGS ?=
|
||||||
XARGS ?= xargs -P4 -rs8000
|
XARGS ?= xargs -P4 -rs8000
|
||||||
DOT ?= dot
|
DOT ?= dot
|
||||||
GZ ?= gzip
|
|
||||||
CLANG = clang
|
CLANG = clang
|
||||||
FC = gfortran #/opt/cross9f/bin/x86_64-linux-musl-gfortran
|
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
|
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
|
PKG = build/bootstrap/package.com
|
||||||
MKDEPS = build/bootstrap/mkdeps.com
|
MKDEPS = build/bootstrap/mkdeps.com
|
||||||
ZIPOBJ = build/bootstrap/zipobj.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
|
AS = o/third_party/gcc/bin/x86_64-linux-musl-as
|
||||||
CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||||
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
|
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
|
STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip
|
||||||
OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy
|
OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy
|
||||||
OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump
|
OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump
|
||||||
ADDR2LINE = $(shell pwd)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
|
ADDR2LINE = $(shell build/bootstrap/pwd.com)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
|
||||||
|
endif
|
||||||
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)
|
|
||||||
|
|
||||||
export ADDR2LINE
|
export ADDR2LINE
|
||||||
export LC_ALL
|
export LC_ALL
|
||||||
|
export MKDIR
|
||||||
export MODE
|
export MODE
|
||||||
export SOURCE_DATE_EPOCH
|
export SOURCE_DATE_EPOCH
|
||||||
export TMPDIR
|
export TMPDIR
|
||||||
|
@ -115,7 +136,7 @@ TRADITIONAL = \
|
||||||
DEFAULT_CCFLAGS = \
|
DEFAULT_CCFLAGS = \
|
||||||
-Wall \
|
-Wall \
|
||||||
-Werror \
|
-Werror \
|
||||||
-fdebug-prefix-map="$(PWD)"= \
|
-fdebug-prefix-map='$(PWD)'= \
|
||||||
-frecord-gcc-switches
|
-frecord-gcc-switches
|
||||||
|
|
||||||
DEFAULT_OFLAGS = \
|
DEFAULT_OFLAGS = \
|
||||||
|
@ -180,7 +201,7 @@ PYFLAGS = \
|
||||||
ASONLYFLAGS = \
|
ASONLYFLAGS = \
|
||||||
-c \
|
-c \
|
||||||
-g \
|
-g \
|
||||||
--debug-prefix-map="$(PWD)"=
|
--debug-prefix-map='$(PWD)'=
|
||||||
|
|
||||||
DEFAULT_LDLIBS =
|
DEFAULT_LDLIBS =
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
20
build/hello
20
build/hello
|
@ -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
|
|
|
@ -29,7 +29,6 @@ o/%.o: %.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx
|
||||||
o/%.o: o/%.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
|
o/%.o: o/%.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
|
||||||
o/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
|
o/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
|
||||||
o/%.inc: %.h ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) -D__ASSEMBLER__ -P $<
|
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/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
|
||||||
o/%.okk: % ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -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) $<
|
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)/%.real.o: %.c ; @$(COMPILE) -AOBJECTIFY.real $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
o/$(MODE)/%.runs: o/$(MODE)/% ; @$(COMPILE) -ACHECK -tT$@ $< $(TESTARGS)
|
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)/%.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: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||||
o/$(MODE)/%-gcc.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -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,$^)
|
$(file >$@.args,$^)
|
||||||
@$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ @$@.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
|
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
|
||||||
@$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
|
@$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,11 @@
|
||||||
#include "third_party/linenoise/linenoise.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
|
* 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
|
* works on Windows and, unlike CMD.EXE, has CTRL-P, CTRL-R, and other
|
||||||
* which alone make it so much better.
|
* GNU Emacs / Readline keyboard shortcuts.
|
||||||
*
|
*
|
||||||
* One day we'll have UNBOURNE.COM working on Windows but the code isn't
|
* One day we'll have UNBOURNE.COM working on Windows but the code isn't
|
||||||
* very maintainable sadly.
|
* very maintainable sadly.
|
||||||
|
@ -184,8 +184,8 @@ int main(int argc, char *argv[]) {
|
||||||
args = xrealloc(args, (++n + 1) * sizeof(*args));
|
args = xrealloc(args, (++n + 1) * sizeof(*args));
|
||||||
args[n - 1] = arg;
|
args[n - 1] = arg;
|
||||||
args[n - 0] = 0;
|
args[n - 0] = 0;
|
||||||
start = 0;
|
|
||||||
}
|
}
|
||||||
|
start = 0;
|
||||||
}
|
}
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
if ((prog = commandv(args[0], path, sizeof(path)))) {
|
if ((prog = commandv(args[0], path, sizeof(path)))) {
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,29 +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/stdio/stdio.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
int i, j;
|
|
||||||
bool wantnewline;
|
|
||||||
if (argc > 1 && !strcmp(argv[1], "-n")) {
|
|
||||||
i = 2;
|
|
||||||
wantnewline = false;
|
|
||||||
} else {
|
|
||||||
i = 1;
|
|
||||||
wantnewline = true;
|
|
||||||
}
|
|
||||||
for (j = 0; i + j < argc; ++j) {
|
|
||||||
if (j) fputc(' ', stdout);
|
|
||||||
fputs(argv[i + j], stdout);
|
|
||||||
}
|
|
||||||
if (wantnewline) fputc('\n', stdout);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -3,6 +3,12 @@
|
||||||
|
|
||||||
PKGS += EXAMPLES
|
PKGS += EXAMPLES
|
||||||
|
|
||||||
|
ifeq ($(MODE),tiny)
|
||||||
|
EXAMPLES_BOOTLOADER = $(CRT) $(APE)
|
||||||
|
else
|
||||||
|
EXAMPLES_BOOTLOADER = $(CRT) $(APE_NO_MODIFY_SELF)
|
||||||
|
endif
|
||||||
|
|
||||||
EXAMPLES_FILES := $(wildcard examples/*)
|
EXAMPLES_FILES := $(wildcard examples/*)
|
||||||
EXAMPLES_MAINS_S = $(filter %.S,$(EXAMPLES_FILES))
|
EXAMPLES_MAINS_S = $(filter %.S,$(EXAMPLES_FILES))
|
||||||
EXAMPLES_MAINS_C = $(filter %.c,$(EXAMPLES_FILES))
|
EXAMPLES_MAINS_C = $(filter %.c,$(EXAMPLES_FILES))
|
||||||
|
@ -100,8 +106,7 @@ o/$(MODE)/examples/%.com.dbg: \
|
||||||
$(EXAMPLES_DEPS) \
|
$(EXAMPLES_DEPS) \
|
||||||
o/$(MODE)/examples/%.o \
|
o/$(MODE)/examples/%.o \
|
||||||
o/$(MODE)/examples/examples.pkg \
|
o/$(MODE)/examples/examples.pkg \
|
||||||
$(CRT) \
|
$(EXAMPLES_BOOTLOADER)
|
||||||
$(APE)
|
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/examples/nomodifyself.com.dbg: \
|
o/$(MODE)/examples/nomodifyself.com.dbg: \
|
||||||
|
@ -112,21 +117,12 @@ o/$(MODE)/examples/nomodifyself.com.dbg: \
|
||||||
$(APE_NO_MODIFY_SELF)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/examples/greenbean.com.dbg: \
|
|
||||||
$(EXAMPLES_DEPS) \
|
|
||||||
o/$(MODE)/examples/greenbean.o \
|
|
||||||
o/$(MODE)/examples/examples.pkg \
|
|
||||||
$(CRT) \
|
|
||||||
$(APE_NO_MODIFY_SELF)
|
|
||||||
@$(APELINK)
|
|
||||||
|
|
||||||
o/$(MODE)/examples/hellolua.com.dbg: \
|
o/$(MODE)/examples/hellolua.com.dbg: \
|
||||||
$(EXAMPLES_DEPS) \
|
$(EXAMPLES_DEPS) \
|
||||||
o/$(MODE)/examples/hellolua.o \
|
o/$(MODE)/examples/hellolua.o \
|
||||||
o/$(MODE)/examples/hellolua.lua.zip.o \
|
o/$(MODE)/examples/hellolua.lua.zip.o \
|
||||||
o/$(MODE)/examples/examples.pkg \
|
o/$(MODE)/examples/examples.pkg \
|
||||||
$(CRT) \
|
$(EXAMPLES_BOOTLOADER)
|
||||||
$(APE)
|
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/examples/ispell.com.dbg: \
|
o/$(MODE)/examples/ispell.com.dbg: \
|
||||||
|
@ -134,8 +130,7 @@ o/$(MODE)/examples/ispell.com.dbg: \
|
||||||
o/$(MODE)/examples/ispell.o \
|
o/$(MODE)/examples/ispell.o \
|
||||||
o/$(MODE)/usr/share/dict/words.zip.o \
|
o/$(MODE)/usr/share/dict/words.zip.o \
|
||||||
o/$(MODE)/examples/examples.pkg \
|
o/$(MODE)/examples/examples.pkg \
|
||||||
$(CRT) \
|
$(EXAMPLES_BOOTLOADER)
|
||||||
$(APE)
|
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/examples/nesemu1.com.dbg: \
|
o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||||
|
@ -145,8 +140,7 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||||
o/$(MODE)/usr/share/rom/zelda.nes.zip.o \
|
o/$(MODE)/usr/share/rom/zelda.nes.zip.o \
|
||||||
o/$(MODE)/usr/share/rom/tetris.nes.zip.o \
|
o/$(MODE)/usr/share/rom/tetris.nes.zip.o \
|
||||||
o/$(MODE)/examples/examples.pkg \
|
o/$(MODE)/examples/examples.pkg \
|
||||||
$(CRT) \
|
$(EXAMPLES_BOOTLOADER)
|
||||||
$(APE)
|
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/examples/nesemu1.com: \
|
o/$(MODE)/examples/nesemu1.com: \
|
||||||
|
@ -160,12 +154,15 @@ o/$(MODE)/examples/nesemu1.com: \
|
||||||
o/$(MODE)/examples/.nesemu1/.symtab
|
o/$(MODE)/examples/.nesemu1/.symtab
|
||||||
|
|
||||||
o/$(MODE)/examples/nesemu1.o: QUOTA += -M512m
|
o/$(MODE)/examples/nesemu1.o: QUOTA += -M512m
|
||||||
|
o/$(MODE)/usr/share/dict/words.zip.o: ZIPOBJ_FLAGS += -C2
|
||||||
|
|
||||||
$(EXAMPLES_OBJS): examples/examples.mk
|
$(EXAMPLES_OBJS): examples/examples.mk
|
||||||
|
|
||||||
usr/share/dict/words: usr/share/dict/words.gz
|
o/$(MODE)/usr/share/dict/words: \
|
||||||
@mkdir -p $(@D)
|
usr/share/dict/words.gz \
|
||||||
@$(GZ) $(ZFLAGS) -d <$< >$@
|
o/$(MODE)/tool/build/gzip.com
|
||||||
|
@$(MKDIR) $(@D)
|
||||||
|
@o/$(MODE)/tool/build/gzip.com $(ZFLAGS) -cd <$< >$@
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/examples
|
.PHONY: o/$(MODE)/examples
|
||||||
o/$(MODE)/examples: \
|
o/$(MODE)/examples: \
|
||||||
|
|
|
@ -60,7 +60,7 @@ o/$(MODE)/examples/package/%.com.dbg: \
|
||||||
$(EXAMPLES_PACKAGE_DEPS) \
|
$(EXAMPLES_PACKAGE_DEPS) \
|
||||||
o/$(MODE)/examples/package/%.o \
|
o/$(MODE)/examples/package/%.o \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
# Invalidates objects in package when makefile is edited.
|
# Invalidates objects in package when makefile is edited.
|
||||||
|
|
|
@ -95,7 +95,7 @@ o/$(MODE)/examples/pyapp/pyapp.com.dbg: \
|
||||||
o/$(MODE)/examples/pyapp/pyapp.pkg \
|
o/$(MODE)/examples/pyapp/pyapp.pkg \
|
||||||
o/$(MODE)/examples/pyapp/pyapp.o \
|
o/$(MODE)/examples/pyapp/pyapp.o \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
$(LINK) $(LINKARGS) -o $@
|
$(LINK) $(LINKARGS) -o $@
|
||||||
|
|
||||||
# # Unwrap the APE .COM binary, that's embedded within the linked file
|
# # Unwrap the APE .COM binary, that's embedded within the linked file
|
||||||
|
|
|
@ -1,29 +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/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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -112,6 +112,7 @@ o/$(MODE)/libc/calls/execl.o \
|
||||||
o/$(MODE)/libc/calls/execle.o \
|
o/$(MODE)/libc/calls/execle.o \
|
||||||
o/$(MODE)/libc/calls/execlp.o \
|
o/$(MODE)/libc/calls/execlp.o \
|
||||||
o/$(MODE)/libc/calls/execve-sysv.o \
|
o/$(MODE)/libc/calls/execve-sysv.o \
|
||||||
|
o/$(MODE)/libc/calls/execve-nt.greg.o \
|
||||||
o/$(MODE)/libc/calls/mkntenvblock.o: \
|
o/$(MODE)/libc/calls/mkntenvblock.o: \
|
||||||
OVERRIDE_CPPFLAGS += \
|
OVERRIDE_CPPFLAGS += \
|
||||||
-DSTACK_FRAME_UNLIMITED
|
-DSTACK_FRAME_UNLIMITED
|
||||||
|
|
|
@ -76,7 +76,7 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
|
||||||
/**
|
/**
|
||||||
* Returns pointer to fastest clock_gettime().
|
* Returns pointer to fastest clock_gettime().
|
||||||
*/
|
*/
|
||||||
clock_gettime_f *__get_clock_gettime(bool *opt_out_isfast) {
|
clock_gettime_f *__clock_gettime_get(bool *opt_out_isfast) {
|
||||||
bool isfast;
|
bool isfast;
|
||||||
clock_gettime_f *res;
|
clock_gettime_f *res;
|
||||||
if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_clock_gettime"))) {
|
if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_clock_gettime"))) {
|
||||||
|
@ -99,6 +99,6 @@ clock_gettime_f *__get_clock_gettime(bool *opt_out_isfast) {
|
||||||
|
|
||||||
hidden int __clock_gettime_init(int clockid, struct timespec *ts) {
|
hidden int __clock_gettime_init(int clockid, struct timespec *ts) {
|
||||||
clock_gettime_f *gettime;
|
clock_gettime_f *gettime;
|
||||||
__clock_gettime = gettime = __get_clock_gettime(0);
|
__clock_gettime = gettime = __clock_gettime_get(0);
|
||||||
return gettime(clockid, ts);
|
return gettime(clockid, ts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ typedef int clock_gettime_f(int, struct timespec *);
|
||||||
|
|
||||||
extern clock_gettime_f *__clock_gettime;
|
extern clock_gettime_f *__clock_gettime;
|
||||||
hidden clock_gettime_f __clock_gettime_init;
|
hidden clock_gettime_f __clock_gettime_init;
|
||||||
hidden clock_gettime_f *__get_clock_gettime(bool *);
|
hidden clock_gettime_f *__clock_gettime_get(bool *);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "libc/calls/ntspawn.h"
|
#include "libc/calls/ntspawn.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/syscall-nt.internal.h"
|
#include "libc/calls/syscall-nt.internal.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/nt/accounting.h"
|
#include "libc/nt/accounting.h"
|
||||||
#include "libc/nt/console.h"
|
#include "libc/nt/console.h"
|
||||||
|
@ -59,13 +60,28 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
||||||
int rc;
|
int rc;
|
||||||
size_t i;
|
size_t i;
|
||||||
uint32_t dwExitCode;
|
uint32_t dwExitCode;
|
||||||
|
char progbuf[PATH_MAX];
|
||||||
struct MemoryIntervals *mm;
|
struct MemoryIntervals *mm;
|
||||||
struct NtStartupInfo startinfo;
|
struct NtStartupInfo startinfo;
|
||||||
struct NtProcessInformation procinfo;
|
struct NtProcessInformation procinfo;
|
||||||
|
|
||||||
|
if (strlen(program) + 4 + 1 > PATH_MAX) {
|
||||||
|
return enametoolong();
|
||||||
|
}
|
||||||
|
|
||||||
// this is a non-recoverable operation, so do some manual validation
|
// this is a non-recoverable operation, so do some manual validation
|
||||||
if (sys_faccessat_nt(AT_FDCWD, program, X_OK, 0) == -1) {
|
if (sys_faccessat_nt(AT_FDCWD, program, X_OK, 0) == -1) {
|
||||||
return eacces();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -16,28 +16,80 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/syscall-sysv.internal.h"
|
#include "libc/calls/syscall-sysv.internal.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/paths.h"
|
#include "libc/paths.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.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 sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||||
|
int e;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
char *buf;
|
||||||
char **shargs;
|
char **shargs;
|
||||||
|
const char *ape;
|
||||||
|
e = errno;
|
||||||
__sys_execve(prog, argv, envp);
|
__sys_execve(prog, argv, envp);
|
||||||
if (errno != ENOEXEC) return -1;
|
if (errno != ENOEXEC) return -1;
|
||||||
for (i = 0; argv[i];) ++i;
|
for (i = 0; argv[i];) ++i;
|
||||||
shargs = alloca((i + 2) * sizeof(char *));
|
buf = alloca(PATH_MAX);
|
||||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
shargs = alloca((i + 4) * sizeof(char *));
|
||||||
if (IsFreebsd() || IsNetbsd()) {
|
if (IsApeBinary(prog) &&
|
||||||
shargs[0] = firstnonnull(commandv("bash", alloca(PATH_MAX), PATH_MAX),
|
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||||
_PATH_BSHELL);
|
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 {
|
} else {
|
||||||
shargs[0] = _PATH_BSHELL;
|
return enoexec();
|
||||||
}
|
}
|
||||||
shargs[1] = prog;
|
errno = e;
|
||||||
return __sys_execve(shargs[0], shargs, envp);
|
return __sys_execve(shargs[0], shargs, envp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,14 +32,21 @@ textwindows char *sys_getcwd_nt(char *buf, size_t size) {
|
||||||
if ((n = GetCurrentDirectory(ARRAYLEN(p), p))) {
|
if ((n = GetCurrentDirectory(ARRAYLEN(p), p))) {
|
||||||
if (4 + n + 1 <= size && 4 + n + 1 <= ARRAYLEN(p)) {
|
if (4 + n + 1 <= size && 4 + n + 1 <= ARRAYLEN(p)) {
|
||||||
tprecode16to8(buf, size, p);
|
tprecode16to8(buf, size, p);
|
||||||
|
i = 0;
|
||||||
j = 0;
|
j = 0;
|
||||||
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
|
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++] = '/';
|
||||||
|
buf[j++] = p[4];
|
||||||
buf[j++] = '/';
|
buf[j++] = '/';
|
||||||
buf[j++] = '?';
|
i += 7;
|
||||||
buf[j++] = '/';
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < n;) {
|
while (i < n) {
|
||||||
x = p[i++] & 0xffff;
|
x = p[i++] & 0xffff;
|
||||||
if (!IsUcs2(x)) {
|
if (!IsUcs2(x)) {
|
||||||
if (i < n) {
|
if (i < n) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
// Obtains WIN32 magic path, e.g. GetTempPathA.
|
// Obtains WIN32 magic path, e.g. GetTempPathA.
|
||||||
|
@ -33,7 +34,13 @@ __getntsyspath:
|
||||||
movpp %rdi,%rcx # call f=%rax(p1=%rcx,p2=%rdx)
|
movpp %rdi,%rcx # call f=%rax(p1=%rcx,p2=%rdx)
|
||||||
sub $40,%rsp
|
sub $40,%rsp
|
||||||
call *%rax
|
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
|
mov -8(%rbp),%ecx # restore %edx param as %ecx
|
||||||
cmp %eax,%ecx # use current dir on overflow
|
cmp %eax,%ecx # use current dir on overflow
|
||||||
cmovbe %edx,%eax
|
cmovbe %edx,%eax
|
||||||
|
|
|
@ -34,6 +34,10 @@
|
||||||
|
|
||||||
char program_executable_name[PATH_MAX];
|
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) {
|
static inline char *StrCat(char buf[PATH_MAX], const char *a, const char *b) {
|
||||||
char *p, *e;
|
char *p, *e;
|
||||||
p = buf;
|
p = buf;
|
||||||
|
@ -56,16 +60,16 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
n = GetModuleFileName(0, u.path16, ARRAYLEN(u.path16));
|
n = GetModuleFileName(0, u.path16, ARRAYLEN(u.path16));
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
|
// turn c:\foo\bar into c:/foo/bar
|
||||||
if (u.path16[i] == '\\') {
|
if (u.path16[i] == '\\') {
|
||||||
u.path16[i] = '/';
|
u.path16[i] = '/';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isalpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') {
|
if (IsAlpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') {
|
||||||
p[0] = '/';
|
// turn c:/... into /c/...
|
||||||
p[1] = '/';
|
u.path16[1] = u.path16[0];
|
||||||
p[2] = '?';
|
u.path16[0] = '/';
|
||||||
p[3] = '/';
|
u.path16[2] = '/';
|
||||||
p += 4;
|
|
||||||
}
|
}
|
||||||
tprecode16to8(p, e - p, u.path16);
|
tprecode16to8(p, e - p, u.path16);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/alg/arraylist2.internal.h"
|
#include "libc/alg/arraylist2.internal.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/calls/ntspawn.h"
|
#include "libc/calls/ntspawn.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/alloca.h"
|
#include "libc/mem/alloca.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
@ -31,15 +33,85 @@
|
||||||
|
|
||||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||||
|
|
||||||
static 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;
|
int a, b;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i;
|
while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i;
|
||||||
return a - b;
|
return a - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InsertString(char **a, size_t i, char *s) {
|
static textwindows void FixPath(char *path) {
|
||||||
size_t j;
|
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) {
|
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
|
||||||
a[j] = a[j - 1];
|
a[j] = a[j - 1];
|
||||||
}
|
}
|
||||||
|
@ -58,18 +130,18 @@ static void InsertString(char **a, size_t i, char *s) {
|
||||||
* @error E2BIG if total number of shorts exceeded ARG_MAX/2 (32767)
|
* @error E2BIG if total number of shorts exceeded ARG_MAX/2 (32767)
|
||||||
*/
|
*/
|
||||||
textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[],
|
textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[],
|
||||||
const char *extravar) {
|
const char *extravar, char buf[ARG_MAX]) {
|
||||||
bool v;
|
bool v;
|
||||||
char *t;
|
char *t;
|
||||||
axdx_t rc;
|
axdx_t rc;
|
||||||
uint64_t w;
|
uint64_t w;
|
||||||
char **vars;
|
char **vars;
|
||||||
wint_t x, y;
|
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++;
|
for (n = 0; envp[n];) n++;
|
||||||
vars = alloca((n + 1) * sizeof(char *));
|
vars = alloca((n + 1) * sizeof(char *));
|
||||||
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
|
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i], buf, &bufi);
|
||||||
if (extravar) InsertString(vars, n++, extravar);
|
if (extravar) InsertString(vars, n++, extravar, buf, &bufi);
|
||||||
for (k = i = 0; i < n; ++i) {
|
for (k = i = 0; i < n; ++i) {
|
||||||
j = 0;
|
j = 0;
|
||||||
v = false;
|
v = false;
|
||||||
|
|
|
@ -31,6 +31,10 @@ static inline bool IsSlash(char c) {
|
||||||
return c == '/' || 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,
|
textwindows static const char *FixNtMagicPath(const char *path,
|
||||||
unsigned flags) {
|
unsigned flags) {
|
||||||
const struct NtMagicPaths *mp = &kNtMagicPaths;
|
const struct NtMagicPaths *mp = &kNtMagicPaths;
|
||||||
|
@ -78,18 +82,51 @@ textwindows int __mkntpath2(const char *path,
|
||||||
*/
|
*/
|
||||||
char16_t *p;
|
char16_t *p;
|
||||||
const char *q;
|
const char *q;
|
||||||
size_t i, n, m, z;
|
bool isdospath;
|
||||||
|
size_t i, n, m, x, z;
|
||||||
if (!path) return efault();
|
if (!path) return efault();
|
||||||
path = FixNtMagicPath(path, flags);
|
path = FixNtMagicPath(path, flags);
|
||||||
p = path16;
|
p = path16;
|
||||||
q = path;
|
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);
|
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 {
|
} else {
|
||||||
z = MIN(260, PATH_MAX);
|
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])) {
|
(IsSlash(q[4]) || !q[4])) {
|
||||||
m = GetTempPath(z, p);
|
m = GetTempPath(z, p);
|
||||||
if (!q[4]) return m;
|
if (!q[4]) return m;
|
||||||
|
@ -99,15 +136,20 @@ textwindows int __mkntpath2(const char *path,
|
||||||
} else {
|
} else {
|
||||||
m = 0;
|
m = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// turn utf-8 into utf-16
|
||||||
n = tprecode8to16(p, z, q).ax;
|
n = tprecode8to16(p, z, q).ax;
|
||||||
if (n >= z - 1) {
|
if (n >= z - 1) {
|
||||||
STRACE("path too long for windows: %#s", path);
|
STRACE("path too long for windows: %#s", path);
|
||||||
return enametoolong();
|
return enametoolong();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// turn slash into backslash
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
if (p[i] == '/') {
|
if (p[i] == '/') {
|
||||||
p[i] = '\\';
|
p[i] = '\\';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m + n;
|
|
||||||
|
return x + m + n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ static long double nowl_vdso(void) {
|
||||||
long double nowl_setup(void) {
|
long double nowl_setup(void) {
|
||||||
bool isfast;
|
bool isfast;
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
__gettime = __get_clock_gettime(&isfast);
|
__gettime = __clock_gettime_get(&isfast);
|
||||||
if (isfast) {
|
if (isfast) {
|
||||||
nowl = nowl_vdso;
|
nowl = nowl_vdso;
|
||||||
} else if (X86_HAVE(INVTSC)) {
|
} else if (X86_HAVE(INVTSC)) {
|
||||||
|
|
|
@ -94,15 +94,15 @@ TryAgain:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = __winerr();
|
rc = __winerr();
|
||||||
STRACE("%s failed: %m", "AccessCheck");
|
STRACE("%s(%#hs) failed: %m", "AccessCheck", pathname);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = __winerr();
|
rc = __winerr();
|
||||||
STRACE("%s failed: %m", "DuplicateToken");
|
STRACE("%s(%#hs) failed: %m", "DuplicateToken", pathname);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = __winerr();
|
rc = __winerr();
|
||||||
STRACE("%s failed: %m", "OpenProcessToken");
|
STRACE("%s(%#hs) failed: %m", "OpenProcessToken", pathname);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
e = GetLastError();
|
e = GetLastError();
|
||||||
|
@ -112,9 +112,11 @@ TryAgain:
|
||||||
goto TryAgain;
|
goto TryAgain;
|
||||||
} else {
|
} else {
|
||||||
rc = enomem();
|
rc = enomem();
|
||||||
|
STRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errno = e;
|
errno = e;
|
||||||
|
STRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname);
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,9 @@ struct SpawnBlock {
|
||||||
struct {
|
struct {
|
||||||
char16_t cmdline[ARG_MAX / 2];
|
char16_t cmdline[ARG_MAX / 2];
|
||||||
char16_t envvars[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,
|
(block = MapViewOfFileEx(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
|
||||||
sizeof(*block), 0)) &&
|
sizeof(*block), 0)) &&
|
||||||
mkntcmdline(block->cmdline, prog, argv) != -1 &&
|
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,
|
CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
|
||||||
opt_lpThreadAttributes, bInheritHandles,
|
opt_lpThreadAttributes, bInheritHandles,
|
||||||
dwCreationFlags | kNtCreateUnicodeEnvironment,
|
dwCreationFlags | kNtCreateUnicodeEnvironment,
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
int mkntcmdline(char16_t[ARG_MAX / 2], const char *, char *const[]) hidden;
|
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 *,
|
int ntspawn(const char *, char *const[], char *const[], const char *,
|
||||||
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
|
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
|
||||||
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
|
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
|
||||||
|
|
|
@ -58,10 +58,9 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
||||||
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
|
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||||
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
|
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
|
||||||
buf[j++] = '/';
|
p[1] = p[0];
|
||||||
buf[j++] = '/';
|
p[0] = '/';
|
||||||
buf[j++] = '?';
|
p[2] = '/';
|
||||||
buf[j++] = '/';
|
|
||||||
}
|
}
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
x = p[i++] & 0xffff;
|
x = p[i++] & 0xffff;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#define _KERNTRACE 0 /* not configurable w/ flag yet */
|
#define _KERNTRACE 0 /* not configurable w/ flag yet */
|
||||||
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
||||||
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
||||||
#define _NTTRACE 1 /* not configurable w/ flag yet */
|
#define _NTTRACE 0 /* not configurable w/ flag yet */
|
||||||
|
|
||||||
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
|
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ i32 sys_mknod(const char *, u32, u64) hidden;
|
||||||
i32 sys_mprotect(void *, u64, i32) hidden;
|
i32 sys_mprotect(void *, u64, i32) hidden;
|
||||||
i32 sys_msync(void *, u64, i32) hidden;
|
i32 sys_msync(void *, u64, i32) hidden;
|
||||||
i32 sys_munmap(void *, u64) 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_openat(i32, const char *, i32, u32) hidden;
|
||||||
i32 sys_pause(void) hidden;
|
i32 sys_pause(void) hidden;
|
||||||
i32 sys_pipe(i32[hasatleast 2]) hidden;
|
i32 sys_pipe(i32[hasatleast 2]) hidden;
|
||||||
|
|
|
@ -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);
|
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.
|
* 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) {
|
if (flags & FLAGS_PRECISION) {
|
||||||
precision = min(strlen(p), precision);
|
precision = min(strlen(p), precision);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ignorenul = false;
|
ignorenul = false;
|
||||||
|
@ -153,6 +138,9 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
||||||
} else if (weaken(strnwidth)) {
|
} else if (weaken(strnwidth)) {
|
||||||
w = weaken(strnwidth)(p, precision, 0);
|
w = weaken(strnwidth)(p, precision, 0);
|
||||||
}
|
}
|
||||||
|
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||||
|
w += 2 + (signbit == 63) + (signbit == 15);
|
||||||
|
}
|
||||||
if (w < width) {
|
if (w < width) {
|
||||||
pad = width - w;
|
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 (__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) {
|
if (justdobytes) {
|
||||||
while (precision--) {
|
while (precision--) {
|
||||||
wc = *p++ & 0xff;
|
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)) {
|
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||||
buf[0] = qchar;
|
buf[0] = qchar;
|
||||||
if (out(buf, arg, 1) == -1) return -1;
|
if (out(buf, arg, 1) == -1) return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pad && (flags & FLAGS_LEFT)) {
|
||||||
|
if (__fmt_pad(out, arg, pad) == -1) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
#define INITIAL_CAPACITY 4
|
#define INITIAL_CAPACITY 4
|
||||||
|
|
||||||
|
nop
|
||||||
|
|
||||||
// Invokes deferred function calls.
|
// Invokes deferred function calls.
|
||||||
//
|
//
|
||||||
// This offers behavior similar to std::unique_ptr. Functions
|
// This offers behavior similar to std::unique_ptr. Functions
|
||||||
|
@ -32,8 +34,6 @@
|
||||||
//
|
//
|
||||||
// @param rax,rdx,xmm0,xmm1,st0,st1 is return value
|
// @param rax,rdx,xmm0,xmm1,st0,st1 is return value
|
||||||
// @see test/libc/runtime/gc_test.c
|
// @see test/libc/runtime/gc_test.c
|
||||||
nop # backtrace workaround
|
|
||||||
// <LIMBO>
|
|
||||||
__gc: decq __garbage(%rip)
|
__gc: decq __garbage(%rip)
|
||||||
mov __garbage(%rip),%r8
|
mov __garbage(%rip),%r8
|
||||||
mov __garbage+16(%rip),%r9
|
mov __garbage+16(%rip),%r9
|
||||||
|
@ -43,17 +43,16 @@ __gc: decq __garbage(%rip)
|
||||||
mov 8(%r8),%r9
|
mov 8(%r8),%r9
|
||||||
mov 16(%r8),%rdi
|
mov 16(%r8),%rdi
|
||||||
push 24(%r8)
|
push 24(%r8)
|
||||||
// </LIMBO>
|
|
||||||
push %rbp
|
push %rbp
|
||||||
mov %rsp,%rbp
|
mov %rsp,%rbp
|
||||||
sub $16,%rsp
|
sub $32,%rsp
|
||||||
push %rax
|
mov %rax,-8(%rbp)
|
||||||
push %rdx
|
mov %rdx,-16(%rbp)
|
||||||
movdqa %xmm0,-16(%rbp)
|
movdqa %xmm0,-32(%rbp)
|
||||||
call *%r9
|
call *%r9
|
||||||
movdqa -16(%rbp),%xmm0
|
movdqa -32(%rbp),%xmm0
|
||||||
pop %rdx
|
mov -16(%rbp),%rdx
|
||||||
pop %rax
|
mov -8(%rbp),%rax
|
||||||
leave
|
leave
|
||||||
ret
|
ret
|
||||||
9: hlt
|
9: hlt
|
||||||
|
|
|
@ -35,23 +35,24 @@ const char *FindDebugBinary(void) {
|
||||||
char *p;
|
char *p;
|
||||||
size_t n;
|
size_t n;
|
||||||
if (!once) {
|
if (!once) {
|
||||||
if (!(res = getenv("COMDBG"))) {
|
p = GetProgramExecutableName();
|
||||||
p = GetProgramExecutableName();
|
n = strlen(p);
|
||||||
n = strlen(p);
|
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
||||||
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
res = p;
|
||||||
res = p;
|
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
||||||
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
n + 4 < ARRAYLEN(buf)) {
|
||||||
n + 4 < ARRAYLEN(buf)) {
|
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
|
||||||
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
|
if (fileexists(buf)) {
|
||||||
if (fileexists(buf)) {
|
res = buf;
|
||||||
res = buf;
|
|
||||||
}
|
|
||||||
} else if (n + 8 < ARRAYLEN(buf)) {
|
|
||||||
mempcpy(mempcpy(buf, p, n), ".com.dbg", 9);
|
|
||||||
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;
|
once = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/tpenc.h"
|
#include "libc/str/tpenc.h"
|
||||||
|
@ -23,6 +24,19 @@
|
||||||
|
|
||||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
#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,
|
static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
|
||||||
size_t dstsize,
|
size_t dstsize,
|
||||||
const char16_t *src) {
|
const char16_t *src) {
|
||||||
|
@ -45,13 +59,51 @@ static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
|
||||||
}
|
}
|
||||||
w = tpenc(x);
|
w = tpenc(x);
|
||||||
do {
|
do {
|
||||||
if (r.ax + 1 >= dstsize) break;
|
if (r.ax + 1 < dstsize) {
|
||||||
dst[r.ax++] = w;
|
dst[r.ax++] = w;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
} while ((w >>= 8));
|
} while ((w >>= 8));
|
||||||
}
|
}
|
||||||
|
if (r.ax < dstsize) {
|
||||||
|
dst[r.ax] = 0;
|
||||||
|
}
|
||||||
return r;
|
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.
|
* 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 *buf, size_t size,
|
||||||
char **envp, size_t max) {
|
char **envp, size_t max) {
|
||||||
int i;
|
int i;
|
||||||
|
char *p;
|
||||||
axdx_t r;
|
axdx_t r;
|
||||||
i = 0;
|
i = 0;
|
||||||
--size;
|
--size;
|
||||||
while (*env) {
|
while (*env) {
|
||||||
if (i + 1 < max) envp[i++] = buf;
|
if (i + 1 < max) envp[i++] = buf;
|
||||||
r = Recode16to8(buf, size, env);
|
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;
|
size -= r.ax + 1;
|
||||||
buf += r.ax + 1;
|
buf += r.ax + 1;
|
||||||
env += r.dx;
|
env += r.dx;
|
||||||
|
|
|
@ -73,6 +73,7 @@ char *xdirname(const char *) paramsnonnull() _XMAL;
|
||||||
char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL;
|
char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL;
|
||||||
char *xreadlink(const char *) paramsnonnull() _XMAL;
|
char *xreadlink(const char *) paramsnonnull() _XMAL;
|
||||||
char *xreadlinkat(int, const char *) paramsnonnull() _XMAL;
|
char *xreadlinkat(int, const char *) paramsnonnull() _XMAL;
|
||||||
|
void xfixpath(void);
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § eXtended apis » time ─╬─│┼
|
│ cosmopolitan § eXtended apis » time ─╬─│┼
|
||||||
|
|
63
libc/x/xfixpath.c
Normal file
63
libc/x/xfixpath.c
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ o/$(MODE)/test/dsp/core/%.com.dbg: \
|
||||||
o/$(MODE)/test/dsp/core/%.o \
|
o/$(MODE)/test/dsp/core/%.o \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/dsp/core
|
.PHONY: o/$(MODE)/test/dsp/core
|
||||||
|
|
|
@ -50,7 +50,7 @@ o/$(MODE)/test/dsp/scale/%.com.dbg: \
|
||||||
o/$(MODE)/test/dsp/scale/scale.pkg \
|
o/$(MODE)/test/dsp/scale/scale.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/dsp/scale
|
.PHONY: o/$(MODE)/test/dsp/scale
|
||||||
|
|
|
@ -45,7 +45,7 @@ o/$(MODE)/test/dsp/tty/%.com.dbg: \
|
||||||
o/$(MODE)/test/dsp/tty/tty.pkg \
|
o/$(MODE)/test/dsp/tty/tty.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/dsp/tty
|
.PHONY: o/$(MODE)/test/dsp/tty
|
||||||
|
|
|
@ -50,7 +50,7 @@ o/$(MODE)/test/libc/alg/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/alg/alg.pkg \
|
o/$(MODE)/test/libc/alg/alg.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_ALG_OBJS): test/libc/alg/test.mk
|
$(TEST_LIBC_ALG_OBJS): test/libc/alg/test.mk
|
||||||
|
|
|
@ -46,7 +46,7 @@ o/$(MODE)/test/libc/bits/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/bits/bits.pkg \
|
o/$(MODE)/test/libc/bits/bits.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_BITS_OBJS): \
|
$(TEST_LIBC_BITS_OBJS): \
|
||||||
|
|
|
@ -35,7 +35,7 @@ TEST(clock_gettime, test) {
|
||||||
ASSERT_NE(0, ts.tv_sec);
|
ASSERT_NE(0, ts.tv_sec);
|
||||||
ASSERT_NE(0, ts.tv_nsec);
|
ASSERT_NE(0, ts.tv_nsec);
|
||||||
if (__is_linux_2_6_23()) {
|
if (__is_linux_2_6_23()) {
|
||||||
ASSERT_GT((intptr_t)__get_clock_gettime(&isfast),
|
ASSERT_GT((intptr_t)__clock_gettime_get(&isfast),
|
||||||
getauxval(AT_SYSINFO_EHDR));
|
getauxval(AT_SYSINFO_EHDR));
|
||||||
ASSERT_TRUE(isfast);
|
ASSERT_TRUE(isfast);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,5 +45,5 @@ TEST(getcwd, testWindows_addsFunnyPrefix) {
|
||||||
if (!IsWindows()) return;
|
if (!IsWindows()) return;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
ASSERT_NE(0, getcwd(path, sizeof(path)));
|
ASSERT_NE(0, getcwd(path, sizeof(path)));
|
||||||
EXPECT_STARTSWITH("//?/", path);
|
EXPECT_STARTSWITH("/C/", path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,17 +20,18 @@
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
char tmp[ARG_MAX];
|
||||||
char16_t envvars[ARG_MAX / 2];
|
char16_t envvars[ARG_MAX / 2];
|
||||||
|
|
||||||
TEST(mkntenvblock, emptyList_onlyOutputsDoubleNulStringTerminator) {
|
TEST(mkntenvblock, emptyList_onlyOutputsDoubleNulStringTerminator) {
|
||||||
char *envp[] = {NULL};
|
char *envp[] = {NULL};
|
||||||
ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL));
|
ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL, tmp));
|
||||||
ASSERT_BINEQ(u" ", envvars);
|
ASSERT_BINEQ(u" ", envvars);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) {
|
TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) {
|
||||||
char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL};
|
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 "
|
ASSERT_BINEQ(u"C = d "
|
||||||
u"H D U C = d "
|
u"H D U C = d "
|
||||||
u"U = b "
|
u"U = b "
|
||||||
|
@ -42,7 +43,7 @@ TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) {
|
||||||
|
|
||||||
TEST(mkntenvblock, extraVar_getsAdded) {
|
TEST(mkntenvblock, extraVar_getsAdded) {
|
||||||
char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL};
|
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 "
|
ASSERT_BINEQ(u"A = a "
|
||||||
u"C = d "
|
u"C = d "
|
||||||
u"H D U C = d "
|
u"H D U C = d "
|
||||||
|
@ -52,3 +53,11 @@ TEST(mkntenvblock, extraVar_getsAdded) {
|
||||||
u" ",
|
u" ",
|
||||||
envvars);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -101,9 +101,10 @@ TEST(readlinkat, statReadsNameLength) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(readlinkat, realpathReturnsLongPath) {
|
TEST(readlinkat, realpathReturnsLongPath) {
|
||||||
if (!IsWindows()) return;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
|
if (!IsWindows()) return;
|
||||||
|
if (!startswith(getcwd(buf, PATH_MAX), "/c/")) return;
|
||||||
ASSERT_SYS(0, 0, touch("froot", 0644));
|
ASSERT_SYS(0, 0, touch("froot", 0644));
|
||||||
ASSERT_STARTSWITH("//?/", realpath("froot", buf));
|
ASSERT_STARTSWITH("/c/", realpath("froot", buf));
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ o/$(MODE)/test/libc/calls/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/calls/calls.pkg \
|
o/$(MODE)/test/libc/calls/calls.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/libc/calls
|
.PHONY: o/$(MODE)/test/libc/calls
|
||||||
|
|
|
@ -53,7 +53,7 @@ o/$(MODE)/test/libc/dns/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/dns/dns.pkg \
|
o/$(MODE)/test/libc/dns/dns.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/libc/dns
|
.PHONY: o/$(MODE)/test/libc/dns
|
||||||
|
|
|
@ -278,6 +278,11 @@ TEST(fmt, p) {
|
||||||
gc(xasprintf("% 10p", 0xffff800000031337)));
|
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) {
|
TEST(fmt, regress) {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
const char *meth = "GET";
|
const char *meth = "GET";
|
||||||
|
|
|
@ -49,7 +49,7 @@ o/$(MODE)/test/libc/fmt/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/fmt/fmt.pkg \
|
o/$(MODE)/test/libc/fmt/fmt.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_FMT_OBJS): test/libc/fmt/test.mk
|
$(TEST_LIBC_FMT_OBJS): test/libc/fmt/test.mk
|
||||||
|
|
|
@ -54,7 +54,7 @@ o/$(MODE)/test/libc/intrin/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/intrin/intrin.pkg \
|
o/$(MODE)/test/libc/intrin/intrin.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_INTRIN_OBJS): \
|
$(TEST_LIBC_INTRIN_OBJS): \
|
||||||
|
|
132
test/libc/log/backtrace.c
Normal file
132
test/libc/log/backtrace.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/mem/io.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
|
@ -40,115 +41,30 @@
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
#include "net/http/escape.h"
|
#include "net/http/escape.h"
|
||||||
|
|
||||||
int StackOverflow(int f(), int n) {
|
STATIC_YOINK("zip_uri_support");
|
||||||
if (n < INT_MAX) {
|
STATIC_YOINK("backtrace.com");
|
||||||
return f(f, n + 1) - 1;
|
STATIC_YOINK("backtrace.com.dbg");
|
||||||
} else {
|
|
||||||
return INT_MAX;
|
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) {
|
static bool OutputHasSymbol(const char *output, const char *s) {
|
||||||
return strstr(output, s) || (!FindDebugBinary() && strstr(output, "NULL"));
|
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;
|
|
||||||
int (*pStackOverflow)(int (*)(), int) = StackOverflow;
|
|
||||||
|
|
||||||
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));
|
|
||||||
case 9:
|
|
||||||
exit(pStackOverflow(pStackOverflow, 0));
|
|
||||||
default:
|
|
||||||
printf("preventing fork recursion: %s\n", __argv[1]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UNFREED MEMORY
|
// UNFREED MEMORY
|
||||||
// o/dbg/test/libc/log/backtrace_test.com
|
// o/dbg/test/libc/log/backtrace_test.com
|
||||||
// max allocated space 655,360
|
// max allocated space 655,360
|
||||||
|
@ -189,9 +105,8 @@ TEST(ShowCrashReports, testMemoryLeakCrash) {
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
execv(GetProgramExecutableName(),
|
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "6", 0});
|
||||||
(char *const[]){GetProgramExecutableName(), "6", 0});
|
_Exit(127);
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
output = 0;
|
output = 0;
|
||||||
|
@ -267,9 +182,8 @@ TEST(ShowCrashReports, testStackOverrunCrash) {
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
execv(GetProgramExecutableName(),
|
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "5", 0});
|
||||||
(char *const[]){GetProgramExecutableName(), "5", 0});
|
_Exit(127);
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
output = 0;
|
output = 0;
|
||||||
|
@ -376,9 +290,8 @@ TEST(ShowCrashReports, testDivideByZero) {
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
execv(GetProgramExecutableName(),
|
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "1", 0});
|
||||||
(char *const[]){GetProgramExecutableName(), "1", 0});
|
_Exit(127);
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
output = 0;
|
output = 0;
|
||||||
|
@ -454,9 +367,8 @@ TEST(ShowCrashReports, testStackOverflow) {
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
execv(GetProgramExecutableName(),
|
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "9", 0});
|
||||||
(char *const[]){GetProgramExecutableName(), "9", "--strace", 0});
|
_Exit(127);
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
output = 0;
|
output = 0;
|
||||||
|
@ -571,9 +483,8 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
execv(GetProgramExecutableName(),
|
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "2", 0});
|
||||||
(char *const[]){GetProgramExecutableName(), "2", 0});
|
_Exit(127);
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
output = 0;
|
output = 0;
|
||||||
|
@ -650,9 +561,8 @@ TEST(ShowCrashReports, testNpeCrash) {
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
execv(GetProgramExecutableName(),
|
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "7", 0});
|
||||||
(char *const[]){GetProgramExecutableName(), "7", 0});
|
_Exit(127);
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
output = 0;
|
output = 0;
|
||||||
|
@ -710,9 +620,8 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
execv(GetProgramExecutableName(),
|
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "4", 0});
|
||||||
(char *const[]){GetProgramExecutableName(), "4", 0});
|
_Exit(127);
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
output = 0;
|
output = 0;
|
||||||
|
@ -765,9 +674,8 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
dup2(fds[1], 1);
|
dup2(fds[1], 1);
|
||||||
dup2(fds[1], 2);
|
dup2(fds[1], 2);
|
||||||
execv(GetProgramExecutableName(),
|
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "8", 0});
|
||||||
(char *const[]){GetProgramExecutableName(), "8", 0});
|
_Exit(127);
|
||||||
_exit(127);
|
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
output = 0;
|
output = 0;
|
||||||
|
|
|
@ -6,56 +6,82 @@ PKGS += TEST_LIBC_LOG
|
||||||
TEST_LIBC_LOG_SRCS := $(wildcard test/libc/log/*.c)
|
TEST_LIBC_LOG_SRCS := $(wildcard test/libc/log/*.c)
|
||||||
TEST_LIBC_LOG_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_LOG_SRCS))
|
TEST_LIBC_LOG_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_LOG_SRCS))
|
||||||
|
|
||||||
TEST_LIBC_LOG_OBJS = \
|
TEST_LIBC_LOG_OBJS = \
|
||||||
$(TEST_LIBC_LOG_SRCS:%.c=o/$(MODE)/%.o)
|
$(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_SRCS:%.c=o/$(MODE)/%.com)
|
||||||
|
|
||||||
TEST_LIBC_LOG_BINS = \
|
TEST_LIBC_LOG_BINS = \
|
||||||
$(TEST_LIBC_LOG_COMS) \
|
$(TEST_LIBC_LOG_COMS) \
|
||||||
$(TEST_LIBC_LOG_COMS:%=%.dbg)
|
$(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_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_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
|
||||||
|
|
||||||
TEST_LIBC_LOG_DIRECTDEPS = \
|
TEST_LIBC_LOG_DIRECTDEPS = \
|
||||||
LIBC_CALLS \
|
LIBC_CALLS \
|
||||||
LIBC_RUNTIME \
|
LIBC_RUNTIME \
|
||||||
NET_HTTP \
|
NET_HTTP \
|
||||||
LIBC_STDIO \
|
LIBC_STDIO \
|
||||||
LIBC_X \
|
LIBC_X \
|
||||||
LIBC_INTRIN \
|
LIBC_INTRIN \
|
||||||
LIBC_FMT \
|
LIBC_FMT \
|
||||||
LIBC_MEM \
|
LIBC_MEM \
|
||||||
LIBC_NEXGEN32E \
|
LIBC_NEXGEN32E \
|
||||||
LIBC_LOG \
|
LIBC_LOG \
|
||||||
LIBC_STR \
|
LIBC_STR \
|
||||||
LIBC_STUBS \
|
LIBC_STUBS \
|
||||||
LIBC_TESTLIB \
|
LIBC_TESTLIB \
|
||||||
LIBC_SYSV \
|
LIBC_SYSV \
|
||||||
LIBC_LOG
|
LIBC_LOG \
|
||||||
|
LIBC_ZIPOS
|
||||||
|
|
||||||
TEST_LIBC_LOG_DEPS := \
|
TEST_LIBC_LOG_DEPS := \
|
||||||
$(call uniq,$(foreach x,$(TEST_LIBC_LOG_DIRECTDEPS),$($(x))))
|
$(call uniq,$(foreach x,$(TEST_LIBC_LOG_DIRECTDEPS),$($(x))))
|
||||||
|
|
||||||
o/$(MODE)/test/libc/log/log.pkg: \
|
o/$(MODE)/test/libc/log/log.pkg: \
|
||||||
$(TEST_LIBC_LOG_OBJS) \
|
$(TEST_LIBC_LOG_OBJS) \
|
||||||
$(foreach x,$(TEST_LIBC_LOG_DIRECTDEPS),$($(x)_A).pkg)
|
$(foreach x,$(TEST_LIBC_LOG_DIRECTDEPS),$($(x)_A).pkg)
|
||||||
|
|
||||||
o/$(MODE)/test/libc/log/%.com.dbg: \
|
o/$(MODE)/test/libc/log/%.com.dbg: \
|
||||||
$(TEST_LIBC_LOG_DEPS) \
|
$(TEST_LIBC_LOG_DEPS) \
|
||||||
o/$(MODE)/test/libc/log/%.o \
|
o/$(MODE)/test/libc/log/%.o \
|
||||||
o/$(MODE)/test/libc/log/log.pkg \
|
o/$(MODE)/test/libc/log/log.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(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
|
.PHONY: o/$(MODE)/test/libc/log
|
||||||
o/$(MODE)/test/libc/log: \
|
o/$(MODE)/test/libc/log: \
|
||||||
$(TEST_LIBC_LOG_BINS) \
|
$(TEST_LIBC_LOG_BINS) \
|
||||||
$(TEST_LIBC_LOG_CHECKS)
|
$(TEST_LIBC_LOG_CHECKS)
|
||||||
|
|
|
@ -58,7 +58,7 @@ o/$(MODE)/test/libc/mem/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/mem/mem.pkg \
|
o/$(MODE)/test/libc/mem/mem.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_MEM_OBJS): \
|
$(TEST_LIBC_MEM_OBJS): \
|
||||||
|
|
|
@ -55,7 +55,7 @@ o/$(MODE)/test/libc/nexgen32e/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/nexgen32e/nexgen32e.pkg \
|
o/$(MODE)/test/libc/nexgen32e/nexgen32e.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_NEXGEN32E_OBJS): \
|
$(TEST_LIBC_NEXGEN32E_OBJS): \
|
||||||
|
|
|
@ -52,7 +52,7 @@ o/$(MODE)/test/libc/rand/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/rand/rand.pkg \
|
o/$(MODE)/test/libc/rand/rand.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_RAND_OBJS): test/libc/rand/test.mk
|
$(TEST_LIBC_RAND_OBJS): test/libc/rand/test.mk
|
||||||
|
|
|
@ -10,7 +10,7 @@ if [ "$MODE" = opt ] || [ "$MODE" = optlinux ]; then
|
||||||
exit
|
exit
|
||||||
fi
|
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
|
# 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"
|
CMD="o/$MODE/tool/build/blinkenlights.com.dbg -r o/$MODE/examples/hello.com"
|
||||||
|
|
|
@ -124,17 +124,17 @@ o/$(MODE)/test/libc/release/smokeansi.com.dbg: \
|
||||||
o/$(MODE)/ape/ape.o \
|
o/$(MODE)/ape/ape.o \
|
||||||
o/$(MODE)/cosmopolitan.a
|
o/$(MODE)/cosmopolitan.a
|
||||||
|
|
||||||
o/$(MODE)/test/libc/release/metal.ok: \
|
# TODO(jart): Rewrite these shell scripts as C code.
|
||||||
test/libc/release/metal.sh \
|
# o/$(MODE)/test/libc/release/metal.ok: \
|
||||||
o/$(MODE)/examples/hello.com \
|
# test/libc/release/metal.sh \
|
||||||
o/$(MODE)/tool/build/blinkenlights.com.dbg
|
# o/$(MODE)/examples/hello.com \
|
||||||
@$(COMPILE) -ASHTEST -tT$@ $<
|
# o/$(MODE)/tool/build/blinkenlights.com.dbg
|
||||||
|
# @$(COMPILE) -ASHTEST -tT$@ $<
|
||||||
o/$(MODE)/test/libc/release/emulate.ok: \
|
# o/$(MODE)/test/libc/release/emulate.ok: \
|
||||||
test/libc/release/emulate.sh \
|
# test/libc/release/emulate.sh \
|
||||||
o/$(MODE)/examples/hello.com \
|
# o/$(MODE)/examples/hello.com \
|
||||||
o/$(MODE)/tool/build/blinkenlights.com.dbg
|
# o/$(MODE)/tool/build/blinkenlights.com.dbg
|
||||||
@$(COMPILE) -ASHTEST -tT$@ $<
|
# @$(COMPILE) -ASHTEST -tT$@ $<
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/libc/release
|
.PHONY: o/$(MODE)/test/libc/release
|
||||||
o/$(MODE)/test/libc/release: \
|
o/$(MODE)/test/libc/release: \
|
||||||
|
@ -145,6 +145,4 @@ o/$(MODE)/test/libc/release: \
|
||||||
o/$(MODE)/test/libc/release/smokecxx.com \
|
o/$(MODE)/test/libc/release/smokecxx.com \
|
||||||
o/$(MODE)/test/libc/release/smokecxx.com.runs \
|
o/$(MODE)/test/libc/release/smokecxx.com.runs \
|
||||||
o/$(MODE)/test/libc/release/smokeansi.com \
|
o/$(MODE)/test/libc/release/smokeansi.com \
|
||||||
o/$(MODE)/test/libc/release/smokeansi.com.runs \
|
o/$(MODE)/test/libc/release/smokeansi.com.runs
|
||||||
o/$(MODE)/test/libc/release/emulate.ok \
|
|
||||||
o/$(MODE)/test/libc/release/metal.ok
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/linux/mmap.h"
|
#include "libc/linux/mmap.h"
|
||||||
#include "libc/linux/munmap.h"
|
#include "libc/linux/munmap.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
@ -228,6 +229,7 @@ TEST(mmap, cow) {
|
||||||
char *p;
|
char *p;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
|
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)));
|
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
|
||||||
EXPECT_EQ(5, write(fd, "hello", 5));
|
EXPECT_EQ(5, write(fd, "hello", 5));
|
||||||
EXPECT_NE(-1, fdatasync(fd));
|
EXPECT_NE(-1, fdatasync(fd));
|
||||||
|
|
|
@ -58,7 +58,7 @@ o/$(MODE)/test/libc/runtime/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/runtime/runtime.pkg \
|
o/$(MODE)/test/libc/runtime/runtime.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/test/libc/runtime/ape_test.com.dbg: \
|
o/$(MODE)/test/libc/runtime/ape_test.com.dbg: \
|
||||||
|
@ -67,7 +67,7 @@ o/$(MODE)/test/libc/runtime/ape_test.com.dbg: \
|
||||||
o/$(MODE)/test/libc/runtime/runtime.pkg \
|
o/$(MODE)/test/libc/runtime/runtime.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_RUNTIME_OBJS): \
|
$(TEST_LIBC_RUNTIME_OBJS): \
|
||||||
|
|
|
@ -51,7 +51,7 @@ o/$(MODE)/test/libc/sock/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/sock/sock.pkg \
|
o/$(MODE)/test/libc/sock/sock.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk
|
$(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk
|
||||||
|
|
|
@ -57,7 +57,7 @@ o/$(MODE)/test/libc/stdio/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/stdio/stdio.pkg \
|
o/$(MODE)/test/libc/stdio/stdio.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_STDIO_OBJS): \
|
$(TEST_LIBC_STDIO_OBJS): \
|
||||||
|
|
|
@ -72,7 +72,7 @@ o/$(MODE)/test/libc/str/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/str/str.pkg \
|
o/$(MODE)/test/libc/str/str.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/test/libc/str/blake2.com.dbg: \
|
o/$(MODE)/test/libc/str/blake2.com.dbg: \
|
||||||
|
@ -82,7 +82,7 @@ o/$(MODE)/test/libc/str/blake2.com.dbg: \
|
||||||
o/$(MODE)/test/libc/str/str.pkg \
|
o/$(MODE)/test/libc/str/str.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_STR_OBJS): \
|
$(TEST_LIBC_STR_OBJS): \
|
||||||
|
|
|
@ -48,7 +48,7 @@ o/$(MODE)/test/libc/thread/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/thread/thread.pkg \
|
o/$(MODE)/test/libc/thread/thread.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_THREAD_OBJS): \
|
$(TEST_LIBC_THREAD_OBJS): \
|
||||||
|
|
|
@ -43,7 +43,7 @@ o/$(MODE)/test/libc/time/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/time/time.pkg \
|
o/$(MODE)/test/libc/time/time.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/libc/time
|
.PHONY: o/$(MODE)/test/libc/time
|
||||||
|
|
|
@ -53,7 +53,7 @@ o/$(MODE)/test/libc/tinymath/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/tinymath/tinymath.pkg \
|
o/$(MODE)/test/libc/tinymath/tinymath.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
$(TEST_LIBC_TINYMATH_OBJS): \
|
$(TEST_LIBC_TINYMATH_OBJS): \
|
||||||
|
|
|
@ -47,7 +47,7 @@ o/$(MODE)/test/libc/unicode/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/unicode/unicode.pkg \
|
o/$(MODE)/test/libc/unicode/unicode.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/libc/unicode
|
.PHONY: o/$(MODE)/test/libc/unicode
|
||||||
|
|
|
@ -53,7 +53,7 @@ o/$(MODE)/test/libc/x/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/x/x.pkg \
|
o/$(MODE)/test/libc/x/x.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/libc/x
|
.PHONY: o/$(MODE)/test/libc/x
|
||||||
|
|
27
test/libc/x/xfixpath_test.c
Normal file
27
test/libc/x/xfixpath_test.c
Normal file
|
@ -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"));
|
||||||
|
}
|
|
@ -93,7 +93,7 @@ o/$(MODE)/test/libc/xed/%.com.dbg: \
|
||||||
o/$(MODE)/test/libc/xed/xed.pkg \
|
o/$(MODE)/test/libc/xed/xed.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
#───────────────────────────────────────────────────────────────────────────────
|
#───────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
|
@ -37,7 +37,7 @@ o/$(MODE)/test/net/http/%.com.dbg: \
|
||||||
o/$(MODE)/test/net/http/%.o \
|
o/$(MODE)/test/net/http/%.o \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/net/http
|
.PHONY: o/$(MODE)/test/net/http
|
||||||
|
|
|
@ -38,7 +38,7 @@ o/$(MODE)/test/net/https/%.com.dbg: \
|
||||||
o/$(MODE)/test/net/https/%.o \
|
o/$(MODE)/test/net/https/%.o \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/net/https
|
.PHONY: o/$(MODE)/test/net/https
|
||||||
|
|
|
@ -66,7 +66,7 @@ o/$(MODE)/test/tool/args/%.com.dbg: \
|
||||||
$(TEST_TOOL_ARGS_A).pkg \
|
$(TEST_TOOL_ARGS_A).pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/tool/args
|
.PHONY: o/$(MODE)/test/tool/args
|
||||||
|
|
|
@ -66,7 +66,7 @@ o/$(MODE)/test/tool/build/lib/%.com.dbg: \
|
||||||
$(TEST_TOOL_BUILD_LIB_A).pkg \
|
$(TEST_TOOL_BUILD_LIB_A).pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/tool/build/lib
|
.PHONY: o/$(MODE)/test/tool/build/lib
|
||||||
|
|
|
@ -68,7 +68,7 @@ o/$(MODE)/test/tool/net/%.com.dbg: \
|
||||||
$(TEST_TOOL_NET_A).pkg \
|
$(TEST_TOOL_NET_A).pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/tool/net
|
.PHONY: o/$(MODE)/test/tool/net
|
||||||
|
|
|
@ -74,7 +74,7 @@ o/$(MODE)/test/tool/plinko/%.com.dbg: \
|
||||||
$(TEST_TOOL_PLINKO_A).pkg \
|
$(TEST_TOOL_PLINKO_A).pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/test/tool/plinko/plinko_test.com.runs: \
|
o/$(MODE)/test/tool/plinko/plinko_test.com.runs: \
|
||||||
|
|
|
@ -55,7 +55,7 @@ o/$(MODE)/test/tool/viz/lib/%.com.dbg: \
|
||||||
o/$(MODE)/test/tool/viz/lib/vizlib.pkg \
|
o/$(MODE)/test/tool/viz/lib/vizlib.pkg \
|
||||||
$(LIBC_TESTMAIN) \
|
$(LIBC_TESTMAIN) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PHONY: o/$(MODE)/test/tool/viz/lib
|
.PHONY: o/$(MODE)/test/tool/viz/lib
|
||||||
|
|
5
third_party/chibicc/chibicc.c
vendored
5
third_party/chibicc/chibicc.c
vendored
|
@ -80,7 +80,7 @@ static void chibicc_usage(int status) {
|
||||||
char *p;
|
char *p;
|
||||||
size_t n;
|
size_t n;
|
||||||
p = xslurp("/zip/third_party/chibicc/help.txt", &n);
|
p = xslurp("/zip/third_party/chibicc/help.txt", &n);
|
||||||
xwrite(1, p, n);
|
__paginate(1, p);
|
||||||
_Exit(status);
|
_Exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +447,8 @@ static bool run_subprocess(char **argv) {
|
||||||
_Exit(1);
|
_Exit(1);
|
||||||
}
|
}
|
||||||
// Wait for the child process to finish.
|
// Wait for the child process to finish.
|
||||||
do rc = wait(&ws);
|
do
|
||||||
|
rc = wait(&ws);
|
||||||
while (rc == -1 && errno == EINTR);
|
while (rc == -1 && errno == EINTR);
|
||||||
return WIFEXITED(ws) && WEXITSTATUS(ws) == 0;
|
return WIFEXITED(ws) && WEXITSTATUS(ws) == 0;
|
||||||
}
|
}
|
||||||
|
|
6
third_party/chibicc/chibicc.mk
vendored
6
third_party/chibicc/chibicc.mk
vendored
|
@ -93,7 +93,7 @@ $(THIRD_PARTY_CHIBICC2_A).pkg: \
|
||||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \
|
o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \
|
||||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||||
$(THIRD_PARTY_CHIBICC_A) \
|
$(THIRD_PARTY_CHIBICC_A) \
|
||||||
$(APE) \
|
$(APE_NO_MODIFY_SELF) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
o/$(MODE)/third_party/chibicc/help.txt.zip.o \
|
o/$(MODE)/third_party/chibicc/help.txt.zip.o \
|
||||||
o/$(MODE)/third_party/chibicc/chibicc.main.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: \
|
o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \
|
||||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||||
$(THIRD_PARTY_CHIBICC2_A) \
|
$(THIRD_PARTY_CHIBICC2_A) \
|
||||||
$(APE) \
|
$(APE_NO_MODIFY_SELF) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
o/$(MODE)/third_party/chibicc/help.txt.zip.o \
|
o/$(MODE)/third_party/chibicc/help.txt.zip.o \
|
||||||
o/$(MODE)/third_party/chibicc/chibicc.main.chibicc.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: \
|
o/$(MODE)/third_party/chibicc/as.com.dbg: \
|
||||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||||
$(THIRD_PARTY_CHIBICC_A) \
|
$(THIRD_PARTY_CHIBICC_A) \
|
||||||
$(APE) \
|
$(APE_NO_MODIFY_SELF) \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
o/$(MODE)/third_party/chibicc/as.main.o \
|
o/$(MODE)/third_party/chibicc/as.main.o \
|
||||||
$(THIRD_PARTY_CHIBICC_A).pkg
|
$(THIRD_PARTY_CHIBICC_A).pkg
|
||||||
|
|
9
third_party/chibicc/help.txt
vendored
9
third_party/chibicc/help.txt
vendored
|
@ -259,6 +259,15 @@ BUILTIN FUNCTIONS
|
||||||
double __builtin_copysign(double, double)
|
double __builtin_copysign(double, double)
|
||||||
float __builtin_copysignf(float, float)
|
float __builtin_copysignf(float, float)
|
||||||
long double __builtin_copysignl(long double, long double)
|
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
|
BUILTIN OBJECTS
|
||||||
|
|
4
third_party/chibicc/test/test.mk
vendored
4
third_party/chibicc/test/test.mk
vendored
|
@ -79,7 +79,7 @@ o/$(MODE)/third_party/chibicc/test/%.com.dbg: \
|
||||||
o/$(MODE)/third_party/chibicc/test/%.chibicc.o \
|
o/$(MODE)/third_party/chibicc/test/%.chibicc.o \
|
||||||
$(THIRD_PARTY_CHIBICC_TEST_A).pkg \
|
$(THIRD_PARTY_CHIBICC_TEST_A).pkg \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \
|
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 \
|
o/$(MODE)/third_party/chibicc/test/%.chibicc2.o \
|
||||||
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg \
|
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg \
|
||||||
$(CRT) \
|
$(CRT) \
|
||||||
$(APE)
|
$(APE_NO_MODIFY_SELF)
|
||||||
@$(APELINK)
|
@$(APELINK)
|
||||||
|
|
||||||
.PRECIOUS: $(THIRD_PARTY_CHIBICC_TEST_OBJS)
|
.PRECIOUS: $(THIRD_PARTY_CHIBICC_TEST_OBJS)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue