mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +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
|
||||
/bx_enh_dbg.ini
|
||||
/tool/emacs/*.elc
|
||||
/usr/share/dict/words
|
||||
|
|
18
Makefile
18
Makefile
|
@ -59,9 +59,9 @@
|
|||
#
|
||||
# build/config.mk
|
||||
|
||||
SHELL = /bin/sh
|
||||
SHELL = build/bootstrap/cocmd.com
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win7 win10 xnu
|
||||
SANITY := $(shell build/sanitycheck $$PPID)
|
||||
#SANITY := $(shell build/sanitycheck $$PPID)
|
||||
|
||||
.SUFFIXES:
|
||||
.DELETE_ON_ERROR:
|
||||
|
@ -229,7 +229,7 @@ depend: o/$(MODE)/depend
|
|||
tags: TAGS HTAGS
|
||||
|
||||
o/$(MODE)/.x:
|
||||
@mkdir -p $(@D) && touch $@
|
||||
@$(COMPILE) -AMKDIR -tT$@ $(MKDIR) $(@D)
|
||||
|
||||
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||
$(file >$@,$(SRCS))
|
||||
|
@ -246,11 +246,11 @@ o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS
|
|||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||
|
||||
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
|
||||
@rm -f $@
|
||||
@$(RM) $@
|
||||
@$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@
|
||||
|
||||
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
|
||||
@rm -f $@
|
||||
@$(RM) $@
|
||||
@$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@
|
||||
|
||||
loc: o/$(MODE)/tool/build/summy.com
|
||||
|
@ -390,9 +390,9 @@ $(SRCS):
|
|||
$(HDRS):
|
||||
$(INCS):
|
||||
.DEFAULT:
|
||||
@echo >&2
|
||||
@echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2
|
||||
@echo >&2
|
||||
rm -f o/$(MODE)/depend
|
||||
@$(ECHO) >&2
|
||||
@$(ECHO) NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2
|
||||
@$(ECHO) >&2
|
||||
$(RM) o/$(MODE)/depend
|
||||
|
||||
-include o/$(MODE)/depend
|
||||
|
|
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):
|
||||
|
||||
```sh
|
||||
$ file hello.com
|
||||
hello.com: DOS/MBR boot sector
|
||||
./hello.com --assimilate
|
||||
$ file hello.com
|
||||
hello.com: ELF 64-bit LSB executable
|
||||
```
|
||||
|
||||
There's also some other useful flags that get baked into your binary by
|
||||
default:
|
||||
|
||||
```sh
|
||||
./hello.com --strace
|
||||
./hello.com --ftrace
|
||||
./hello.com --strace # log system calls to stderr
|
||||
./hello.com --ftrace # log function calls to stderr
|
||||
```
|
||||
|
||||
If you want your `hello.com` program to be much tinier, more on the
|
||||
|
@ -100,22 +104,85 @@ Windows](https://justine.lol/cosmopolitan/windows-compiling.html)
|
|||
tutorial. It's needed because the ELF object format is what makes
|
||||
universal binaries possible.
|
||||
|
||||
Cosmopolitan officially only builds on Linux. However, one highly
|
||||
experimental (and currently broken) thing you could try, is building the
|
||||
entire cosmo repository from source using the cross9 toolchain.
|
||||
|
||||
```
|
||||
mkdir -p o/third_party
|
||||
rm -rf o/third_party/gcc
|
||||
wget https://justine.lol/linux-compiler-on-windows/cross9.zip
|
||||
unzip cross9.zip
|
||||
mv cross9 o/third_party/gcc
|
||||
build/bootstrap/make.com
|
||||
```
|
||||
|
||||
## Source Builds
|
||||
|
||||
Cosmopolitan can be compiled from source on any Linux distro. GNU make
|
||||
needs to be installed beforehand. This is a freestanding hermetic
|
||||
repository that bootstraps using a vendored static gcc9 executable.
|
||||
No further dependencies are required.
|
||||
Cosmopolitan can be compiled from source on any Linux distro. First, you
|
||||
need to download or clone the repository.
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz
|
||||
tar xf cosmopolitan.tar.gz # see releases page
|
||||
cd cosmopolitan
|
||||
make -j16
|
||||
```
|
||||
|
||||
This will build the entire repository and run all the tests:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16
|
||||
o//examples/hello.com
|
||||
find o -name \*.com | xargs ls -rShal | less
|
||||
```
|
||||
|
||||
If you get an error running make.com then it's probably because you have
|
||||
WINE installed to `binfmt_misc`. You can fix that by installing the the
|
||||
APE loader as an interpreter. It'll improve build performance too!
|
||||
|
||||
```sh
|
||||
ape/apeinstall.sh
|
||||
```
|
||||
|
||||
Since the Cosmopolitan repository is very large, you might only want to
|
||||
build a particular thing. Cosmopolitan's build config does a good job at
|
||||
having minimal deterministic builds. For example, if you wanted to build
|
||||
only hello.com then you could do that as follows:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 o//examples/hello.com
|
||||
```
|
||||
|
||||
Sometimes it's desirable to build a subset of targets, without having to
|
||||
list out each individual one. You can do that by asking make to build a
|
||||
directory name. For example, if you wanted to build only the targets and
|
||||
subtargets of the chibicc package including its tests, you would say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 o//third_party/chibicc
|
||||
o//third_party/chibicc/chibicc.com --help
|
||||
```
|
||||
|
||||
Cosmopolitan provides a variety of build modes. For example, if you want
|
||||
really tiny binaries (as small as 12kb in size) then you'd say:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 MODE=tiny
|
||||
```
|
||||
|
||||
Here's some other build modes you can try:
|
||||
|
||||
```sh
|
||||
build/bootstrap/make.com -j16 MODE=dbg # asan + ubsan + debug
|
||||
build/bootstrap/make.com -j16 MODE=asan # production memory safety
|
||||
build/bootstrap/make.com -j16 MODE=opt # -march=native optimizations
|
||||
build/bootstrap/make.com -j16 MODE=rel # traditional release binaries
|
||||
build/bootstrap/make.com -j16 MODE=optlinux # optimal linux-only performance
|
||||
build/bootstrap/make.com -j16 MODE=tinylinux # tiniest linux-only 4kb binaries
|
||||
```
|
||||
|
||||
For further details, see [//build/config.mk](build/config.mk).
|
||||
|
||||
## GDB
|
||||
|
||||
Here's the recommended `~/.gdbinit` config:
|
||||
|
@ -159,4 +226,3 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
|||
| FreeBSD | 12 | 2018 |
|
||||
| OpenBSD | 6.4 | 2018 |
|
||||
| NetBSD | 9.1 | 2020 |
|
||||
| GNU Make | 4.0 | 2015 |
|
||||
|
|
109
ape/ape.mk
109
ape/ape.mk
|
@ -15,38 +15,38 @@
|
|||
|
||||
PKGS += APE
|
||||
|
||||
APE = o/$(MODE)/ape/ape.o \
|
||||
APE = o/$(MODE)/ape/ape.o \
|
||||
o/$(MODE)/ape/ape.lds
|
||||
|
||||
APE_NO_MODIFY_SELF = \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
APE_NO_MODIFY_SELF = \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o
|
||||
|
||||
APE_COPY_SELF = \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
APE_COPY_SELF = \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/ape/ape-copy-self.o
|
||||
|
||||
APELINK = \
|
||||
$(COMPILE) \
|
||||
-ALINK.ape \
|
||||
$(LINK) \
|
||||
$(LINKARGS) \
|
||||
APELINK = \
|
||||
$(COMPILE) \
|
||||
-ALINK.ape \
|
||||
$(LINK) \
|
||||
$(LINKARGS) \
|
||||
$(OUTPUT_OPTION)
|
||||
|
||||
APE_LOADER_FLAGS = \
|
||||
-DNDEBUG \
|
||||
-iquote. \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-fpie \
|
||||
-Os \
|
||||
-ffreestanding \
|
||||
-mgeneral-regs-only \
|
||||
-mno-red-zone \
|
||||
-fno-ident \
|
||||
-fno-gnu-unique \
|
||||
-c \
|
||||
$(OUTPUT_OPTION) \
|
||||
APE_LOADER_FLAGS = \
|
||||
-DNDEBUG \
|
||||
-iquote. \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-fpie \
|
||||
-Os \
|
||||
-ffreestanding \
|
||||
-mgeneral-regs-only \
|
||||
-mno-red-zone \
|
||||
-fno-ident \
|
||||
-fno-gnu-unique \
|
||||
-c \
|
||||
$(OUTPUT_OPTION) \
|
||||
$<
|
||||
|
||||
APE_FILES := $(wildcard ape/*.*)
|
||||
|
@ -58,32 +58,32 @@ APE_SRCS = $(APE_SRCS_C) $(APE_SRCS_S)
|
|||
APE_OBJS = $(APE_SRCS_S:%.S=o/$(MODE)/%.o)
|
||||
APE_CHECKS = $(APE_HDRS:%=o/%.ok)
|
||||
|
||||
o/$(MODE)/ape/ape.lds: \
|
||||
ape/ape.lds \
|
||||
ape/macros.internal.h \
|
||||
libc/dce.h \
|
||||
o/$(MODE)/ape/ape.lds: \
|
||||
ape/ape.lds \
|
||||
ape/macros.internal.h \
|
||||
libc/dce.h \
|
||||
libc/zip.h
|
||||
|
||||
o/ape/idata.inc: \
|
||||
ape/idata.internal.h \
|
||||
o/ape/idata.inc: \
|
||||
ape/idata.internal.h \
|
||||
ape/relocations.h
|
||||
|
||||
o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
ape/ape.S \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o: \
|
||||
ape/ape.S \
|
||||
o/$(MODE)/ape/ape.elf
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
$(OBJECTIFY.S) \
|
||||
$(OUTPUT_OPTION) \
|
||||
-DAPE_NO_MODIFY_SELF \
|
||||
-DAPE_LOADER="\"o/$(MODE)/ape/ape.elf\"" $<
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
$(OBJECTIFY.S) \
|
||||
$(OUTPUT_OPTION) \
|
||||
-DAPE_NO_MODIFY_SELF \
|
||||
-DAPE_LOADER='"o/$(MODE)/ape/ape.elf"' $<
|
||||
|
||||
o/$(MODE)/ape/ape-copy-self.o: \
|
||||
o/$(MODE)/ape/ape-copy-self.o: \
|
||||
ape/ape.S
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
$(OBJECTIFY.S) \
|
||||
$(OUTPUT_OPTION) \
|
||||
@$(COMPILE) \
|
||||
-AOBJECTIFY.S \
|
||||
$(OBJECTIFY.S) \
|
||||
$(OUTPUT_OPTION) \
|
||||
-DAPE_NO_MODIFY_SELF $<
|
||||
|
||||
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.macho: o/$(MODE)/ape/ape.macho.dbg
|
||||
|
||||
o/$(MODE)/ape/ape.elf.dbg: \
|
||||
o/$(MODE)/ape/loader.o \
|
||||
o/$(MODE)/ape/loader-elf.o \
|
||||
o/$(MODE)/ape/ape.elf.dbg: \
|
||||
o/$(MODE)/ape/loader.o \
|
||||
o/$(MODE)/ape/loader-elf.o \
|
||||
ape/loader.lds
|
||||
@$(ELFLINK) -z max-page-size=0x10
|
||||
|
||||
o/$(MODE)/ape/ape.macho.dbg: \
|
||||
o/$(MODE)/ape/loader-xnu.o \
|
||||
o/$(MODE)/ape/loader-macho.o \
|
||||
o/$(MODE)/ape/ape.macho.dbg: \
|
||||
o/$(MODE)/ape/loader-xnu.o \
|
||||
o/$(MODE)/ape/loader-macho.o \
|
||||
ape/loader-macho.lds
|
||||
@$(ELFLINK) -z max-page-size=0x10
|
||||
|
||||
.PHONY: o/$(MODE)/ape
|
||||
o/$(MODE)/ape: $(APE) \
|
||||
$(APE_CHECKS) \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
o/$(MODE)/ape/ape.macho \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
o/$(MODE)/ape: $(APE_CHECKS) \
|
||||
o/$(MODE)/ape/ape.o \
|
||||
o/$(MODE)/ape/ape.lds \
|
||||
o/$(MODE)/ape/ape.elf \
|
||||
o/$(MODE)/ape/ape.macho \
|
||||
o/$(MODE)/ape/ape-copy-self.o \
|
||||
o/$(MODE)/ape/ape-no-modify-self.o
|
||||
|
|
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 ?=
|
||||
XARGS ?= xargs -P4 -rs8000
|
||||
DOT ?= dot
|
||||
GZ ?= gzip
|
||||
CLANG = clang
|
||||
FC = gfortran #/opt/cross9f/bin/x86_64-linux-musl-gfortran
|
||||
TMPDIR = o/tmp
|
||||
|
||||
# see build/compile, etc. which run third_party/gcc/unbundle.sh
|
||||
AR = build/bootstrap/ar.com
|
||||
CP = build/bootstrap/cp.com
|
||||
RM = build/bootstrap/rm.com -f
|
||||
ECHO = build/bootstrap/echo.com
|
||||
TOUCH = build/bootstrap/touch.com
|
||||
PKG = build/bootstrap/package.com
|
||||
MKDEPS = build/bootstrap/mkdeps.com
|
||||
ZIPOBJ = build/bootstrap/zipobj.com
|
||||
MKDIR = build/bootstrap/mkdir.com -p
|
||||
COMPILE = build/bootstrap/compile.com -V9 $(QUOTA)
|
||||
|
||||
COMMA := ,
|
||||
PWD := $(shell build/bootstrap/pwd.com)
|
||||
IMAGE_BASE_VIRTUAL ?= 0x400000
|
||||
|
||||
IGNORE := $(shell $(ECHO) -2 ♥cosmo)
|
||||
IGNORE := $(shell $(MKDIR) o/tmp)
|
||||
|
||||
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe)","")
|
||||
AS = o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe
|
||||
CC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
|
||||
CXX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-g++.exe
|
||||
CXXFILT = o/third_party/gcc/bin/x86_64-pc-linux-gnu-c++filt.exe
|
||||
LD = o/third_party/gcc/bin/x86_64-pc-linux-gnu-ld.bfd.exe
|
||||
NM = o/third_party/gcc/bin/x86_64-pc-linux-gnu-nm.exe
|
||||
GCC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
|
||||
STRIP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-strip.exe
|
||||
OBJCOPY = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objcopy.exe
|
||||
OBJDUMP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objdump.exe
|
||||
ADDR2LINE = $(shell build/bootstrap/pwd.com)/o/third_party/gcc/bin/x86_64-pc-linux-gnu-addr2line.exe
|
||||
else
|
||||
IGNORE := $(shell build/bootstrap/unbundle.com)
|
||||
AS = o/third_party/gcc/bin/x86_64-linux-musl-as
|
||||
CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
|
||||
|
@ -69,18 +96,12 @@ GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
|||
STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip
|
||||
OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy
|
||||
OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump
|
||||
ADDR2LINE = $(shell pwd)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
|
||||
|
||||
COMMA := ,
|
||||
PWD := $(shell pwd)
|
||||
IMAGE_BASE_VIRTUAL ?= 0x400000
|
||||
HELLO := $(shell build/hello)
|
||||
TMPDIR := $(shell build/findtmp)
|
||||
SPAWNER := $(shell build/getcompile) -V$(shell build/getccversion $(CC))
|
||||
COMPILE = $(SPAWNER) $(HARNESSFLAGS) $(QUOTA)
|
||||
ADDR2LINE = $(shell build/bootstrap/pwd.com)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
|
||||
endif
|
||||
|
||||
export ADDR2LINE
|
||||
export LC_ALL
|
||||
export MKDIR
|
||||
export MODE
|
||||
export SOURCE_DATE_EPOCH
|
||||
export TMPDIR
|
||||
|
@ -115,7 +136,7 @@ TRADITIONAL = \
|
|||
DEFAULT_CCFLAGS = \
|
||||
-Wall \
|
||||
-Werror \
|
||||
-fdebug-prefix-map="$(PWD)"= \
|
||||
-fdebug-prefix-map='$(PWD)'= \
|
||||
-frecord-gcc-switches
|
||||
|
||||
DEFAULT_OFLAGS = \
|
||||
|
@ -180,7 +201,7 @@ PYFLAGS = \
|
|||
ASONLYFLAGS = \
|
||||
-c \
|
||||
-g \
|
||||
--debug-prefix-map="$(PWD)"=
|
||||
--debug-prefix-map='$(PWD)'=
|
||||
|
||||
DEFAULT_LDLIBS =
|
||||
|
||||
|
|
|
@ -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/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
|
||||
o/%.inc: %.h ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) -D__ASSEMBLER__ -P $<
|
||||
o/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
|
||||
o/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
|
||||
o/%.okk: % ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
||||
|
@ -75,7 +74,6 @@ o/$(MODE)/%.ncabi.o: %.ncabi.c ; @$(COMPILE) -AOBJECTIFY.nc $(OBJECTIFY.ncab
|
|||
o/$(MODE)/%.real.o: %.c ; @$(COMPILE) -AOBJECTIFY.real $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/%.runs: o/$(MODE)/% ; @$(COMPILE) -ACHECK -tT$@ $< $(TESTARGS)
|
||||
o/$(MODE)/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
|
||||
o/$(MODE)/%.zip.o: % ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-gcc.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
|
||||
|
@ -87,6 +85,14 @@ o/%.a:
|
|||
$(file >$@.args,$^)
|
||||
@$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ @$@.args
|
||||
|
||||
o/%.pkg:
|
||||
$(file >$@.args,$(filter %.o,$^))
|
||||
@$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$@.args
|
||||
|
||||
o/$(MODE)/%.pkg:
|
||||
$(file >$@.args,$(filter %.o,$^))
|
||||
@$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$@.args
|
||||
|
||||
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
|
||||
@$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
|
||||
|
||||
|
|
|
@ -32,11 +32,11 @@
|
|||
#include "third_party/linenoise/linenoise.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Shell that works on Windows.
|
||||
* @fileoverview Cosmopolitan Shell
|
||||
*
|
||||
* This doesn't have script language features like UNBOURNE.COM but it
|
||||
* works on Windows and, unlike CMD.EXE, actually has CTRL-P and CTRL-R
|
||||
* which alone make it so much better.
|
||||
* works on Windows and, unlike CMD.EXE, has CTRL-P, CTRL-R, and other
|
||||
* GNU Emacs / Readline keyboard shortcuts.
|
||||
*
|
||||
* One day we'll have UNBOURNE.COM working on Windows but the code isn't
|
||||
* very maintainable sadly.
|
||||
|
@ -184,8 +184,8 @@ int main(int argc, char *argv[]) {
|
|||
args = xrealloc(args, (++n + 1) * sizeof(*args));
|
||||
args[n - 1] = arg;
|
||||
args[n - 0] = 0;
|
||||
start = 0;
|
||||
}
|
||||
start = 0;
|
||||
}
|
||||
if (n > 0) {
|
||||
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
|
||||
|
||||
ifeq ($(MODE),tiny)
|
||||
EXAMPLES_BOOTLOADER = $(CRT) $(APE)
|
||||
else
|
||||
EXAMPLES_BOOTLOADER = $(CRT) $(APE_NO_MODIFY_SELF)
|
||||
endif
|
||||
|
||||
EXAMPLES_FILES := $(wildcard examples/*)
|
||||
EXAMPLES_MAINS_S = $(filter %.S,$(EXAMPLES_FILES))
|
||||
EXAMPLES_MAINS_C = $(filter %.c,$(EXAMPLES_FILES))
|
||||
|
@ -100,8 +106,7 @@ o/$(MODE)/examples/%.com.dbg: \
|
|||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/nomodifyself.com.dbg: \
|
||||
|
@ -112,21 +117,12 @@ o/$(MODE)/examples/nomodifyself.com.dbg: \
|
|||
$(APE_NO_MODIFY_SELF)
|
||||
@$(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: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/hellolua.o \
|
||||
o/$(MODE)/examples/hellolua.lua.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/ispell.com.dbg: \
|
||||
|
@ -134,8 +130,7 @@ o/$(MODE)/examples/ispell.com.dbg: \
|
|||
o/$(MODE)/examples/ispell.o \
|
||||
o/$(MODE)/usr/share/dict/words.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
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/tetris.nes.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(EXAMPLES_BOOTLOADER)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/nesemu1.com: \
|
||||
|
@ -160,12 +154,15 @@ o/$(MODE)/examples/nesemu1.com: \
|
|||
o/$(MODE)/examples/.nesemu1/.symtab
|
||||
|
||||
o/$(MODE)/examples/nesemu1.o: QUOTA += -M512m
|
||||
o/$(MODE)/usr/share/dict/words.zip.o: ZIPOBJ_FLAGS += -C2
|
||||
|
||||
$(EXAMPLES_OBJS): examples/examples.mk
|
||||
|
||||
usr/share/dict/words: usr/share/dict/words.gz
|
||||
@mkdir -p $(@D)
|
||||
@$(GZ) $(ZFLAGS) -d <$< >$@
|
||||
o/$(MODE)/usr/share/dict/words: \
|
||||
usr/share/dict/words.gz \
|
||||
o/$(MODE)/tool/build/gzip.com
|
||||
@$(MKDIR) $(@D)
|
||||
@o/$(MODE)/tool/build/gzip.com $(ZFLAGS) -cd <$< >$@
|
||||
|
||||
.PHONY: o/$(MODE)/examples
|
||||
o/$(MODE)/examples: \
|
||||
|
|
|
@ -60,7 +60,7 @@ o/$(MODE)/examples/package/%.com.dbg: \
|
|||
$(EXAMPLES_PACKAGE_DEPS) \
|
||||
o/$(MODE)/examples/package/%.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
# Invalidates objects in package when makefile is edited.
|
||||
|
|
|
@ -95,7 +95,7 @@ o/$(MODE)/examples/pyapp/pyapp.com.dbg: \
|
|||
o/$(MODE)/examples/pyapp/pyapp.pkg \
|
||||
o/$(MODE)/examples/pyapp/pyapp.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
$(LINK) $(LINKARGS) -o $@
|
||||
|
||||
# # Unwrap the APE .COM binary, that's embedded within the linked file
|
||||
|
|
|
@ -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/execlp.o \
|
||||
o/$(MODE)/libc/calls/execve-sysv.o \
|
||||
o/$(MODE)/libc/calls/execve-nt.greg.o \
|
||||
o/$(MODE)/libc/calls/mkntenvblock.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
|
|
@ -76,7 +76,7 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
|
|||
/**
|
||||
* 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;
|
||||
clock_gettime_f *res;
|
||||
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) {
|
||||
clock_gettime_f *gettime;
|
||||
__clock_gettime = gettime = __get_clock_gettime(0);
|
||||
__clock_gettime = gettime = __clock_gettime_get(0);
|
||||
return gettime(clockid, ts);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ typedef int clock_gettime_f(int, struct timespec *);
|
|||
|
||||
extern clock_gettime_f *__clock_gettime;
|
||||
hidden clock_gettime_f __clock_gettime_init;
|
||||
hidden clock_gettime_f *__get_clock_gettime(bool *);
|
||||
hidden clock_gettime_f *__clock_gettime_get(bool *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/calls/ntspawn.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/console.h"
|
||||
|
@ -59,13 +60,28 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
|||
int rc;
|
||||
size_t i;
|
||||
uint32_t dwExitCode;
|
||||
char progbuf[PATH_MAX];
|
||||
struct MemoryIntervals *mm;
|
||||
struct NtStartupInfo startinfo;
|
||||
struct NtProcessInformation procinfo;
|
||||
|
||||
if (strlen(program) + 4 + 1 > PATH_MAX) {
|
||||
return enametoolong();
|
||||
}
|
||||
|
||||
// this is a non-recoverable operation, so do some manual validation
|
||||
if (sys_faccessat_nt(AT_FDCWD, program, X_OK, 0) == -1) {
|
||||
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 │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/paths.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static bool CanExecute(const char *path) {
|
||||
return !sys_faccessat(AT_FDCWD, path, X_OK, 0);
|
||||
}
|
||||
|
||||
static bool IsApeBinary(const char *path) {
|
||||
int fd;
|
||||
char buf[8];
|
||||
bool res = false;
|
||||
if ((fd = sys_open(path, O_RDONLY, 0)) != -1) {
|
||||
if (sys_read(fd, buf, 8) == 8 && READ64LE(buf) == READ64LE("MZqFpD='")) {
|
||||
res = true;
|
||||
}
|
||||
sys_close(fd);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char *Join(const char *a, const char *b, char buf[PATH_MAX]) {
|
||||
size_t n, m;
|
||||
n = strlen(a);
|
||||
m = strlen(b);
|
||||
if (n + 1 + m + 1 < PATH_MAX) {
|
||||
stpcpy(stpcpy(stpcpy(buf, a), "/"), b);
|
||||
return buf;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
||||
int e;
|
||||
size_t i;
|
||||
char *buf;
|
||||
char **shargs;
|
||||
const char *ape;
|
||||
e = errno;
|
||||
__sys_execve(prog, argv, envp);
|
||||
if (errno != ENOEXEC) return -1;
|
||||
for (i = 0; argv[i];) ++i;
|
||||
shargs = alloca((i + 2) * sizeof(char *));
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
if (IsFreebsd() || IsNetbsd()) {
|
||||
shargs[0] = firstnonnull(commandv("bash", alloca(PATH_MAX), PATH_MAX),
|
||||
_PATH_BSHELL);
|
||||
buf = alloca(PATH_MAX);
|
||||
shargs = alloca((i + 4) * sizeof(char *));
|
||||
if (IsApeBinary(prog) &&
|
||||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute(
|
||||
(ape = Join(firstnonnull(getenv("TMPDIR"), "/tmp"), "ape", buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
shargs[2] = prog;
|
||||
memcpy(shargs + 3, argv, (i + 1) * sizeof(char *));
|
||||
} else if (CanExecute(prog)) {
|
||||
if (IsFreebsd() || IsNetbsd()) {
|
||||
shargs[0] = firstnonnull(commandv("bash", buf, PATH_MAX), _PATH_BSHELL);
|
||||
} else {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
}
|
||||
shargs[1] = prog;
|
||||
memcpy(shargs + 2, argv + 1, i * sizeof(char *));
|
||||
} else {
|
||||
shargs[0] = _PATH_BSHELL;
|
||||
return enoexec();
|
||||
}
|
||||
shargs[1] = prog;
|
||||
errno = e;
|
||||
return __sys_execve(shargs[0], shargs, envp);
|
||||
}
|
||||
|
|
|
@ -32,14 +32,21 @@ textwindows char *sys_getcwd_nt(char *buf, size_t size) {
|
|||
if ((n = GetCurrentDirectory(ARRAYLEN(p), p))) {
|
||||
if (4 + n + 1 <= size && 4 + n + 1 <= ARRAYLEN(p)) {
|
||||
tprecode16to8(buf, size, p);
|
||||
i = 0;
|
||||
j = 0;
|
||||
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
|
||||
// turn c:\... into \c\...
|
||||
p[1] = p[0];
|
||||
p[0] = '\\';
|
||||
} else if (n >= 7 && p[0] == '\\' && p[1] == '\\' && p[2] == '?' &&
|
||||
p[3] == '\\' && isalpha(p[4]) && p[5] == ':' && p[6] == '\\') {
|
||||
// turn \\?\c:\... into \c\...
|
||||
buf[j++] = '/';
|
||||
buf[j++] = p[4];
|
||||
buf[j++] = '/';
|
||||
buf[j++] = '?';
|
||||
buf[j++] = '/';
|
||||
i += 7;
|
||||
}
|
||||
for (i = 0; i < n;) {
|
||||
while (i < n) {
|
||||
x = p[i++] & 0xffff;
|
||||
if (!IsUcs2(x)) {
|
||||
if (i < n) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
// Obtains WIN32 magic path, e.g. GetTempPathA.
|
||||
|
@ -33,7 +34,13 @@ __getntsyspath:
|
|||
movpp %rdi,%rcx # call f=%rax(p1=%rcx,p2=%rdx)
|
||||
sub $40,%rsp
|
||||
call *%rax
|
||||
xor %edx,%edx
|
||||
testb IsWindows()
|
||||
jz 3f
|
||||
mov (%rdi),%cl # turn c:\... into \c\...
|
||||
movb $'\\',(%rdi)
|
||||
mov %cl,1(%rdi)
|
||||
movb $'\\',2(%rdi)
|
||||
3: xor %edx,%edx
|
||||
mov -8(%rbp),%ecx # restore %edx param as %ecx
|
||||
cmp %eax,%ecx # use current dir on overflow
|
||||
cmovbe %edx,%eax
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
|
||||
char program_executable_name[PATH_MAX];
|
||||
|
||||
static inline int IsAlpha(int c) {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
|
||||
static inline char *StrCat(char buf[PATH_MAX], const char *a, const char *b) {
|
||||
char *p, *e;
|
||||
p = buf;
|
||||
|
@ -56,16 +60,16 @@ static inline void GetProgramExecutableNameImpl(char *p, char *e) {
|
|||
if (IsWindows()) {
|
||||
n = GetModuleFileName(0, u.path16, ARRAYLEN(u.path16));
|
||||
for (i = 0; i < n; ++i) {
|
||||
// turn c:\foo\bar into c:/foo/bar
|
||||
if (u.path16[i] == '\\') {
|
||||
u.path16[i] = '/';
|
||||
}
|
||||
}
|
||||
if (isalpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') {
|
||||
p[0] = '/';
|
||||
p[1] = '/';
|
||||
p[2] = '?';
|
||||
p[3] = '/';
|
||||
p += 4;
|
||||
if (IsAlpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') {
|
||||
// turn c:/... into /c/...
|
||||
u.path16[1] = u.path16[0];
|
||||
u.path16[0] = '/';
|
||||
u.path16[2] = '/';
|
||||
}
|
||||
tprecode16to8(p, e - p, u.path16);
|
||||
return;
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist2.internal.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/ntspawn.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -31,15 +33,85 @@
|
|||
|
||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
static int CompareStrings(const char *l, const char *r) {
|
||||
static inline int IsAlpha(int c) {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
|
||||
static inline char *StrChr(char *s, int c) {
|
||||
for (;; ++s) {
|
||||
if ((*s & 255) == (c & 255)) return s;
|
||||
if (!*s) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows inline int CompareStrings(const char *l, const char *r) {
|
||||
int a, b;
|
||||
size_t i = 0;
|
||||
while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static void InsertString(char **a, size_t i, char *s) {
|
||||
size_t j;
|
||||
static textwindows void FixPath(char *path) {
|
||||
char *p;
|
||||
size_t i;
|
||||
|
||||
// skip over variable name
|
||||
while (*path++) {
|
||||
if (path[-1] == '=') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// turn colon into semicolon
|
||||
// unless it already looks like a dos path
|
||||
for (p = path; *p; ++p) {
|
||||
if (p[0] == ':' && p[1] != '\\') {
|
||||
p[0] = ';';
|
||||
}
|
||||
}
|
||||
|
||||
// turn \c\... into c:\...
|
||||
p = path;
|
||||
if (p[0] == '/' && IsAlpha(p[1]) && p[2] == '/') {
|
||||
p[0] = p[1];
|
||||
p[1] = ':';
|
||||
}
|
||||
for (; *p; ++p) {
|
||||
if (p[0] == ';' && p[1] == '/' && IsAlpha(p[2]) && p[3] == '/') {
|
||||
p[1] = p[2];
|
||||
p[2] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
// turn slash into backslash
|
||||
for (p = path; *p; ++p) {
|
||||
if (*p == '/') {
|
||||
*p = '\\';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows void InsertString(char **a, size_t i, char *s,
|
||||
char buf[ARG_MAX], size_t *bufi) {
|
||||
char *v;
|
||||
size_t j, k;
|
||||
|
||||
// apply fixups to var=/c/...
|
||||
if ((v = StrChr(s, '=')) && v[1] == '/' && IsAlpha(v[2]) && v[3] == '/') {
|
||||
v = buf + *bufi;
|
||||
for (k = 0; s[k]; ++k) {
|
||||
if (*bufi + 1 < ARG_MAX) {
|
||||
buf[(*bufi)++] = s[k];
|
||||
}
|
||||
}
|
||||
if (*bufi < ARG_MAX) {
|
||||
buf[(*bufi)++] = 0;
|
||||
FixPath(v);
|
||||
s = v;
|
||||
}
|
||||
}
|
||||
|
||||
// append to sorted list
|
||||
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
|
||||
a[j] = a[j - 1];
|
||||
}
|
||||
|
@ -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)
|
||||
*/
|
||||
textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[],
|
||||
const char *extravar) {
|
||||
const char *extravar, char buf[ARG_MAX]) {
|
||||
bool v;
|
||||
char *t;
|
||||
axdx_t rc;
|
||||
uint64_t w;
|
||||
char **vars;
|
||||
wint_t x, y;
|
||||
size_t i, j, k, n, m;
|
||||
size_t i, j, k, n, m, bufi = 0;
|
||||
for (n = 0; envp[n];) n++;
|
||||
vars = alloca((n + 1) * sizeof(char *));
|
||||
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
|
||||
if (extravar) InsertString(vars, n++, extravar);
|
||||
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i], buf, &bufi);
|
||||
if (extravar) InsertString(vars, n++, extravar, buf, &bufi);
|
||||
for (k = i = 0; i < n; ++i) {
|
||||
j = 0;
|
||||
v = false;
|
||||
|
|
|
@ -31,6 +31,10 @@ static inline bool IsSlash(char c) {
|
|||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
static inline int IsAlpha(int c) {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
|
||||
textwindows static const char *FixNtMagicPath(const char *path,
|
||||
unsigned flags) {
|
||||
const struct NtMagicPaths *mp = &kNtMagicPaths;
|
||||
|
@ -78,18 +82,51 @@ textwindows int __mkntpath2(const char *path,
|
|||
*/
|
||||
char16_t *p;
|
||||
const char *q;
|
||||
size_t i, n, m, z;
|
||||
bool isdospath;
|
||||
size_t i, n, m, x, z;
|
||||
if (!path) return efault();
|
||||
path = FixNtMagicPath(path, flags);
|
||||
p = path16;
|
||||
q = path;
|
||||
if (IsSlash(path[0]) && IsSlash(path[1]) && path[2] == '?' &&
|
||||
IsSlash(path[3])) {
|
||||
|
||||
if (IsSlash(q[0]) && IsAlpha(q[1]) && IsSlash(q[2])) {
|
||||
z = MIN(32767, PATH_MAX);
|
||||
// turn "\c\foo" into "\\?\c:\foo"
|
||||
p[0] = '\\';
|
||||
p[1] = '\\';
|
||||
p[2] = '?';
|
||||
p[3] = '\\';
|
||||
p[4] = q[1];
|
||||
p[5] = ':';
|
||||
p[6] = '\\';
|
||||
p += 7;
|
||||
q += 3;
|
||||
z -= 7;
|
||||
x = 7;
|
||||
} else if (IsSlash(q[0]) && IsAlpha(q[1]) && IsSlash(q[2])) {
|
||||
z = MIN(32767, PATH_MAX);
|
||||
// turn "c:\foo" into "\\?\c:\foo"
|
||||
p[0] = '\\';
|
||||
p[1] = '\\';
|
||||
p[2] = '?';
|
||||
p[3] = '\\';
|
||||
p[4] = q[0];
|
||||
p[5] = ':';
|
||||
p[6] = '\\';
|
||||
p += 7;
|
||||
q += 3;
|
||||
z -= 7;
|
||||
x = 7;
|
||||
} else if (IsSlash(q[0]) && IsSlash(q[1]) && q[2] == '?' && IsSlash(q[3])) {
|
||||
z = MIN(32767, PATH_MAX);
|
||||
x = 0;
|
||||
} else {
|
||||
z = MIN(260, PATH_MAX);
|
||||
x = 0;
|
||||
}
|
||||
if (IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' &&
|
||||
|
||||
// turn /tmp into GetTempPath()
|
||||
if (!x && IsSlash(q[0]) && q[1] == 't' && q[2] == 'm' && q[3] == 'p' &&
|
||||
(IsSlash(q[4]) || !q[4])) {
|
||||
m = GetTempPath(z, p);
|
||||
if (!q[4]) return m;
|
||||
|
@ -99,15 +136,20 @@ textwindows int __mkntpath2(const char *path,
|
|||
} else {
|
||||
m = 0;
|
||||
}
|
||||
|
||||
// turn utf-8 into utf-16
|
||||
n = tprecode8to16(p, z, q).ax;
|
||||
if (n >= z - 1) {
|
||||
STRACE("path too long for windows: %#s", path);
|
||||
return enametoolong();
|
||||
}
|
||||
|
||||
// turn slash into backslash
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (p[i] == '/') {
|
||||
p[i] = '\\';
|
||||
}
|
||||
}
|
||||
return m + n;
|
||||
|
||||
return x + m + n;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ static long double nowl_vdso(void) {
|
|||
long double nowl_setup(void) {
|
||||
bool isfast;
|
||||
uint64_t ticks;
|
||||
__gettime = __get_clock_gettime(&isfast);
|
||||
__gettime = __clock_gettime_get(&isfast);
|
||||
if (isfast) {
|
||||
nowl = nowl_vdso;
|
||||
} else if (X86_HAVE(INVTSC)) {
|
||||
|
|
|
@ -94,15 +94,15 @@ TryAgain:
|
|||
}
|
||||
} else {
|
||||
rc = __winerr();
|
||||
STRACE("%s failed: %m", "AccessCheck");
|
||||
STRACE("%s(%#hs) failed: %m", "AccessCheck", pathname);
|
||||
}
|
||||
} else {
|
||||
rc = __winerr();
|
||||
STRACE("%s failed: %m", "DuplicateToken");
|
||||
STRACE("%s(%#hs) failed: %m", "DuplicateToken", pathname);
|
||||
}
|
||||
} else {
|
||||
rc = __winerr();
|
||||
STRACE("%s failed: %m", "OpenProcessToken");
|
||||
STRACE("%s(%#hs) failed: %m", "OpenProcessToken", pathname);
|
||||
}
|
||||
} else {
|
||||
e = GetLastError();
|
||||
|
@ -112,9 +112,11 @@ TryAgain:
|
|||
goto TryAgain;
|
||||
} else {
|
||||
rc = enomem();
|
||||
STRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname);
|
||||
}
|
||||
} else {
|
||||
errno = e;
|
||||
STRACE("%s(%#hs) failed: %m", "GetFileSecurity", pathname);
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,8 +36,9 @@ struct SpawnBlock {
|
|||
struct {
|
||||
char16_t cmdline[ARG_MAX / 2];
|
||||
char16_t envvars[ARG_MAX / 2];
|
||||
char buf[ARG_MAX];
|
||||
};
|
||||
char __pad[ROUNDUP(ARG_MAX / 2 * 2 * sizeof(char16_t), FRAMESIZE)];
|
||||
char __pad[ROUNDUP(ARG_MAX / 2 * 3 * sizeof(char16_t), FRAMESIZE)];
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -83,7 +84,7 @@ textwindows int ntspawn(
|
|||
(block = MapViewOfFileEx(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
|
||||
sizeof(*block), 0)) &&
|
||||
mkntcmdline(block->cmdline, prog, argv) != -1 &&
|
||||
mkntenvblock(block->envvars, envp, extravar) != -1 &&
|
||||
mkntenvblock(block->envvars, envp, extravar, block->buf) != -1 &&
|
||||
CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
|
||||
opt_lpThreadAttributes, bInheritHandles,
|
||||
dwCreationFlags | kNtCreateUnicodeEnvironment,
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
int mkntcmdline(char16_t[ARG_MAX / 2], const char *, char *const[]) hidden;
|
||||
int mkntenvblock(char16_t[ARG_MAX / 2], char *const[], const char *) hidden;
|
||||
int mkntenvblock(char16_t[ARG_MAX / 2], char *const[], const char *,
|
||||
char[ARG_MAX]) hidden;
|
||||
int ntspawn(const char *, char *const[], char *const[], const char *,
|
||||
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
|
||||
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
|
||||
|
|
|
@ -58,10 +58,9 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
|||
p = (char16_t *)((char *)rdb->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||
if (n >= 3 && isalpha(p[0]) && p[1] == ':' && p[2] == '\\') {
|
||||
buf[j++] = '/';
|
||||
buf[j++] = '/';
|
||||
buf[j++] = '?';
|
||||
buf[j++] = '/';
|
||||
p[1] = p[0];
|
||||
p[0] = '/';
|
||||
p[2] = '/';
|
||||
}
|
||||
while (i < n) {
|
||||
x = p[i++] & 0xffff;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#define _KERNTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _DATATRACE 1 /* not configurable w/ flag yet */
|
||||
#define _NTTRACE 1 /* not configurable w/ flag yet */
|
||||
#define _NTTRACE 0 /* not configurable w/ flag yet */
|
||||
|
||||
#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_msync(void *, u64, i32) hidden;
|
||||
i32 sys_munmap(void *, u64) hidden;
|
||||
i32 sys_open(const char *, i32, u32) hidden;
|
||||
i32 sys_openat(i32, const char *, i32, u32) hidden;
|
||||
i32 sys_pause(void) hidden;
|
||||
i32 sys_pipe(i32[hasatleast 2]) hidden;
|
||||
|
|
|
@ -62,19 +62,6 @@ static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) {
|
|||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_quote(out_f out, void *arg, unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
if (flags & FLAGS_REPR) {
|
||||
if (signbit == 63) {
|
||||
if (out("L", arg, 1) == -1) return -1;
|
||||
} else if (signbit == 15) {
|
||||
if (out("u", arg, 1) == -1) return -1;
|
||||
}
|
||||
if (out(&ch, arg, 1) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string to array.
|
||||
*
|
||||
|
@ -103,8 +90,6 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
|||
if (flags & FLAGS_PRECISION) {
|
||||
precision = min(strlen(p), precision);
|
||||
}
|
||||
} else {
|
||||
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
}
|
||||
|
||||
ignorenul = false;
|
||||
|
@ -153,6 +138,9 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
|||
} else if (weaken(strnwidth)) {
|
||||
w = weaken(strnwidth)(p, precision, 0);
|
||||
}
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
w += 2 + (signbit == 63) + (signbit == 15);
|
||||
}
|
||||
if (w < width) {
|
||||
pad = width - w;
|
||||
}
|
||||
|
@ -162,6 +150,16 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
|||
if (__fmt_pad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
if (signbit == 63) {
|
||||
if (out("L", arg, 1) == -1) return -1;
|
||||
} else if (signbit == 15) {
|
||||
if (out("u", arg, 1) == -1) return -1;
|
||||
}
|
||||
buf[0] = qchar;
|
||||
if (out(buf, arg, 1) == -1) return -1;
|
||||
}
|
||||
|
||||
if (justdobytes) {
|
||||
while (precision--) {
|
||||
wc = *p++ & 0xff;
|
||||
|
@ -207,14 +205,14 @@ int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
|||
}
|
||||
}
|
||||
|
||||
if (pad && (flags & FLAGS_LEFT)) {
|
||||
if (__fmt_pad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
buf[0] = qchar;
|
||||
if (out(buf, arg, 1) == -1) return -1;
|
||||
}
|
||||
|
||||
if (pad && (flags & FLAGS_LEFT)) {
|
||||
if (__fmt_pad(out, arg, pad) == -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#define INITIAL_CAPACITY 4
|
||||
|
||||
nop
|
||||
|
||||
// Invokes deferred function calls.
|
||||
//
|
||||
// This offers behavior similar to std::unique_ptr. Functions
|
||||
|
@ -32,8 +34,6 @@
|
|||
//
|
||||
// @param rax,rdx,xmm0,xmm1,st0,st1 is return value
|
||||
// @see test/libc/runtime/gc_test.c
|
||||
nop # backtrace workaround
|
||||
// <LIMBO>
|
||||
__gc: decq __garbage(%rip)
|
||||
mov __garbage(%rip),%r8
|
||||
mov __garbage+16(%rip),%r9
|
||||
|
@ -43,17 +43,16 @@ __gc: decq __garbage(%rip)
|
|||
mov 8(%r8),%r9
|
||||
mov 16(%r8),%rdi
|
||||
push 24(%r8)
|
||||
// </LIMBO>
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
sub $16,%rsp
|
||||
push %rax
|
||||
push %rdx
|
||||
movdqa %xmm0,-16(%rbp)
|
||||
sub $32,%rsp
|
||||
mov %rax,-8(%rbp)
|
||||
mov %rdx,-16(%rbp)
|
||||
movdqa %xmm0,-32(%rbp)
|
||||
call *%r9
|
||||
movdqa -16(%rbp),%xmm0
|
||||
pop %rdx
|
||||
pop %rax
|
||||
movdqa -32(%rbp),%xmm0
|
||||
mov -16(%rbp),%rdx
|
||||
mov -8(%rbp),%rax
|
||||
leave
|
||||
ret
|
||||
9: hlt
|
||||
|
|
|
@ -35,23 +35,24 @@ const char *FindDebugBinary(void) {
|
|||
char *p;
|
||||
size_t n;
|
||||
if (!once) {
|
||||
if (!(res = getenv("COMDBG"))) {
|
||||
p = GetProgramExecutableName();
|
||||
n = strlen(p);
|
||||
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
||||
res = p;
|
||||
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
||||
n + 4 < ARRAYLEN(buf)) {
|
||||
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
|
||||
if (fileexists(buf)) {
|
||||
res = buf;
|
||||
}
|
||||
} else if (n + 8 < ARRAYLEN(buf)) {
|
||||
mempcpy(mempcpy(buf, p, n), ".com.dbg", 9);
|
||||
if (fileexists(buf)) {
|
||||
res = buf;
|
||||
}
|
||||
p = GetProgramExecutableName();
|
||||
n = strlen(p);
|
||||
if (n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) {
|
||||
res = p;
|
||||
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
||||
n + 4 < ARRAYLEN(buf)) {
|
||||
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
|
||||
if (fileexists(buf)) {
|
||||
res = buf;
|
||||
}
|
||||
} else if (n + 8 < ARRAYLEN(buf)) {
|
||||
mempcpy(mempcpy(buf, p, n), ".com.dbg", 9);
|
||||
if (fileexists(buf)) {
|
||||
res = buf;
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
res = getenv("COMDBG");
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
|
@ -23,6 +24,19 @@
|
|||
|
||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
forceinline int IsAlpha(int c) {
|
||||
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
||||
}
|
||||
|
||||
forceinline char *MemChr(const char *s, unsigned char c, unsigned long n) {
|
||||
for (; n; --n, ++s) {
|
||||
if ((*s & 255) == c) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
|
||||
size_t dstsize,
|
||||
const char16_t *src) {
|
||||
|
@ -45,13 +59,51 @@ static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
|
|||
}
|
||||
w = tpenc(x);
|
||||
do {
|
||||
if (r.ax + 1 >= dstsize) break;
|
||||
dst[r.ax++] = w;
|
||||
if (r.ax + 1 < dstsize) {
|
||||
dst[r.ax++] = w;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
}
|
||||
if (r.ax < dstsize) {
|
||||
dst[r.ax] = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
textwindows noinstrument noasan void FixPath(char *path) {
|
||||
char *p;
|
||||
size_t i;
|
||||
|
||||
// turn backslash into slash
|
||||
for (p = path; *p; ++p) {
|
||||
if (*p == '\\') {
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
// turn c:/... into /c/...
|
||||
p = path;
|
||||
if (IsAlpha(p[0]) && p[1] == ':' && p[2] == '/') {
|
||||
p[1] = p[0];
|
||||
p[0] = '/';
|
||||
}
|
||||
for (; *p; ++p) {
|
||||
if (p[0] == ';' && IsAlpha(p[1]) && p[2] == ':' && p[3] == '/') {
|
||||
p[2] = p[1];
|
||||
p[1] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
// turn semicolon into colon
|
||||
for (p = path; *p; ++p) {
|
||||
if (*p == ';') {
|
||||
*p = ':';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transcodes NT environment variable block from UTF-16 to UTF-8.
|
||||
*
|
||||
|
@ -66,12 +118,17 @@ textwindows noasan noinstrument int GetDosEnviron(const char16_t *env,
|
|||
char *buf, size_t size,
|
||||
char **envp, size_t max) {
|
||||
int i;
|
||||
char *p;
|
||||
axdx_t r;
|
||||
i = 0;
|
||||
--size;
|
||||
while (*env) {
|
||||
if (i + 1 < max) envp[i++] = buf;
|
||||
r = Recode16to8(buf, size, env);
|
||||
if ((p = memchr(buf, '=', r.ax)) && IsAlpha(p[1]) && p[2] == ':' &&
|
||||
(p[3] == '\\' || p[3] == '/')) {
|
||||
FixPath(p + 1);
|
||||
}
|
||||
size -= r.ax + 1;
|
||||
buf += r.ax + 1;
|
||||
env += r.dx;
|
||||
|
|
|
@ -73,6 +73,7 @@ char *xdirname(const char *) paramsnonnull() _XMAL;
|
|||
char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL;
|
||||
char *xreadlink(const char *) paramsnonnull() _XMAL;
|
||||
char *xreadlinkat(int, const char *) paramsnonnull() _XMAL;
|
||||
void xfixpath(void);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § eXtended apis » time ─╬─│┼
|
||||
|
|
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 \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/dsp/core
|
||||
|
|
|
@ -50,7 +50,7 @@ o/$(MODE)/test/dsp/scale/%.com.dbg: \
|
|||
o/$(MODE)/test/dsp/scale/scale.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/dsp/scale
|
||||
|
|
|
@ -45,7 +45,7 @@ o/$(MODE)/test/dsp/tty/%.com.dbg: \
|
|||
o/$(MODE)/test/dsp/tty/tty.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/dsp/tty
|
||||
|
|
|
@ -50,7 +50,7 @@ o/$(MODE)/test/libc/alg/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/alg/alg.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_ALG_OBJS): test/libc/alg/test.mk
|
||||
|
|
|
@ -46,7 +46,7 @@ o/$(MODE)/test/libc/bits/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/bits/bits.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_BITS_OBJS): \
|
||||
|
|
|
@ -35,7 +35,7 @@ TEST(clock_gettime, test) {
|
|||
ASSERT_NE(0, ts.tv_sec);
|
||||
ASSERT_NE(0, ts.tv_nsec);
|
||||
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));
|
||||
ASSERT_TRUE(isfast);
|
||||
}
|
||||
|
|
|
@ -45,5 +45,5 @@ TEST(getcwd, testWindows_addsFunnyPrefix) {
|
|||
if (!IsWindows()) return;
|
||||
char path[PATH_MAX];
|
||||
ASSERT_NE(0, getcwd(path, sizeof(path)));
|
||||
EXPECT_STARTSWITH("//?/", path);
|
||||
EXPECT_STARTSWITH("/C/", path);
|
||||
}
|
||||
|
|
|
@ -20,17 +20,18 @@
|
|||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
char tmp[ARG_MAX];
|
||||
char16_t envvars[ARG_MAX / 2];
|
||||
|
||||
TEST(mkntenvblock, emptyList_onlyOutputsDoubleNulStringTerminator) {
|
||||
char *envp[] = {NULL};
|
||||
ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL));
|
||||
ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL, tmp));
|
||||
ASSERT_BINEQ(u" ", envvars);
|
||||
}
|
||||
|
||||
TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) {
|
||||
char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL};
|
||||
ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL));
|
||||
ASSERT_NE(-1, mkntenvblock(envvars, envp, NULL, tmp));
|
||||
ASSERT_BINEQ(u"C = d "
|
||||
u"H D U C = d "
|
||||
u"U = b "
|
||||
|
@ -42,7 +43,7 @@ TEST(mkntenvblock, envp_becomesSortedDoubleNulTerminatedUtf16String) {
|
|||
|
||||
TEST(mkntenvblock, extraVar_getsAdded) {
|
||||
char *envp[] = {"u=b", "c=d", "韩=非", "uh=d", "hduc=d", NULL};
|
||||
ASSERT_NE(-1, mkntenvblock(envvars, envp, "a=a"));
|
||||
ASSERT_NE(-1, mkntenvblock(envvars, envp, "a=a", tmp));
|
||||
ASSERT_BINEQ(u"A = a "
|
||||
u"C = d "
|
||||
u"H D U C = d "
|
||||
|
@ -52,3 +53,11 @@ TEST(mkntenvblock, extraVar_getsAdded) {
|
|||
u" ",
|
||||
envvars);
|
||||
}
|
||||
|
||||
TEST(mkntenvblock, pathvars_getUpdated) {
|
||||
char *envp[] = {"PATH=/c/foo:/d/bar", NULL};
|
||||
ASSERT_NE(-1, mkntenvblock(envvars, envp, 0, tmp));
|
||||
ASSERT_BINEQ(u"P A T H = c : \\ f o o ; d : \\ b a r "
|
||||
u" ",
|
||||
envvars);
|
||||
}
|
||||
|
|
|
@ -101,9 +101,10 @@ TEST(readlinkat, statReadsNameLength) {
|
|||
}
|
||||
|
||||
TEST(readlinkat, realpathReturnsLongPath) {
|
||||
if (!IsWindows()) return;
|
||||
struct stat st;
|
||||
char buf[PATH_MAX];
|
||||
if (!IsWindows()) return;
|
||||
if (!startswith(getcwd(buf, PATH_MAX), "/c/")) return;
|
||||
ASSERT_SYS(0, 0, touch("froot", 0644));
|
||||
ASSERT_STARTSWITH("//?/", realpath("froot", buf));
|
||||
ASSERT_STARTSWITH("/c/", realpath("froot", buf));
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ o/$(MODE)/test/libc/calls/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/calls/calls.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/calls
|
||||
|
|
|
@ -53,7 +53,7 @@ o/$(MODE)/test/libc/dns/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/dns/dns.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/dns
|
||||
|
|
|
@ -278,6 +278,11 @@ TEST(fmt, p) {
|
|||
gc(xasprintf("% 10p", 0xffff800000031337)));
|
||||
}
|
||||
|
||||
TEST(fmt, quoted) {
|
||||
ASSERT_STREQ(" \"hello\"", gc(xasprintf("%`*.*s", 10, 5, "hello")));
|
||||
ASSERT_STREQ("\"hello\" ", gc(xasprintf("%-`*.*s", 10, 5, "hello")));
|
||||
}
|
||||
|
||||
TEST(fmt, regress) {
|
||||
char buf[512];
|
||||
const char *meth = "GET";
|
||||
|
|
|
@ -49,7 +49,7 @@ o/$(MODE)/test/libc/fmt/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/fmt/fmt.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_FMT_OBJS): test/libc/fmt/test.mk
|
||||
|
|
|
@ -54,7 +54,7 @@ o/$(MODE)/test/libc/intrin/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/intrin/intrin.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_INTRIN_OBJS): \
|
||||
|
|
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/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/io.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
@ -40,115 +41,30 @@
|
|||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
int StackOverflow(int f(), int n) {
|
||||
if (n < INT_MAX) {
|
||||
return f(f, n + 1) - 1;
|
||||
} else {
|
||||
return INT_MAX;
|
||||
}
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
STATIC_YOINK("backtrace.com");
|
||||
STATIC_YOINK("backtrace.com.dbg");
|
||||
|
||||
char testlib_enable_tmp_setup_teardown_once;
|
||||
|
||||
void Extract(const char *from, const char *to, int mode) {
|
||||
ASSERT_SYS(0, 3, open(from, O_RDONLY));
|
||||
ASSERT_SYS(0, 4, creat(to, mode));
|
||||
ASSERT_NE(-1, _copyfd(3, 4, -1));
|
||||
EXPECT_SYS(0, 0, close(4));
|
||||
EXPECT_SYS(0, 0, close(3));
|
||||
}
|
||||
|
||||
void SetUpOnce(void) {
|
||||
ASSERT_NE(-1, mkdir("bin", 0755));
|
||||
Extract("/zip/backtrace.com", "bin/backtrace.com", 0755);
|
||||
Extract("/zip/backtrace.com.dbg", "bin/backtrace.com.dbg", 0755);
|
||||
}
|
||||
|
||||
static bool OutputHasSymbol(const char *output, const char *s) {
|
||||
return strstr(output, s) || (!FindDebugBinary() && strstr(output, "NULL"));
|
||||
}
|
||||
|
||||
void FpuCrash(void) {
|
||||
typedef char xmm_t __attribute__((__vector_size__(16)));
|
||||
xmm_t v = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
volatile int x = 0;
|
||||
asm volatile("fldpi");
|
||||
asm volatile("mov\t%0,%%r15" : /* no outputs */ : "g"(0x3133731337));
|
||||
asm volatile("movaps\t%0,%%xmm15" : /* no outputs */ : "x"(v));
|
||||
fputc(7 / x, stdout);
|
||||
}
|
||||
|
||||
char bss[10];
|
||||
void BssOverrunCrash(int n) {
|
||||
int i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
bss[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
char data[10] = "abcdeabcde";
|
||||
void DataOverrunCrash(int n) {
|
||||
int i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
const char rodata[10] = "abcdeabcde";
|
||||
int RodataOverrunCrash(int i) {
|
||||
return rodata[i];
|
||||
}
|
||||
|
||||
char *StackOverrunCrash(int n) {
|
||||
int i;
|
||||
char stack[10];
|
||||
bzero(stack, sizeof(stack));
|
||||
for (i = 0; i < n; ++i) {
|
||||
stack[i] = i;
|
||||
}
|
||||
return strdup(stack);
|
||||
}
|
||||
|
||||
char *MemoryLeakCrash(void) {
|
||||
char *p = strdup("doge");
|
||||
CheckForMemoryLeaks();
|
||||
return p;
|
||||
}
|
||||
|
||||
int NpeCrash(char *p) {
|
||||
asm("nop"); // xxx: due to backtrace addr-1 thing
|
||||
return *p;
|
||||
}
|
||||
|
||||
void (*pFpuCrash)(void) = FpuCrash;
|
||||
void (*pBssOverrunCrash)(int) = BssOverrunCrash;
|
||||
void (*pDataOverrunCrash)(int) = DataOverrunCrash;
|
||||
int (*pRodataOverrunCrash)(int) = RodataOverrunCrash;
|
||||
char *(*pStackOverrunCrash)(int) = StackOverrunCrash;
|
||||
char *(*pMemoryLeakCrash)(void) = MemoryLeakCrash;
|
||||
int (*pNpeCrash)(char *) = NpeCrash;
|
||||
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
|
||||
// o/dbg/test/libc/log/backtrace_test.com
|
||||
// max allocated space 655,360
|
||||
|
@ -189,9 +105,8 @@ TEST(ShowCrashReports, testMemoryLeakCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "6", 0});
|
||||
_exit(127);
|
||||
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "6", 0});
|
||||
_Exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
|
@ -267,9 +182,8 @@ TEST(ShowCrashReports, testStackOverrunCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "5", 0});
|
||||
_exit(127);
|
||||
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "5", 0});
|
||||
_Exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
|
@ -376,9 +290,8 @@ TEST(ShowCrashReports, testDivideByZero) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "1", 0});
|
||||
_exit(127);
|
||||
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "1", 0});
|
||||
_Exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
|
@ -454,9 +367,8 @@ TEST(ShowCrashReports, testStackOverflow) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "9", "--strace", 0});
|
||||
_exit(127);
|
||||
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "9", 0});
|
||||
_Exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
|
@ -571,9 +483,8 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "2", 0});
|
||||
_exit(127);
|
||||
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "2", 0});
|
||||
_Exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
|
@ -650,9 +561,8 @@ TEST(ShowCrashReports, testNpeCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "7", 0});
|
||||
_exit(127);
|
||||
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "7", 0});
|
||||
_Exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
|
@ -710,9 +620,8 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "4", 0});
|
||||
_exit(127);
|
||||
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "4", 0});
|
||||
_Exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
|
@ -765,9 +674,8 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
|
|||
if (!pid) {
|
||||
dup2(fds[1], 1);
|
||||
dup2(fds[1], 2);
|
||||
execv(GetProgramExecutableName(),
|
||||
(char *const[]){GetProgramExecutableName(), "8", 0});
|
||||
_exit(127);
|
||||
execv("bin/backtrace.com", (char *const[]){"bin/backtrace.com", "8", 0});
|
||||
_Exit(127);
|
||||
}
|
||||
close(fds[1]);
|
||||
output = 0;
|
||||
|
|
|
@ -6,56 +6,82 @@ PKGS += TEST_LIBC_LOG
|
|||
TEST_LIBC_LOG_SRCS := $(wildcard test/libc/log/*.c)
|
||||
TEST_LIBC_LOG_SRCS_TEST = $(filter %_test.c,$(TEST_LIBC_LOG_SRCS))
|
||||
|
||||
TEST_LIBC_LOG_OBJS = \
|
||||
$(TEST_LIBC_LOG_SRCS:%.c=o/$(MODE)/%.o)
|
||||
TEST_LIBC_LOG_OBJS = \
|
||||
$(TEST_LIBC_LOG_SRCS:%.c=o/$(MODE)/%.o) \
|
||||
o/$(MODE)/test/libc/log/backtrace.com.zip.o \
|
||||
o/$(MODE)/test/libc/log/backtrace.com.dbg.zip.o
|
||||
|
||||
TEST_LIBC_LOG_COMS = \
|
||||
TEST_LIBC_LOG_COMS = \
|
||||
$(TEST_LIBC_LOG_SRCS:%.c=o/$(MODE)/%.com)
|
||||
|
||||
TEST_LIBC_LOG_BINS = \
|
||||
$(TEST_LIBC_LOG_COMS) \
|
||||
TEST_LIBC_LOG_BINS = \
|
||||
$(TEST_LIBC_LOG_COMS) \
|
||||
$(TEST_LIBC_LOG_COMS:%=%.dbg)
|
||||
|
||||
TEST_LIBC_LOG_TESTS = \
|
||||
TEST_LIBC_LOG_TESTS = \
|
||||
$(TEST_LIBC_LOG_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
|
||||
|
||||
TEST_LIBC_LOG_CHECKS = \
|
||||
TEST_LIBC_LOG_CHECKS = \
|
||||
$(TEST_LIBC_LOG_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
|
||||
|
||||
TEST_LIBC_LOG_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_RUNTIME \
|
||||
NET_HTTP \
|
||||
LIBC_STDIO \
|
||||
LIBC_X \
|
||||
LIBC_INTRIN \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_LOG \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_SYSV \
|
||||
LIBC_LOG
|
||||
TEST_LIBC_LOG_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_RUNTIME \
|
||||
NET_HTTP \
|
||||
LIBC_STDIO \
|
||||
LIBC_X \
|
||||
LIBC_INTRIN \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_LOG \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_SYSV \
|
||||
LIBC_LOG \
|
||||
LIBC_ZIPOS
|
||||
|
||||
TEST_LIBC_LOG_DEPS := \
|
||||
TEST_LIBC_LOG_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TEST_LIBC_LOG_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/test/libc/log/log.pkg: \
|
||||
$(TEST_LIBC_LOG_OBJS) \
|
||||
o/$(MODE)/test/libc/log/log.pkg: \
|
||||
$(TEST_LIBC_LOG_OBJS) \
|
||||
$(foreach x,$(TEST_LIBC_LOG_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/test/libc/log/%.com.dbg: \
|
||||
$(TEST_LIBC_LOG_DEPS) \
|
||||
o/$(MODE)/test/libc/log/%.o \
|
||||
o/$(MODE)/test/libc/log/log.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
o/$(MODE)/test/libc/log/%.com.dbg: \
|
||||
$(TEST_LIBC_LOG_DEPS) \
|
||||
o/$(MODE)/test/libc/log/%.o \
|
||||
o/$(MODE)/test/libc/log/log.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/log/backtrace_test.com.dbg: \
|
||||
$(TEST_LIBC_LOG_DEPS) \
|
||||
o/$(MODE)/test/libc/log/backtrace.com.zip.o \
|
||||
o/$(MODE)/test/libc/log/backtrace.com.dbg.zip.o \
|
||||
o/$(MODE)/test/libc/log/backtrace_test.o \
|
||||
o/$(MODE)/test/libc/log/log.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/log/backtrace.com.dbg: \
|
||||
$(TEST_LIBC_LOG_DEPS) \
|
||||
o/$(MODE)/test/libc/log/backtrace.o \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/log/backtrace.com.zip.o \
|
||||
o/$(MODE)/test/libc/log/backtrace.com.dbg.zip.o: \
|
||||
ZIPOBJ_FLAGS += \
|
||||
-B
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/log
|
||||
o/$(MODE)/test/libc/log: \
|
||||
$(TEST_LIBC_LOG_BINS) \
|
||||
o/$(MODE)/test/libc/log: \
|
||||
$(TEST_LIBC_LOG_BINS) \
|
||||
$(TEST_LIBC_LOG_CHECKS)
|
||||
|
|
|
@ -58,7 +58,7 @@ o/$(MODE)/test/libc/mem/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/mem/mem.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_MEM_OBJS): \
|
||||
|
|
|
@ -55,7 +55,7 @@ o/$(MODE)/test/libc/nexgen32e/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/nexgen32e/nexgen32e.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_NEXGEN32E_OBJS): \
|
||||
|
|
|
@ -52,7 +52,7 @@ o/$(MODE)/test/libc/rand/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/rand/rand.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_RAND_OBJS): test/libc/rand/test.mk
|
||||
|
|
|
@ -10,7 +10,7 @@ if [ "$MODE" = opt ] || [ "$MODE" = optlinux ]; then
|
|||
exit
|
||||
fi
|
||||
|
||||
mkdir -p o/$MODE/test/libc/release/
|
||||
$MKDIR o/$MODE/test/libc/release/
|
||||
|
||||
# smoke test booting on bare metal and printing data to serial uart
|
||||
CMD="o/$MODE/tool/build/blinkenlights.com.dbg -r o/$MODE/examples/hello.com"
|
||||
|
|
|
@ -124,17 +124,17 @@ o/$(MODE)/test/libc/release/smokeansi.com.dbg: \
|
|||
o/$(MODE)/ape/ape.o \
|
||||
o/$(MODE)/cosmopolitan.a
|
||||
|
||||
o/$(MODE)/test/libc/release/metal.ok: \
|
||||
test/libc/release/metal.sh \
|
||||
o/$(MODE)/examples/hello.com \
|
||||
o/$(MODE)/tool/build/blinkenlights.com.dbg
|
||||
@$(COMPILE) -ASHTEST -tT$@ $<
|
||||
|
||||
o/$(MODE)/test/libc/release/emulate.ok: \
|
||||
test/libc/release/emulate.sh \
|
||||
o/$(MODE)/examples/hello.com \
|
||||
o/$(MODE)/tool/build/blinkenlights.com.dbg
|
||||
@$(COMPILE) -ASHTEST -tT$@ $<
|
||||
# TODO(jart): Rewrite these shell scripts as C code.
|
||||
# o/$(MODE)/test/libc/release/metal.ok: \
|
||||
# test/libc/release/metal.sh \
|
||||
# o/$(MODE)/examples/hello.com \
|
||||
# o/$(MODE)/tool/build/blinkenlights.com.dbg
|
||||
# @$(COMPILE) -ASHTEST -tT$@ $<
|
||||
# o/$(MODE)/test/libc/release/emulate.ok: \
|
||||
# test/libc/release/emulate.sh \
|
||||
# o/$(MODE)/examples/hello.com \
|
||||
# o/$(MODE)/tool/build/blinkenlights.com.dbg
|
||||
# @$(COMPILE) -ASHTEST -tT$@ $<
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/release
|
||||
o/$(MODE)/test/libc/release: \
|
||||
|
@ -145,6 +145,4 @@ o/$(MODE)/test/libc/release: \
|
|||
o/$(MODE)/test/libc/release/smokecxx.com \
|
||||
o/$(MODE)/test/libc/release/smokecxx.com.runs \
|
||||
o/$(MODE)/test/libc/release/smokeansi.com \
|
||||
o/$(MODE)/test/libc/release/smokeansi.com.runs \
|
||||
o/$(MODE)/test/libc/release/emulate.ok \
|
||||
o/$(MODE)/test/libc/release/metal.ok
|
||||
o/$(MODE)/test/libc/release/smokeansi.com.runs
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/linux/mmap.h"
|
||||
#include "libc/linux/munmap.h"
|
||||
#include "libc/log/log.h"
|
||||
|
@ -228,6 +229,7 @@ TEST(mmap, cow) {
|
|||
char *p;
|
||||
char path[PATH_MAX];
|
||||
sprintf(path, "%s%s.%ld", kTmpPath, program_invocation_short_name, lemur64());
|
||||
kprintf("path = %#s\n", path);
|
||||
ASSERT_NE(-1, (fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644)));
|
||||
EXPECT_EQ(5, write(fd, "hello", 5));
|
||||
EXPECT_NE(-1, fdatasync(fd));
|
||||
|
|
|
@ -58,7 +58,7 @@ o/$(MODE)/test/libc/runtime/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/runtime/runtime.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/runtime/ape_test.com.dbg: \
|
||||
|
@ -67,7 +67,7 @@ o/$(MODE)/test/libc/runtime/ape_test.com.dbg: \
|
|||
o/$(MODE)/test/libc/runtime/runtime.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_RUNTIME_OBJS): \
|
||||
|
|
|
@ -51,7 +51,7 @@ o/$(MODE)/test/libc/sock/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/sock/sock.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk
|
||||
|
|
|
@ -57,7 +57,7 @@ o/$(MODE)/test/libc/stdio/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/stdio/stdio.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_STDIO_OBJS): \
|
||||
|
|
|
@ -72,7 +72,7 @@ o/$(MODE)/test/libc/str/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/str/str.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/libc/str/blake2.com.dbg: \
|
||||
|
@ -82,7 +82,7 @@ o/$(MODE)/test/libc/str/blake2.com.dbg: \
|
|||
o/$(MODE)/test/libc/str/str.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_STR_OBJS): \
|
||||
|
|
|
@ -48,7 +48,7 @@ o/$(MODE)/test/libc/thread/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/thread/thread.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_THREAD_OBJS): \
|
||||
|
|
|
@ -43,7 +43,7 @@ o/$(MODE)/test/libc/time/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/time/time.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/time
|
||||
|
|
|
@ -53,7 +53,7 @@ o/$(MODE)/test/libc/tinymath/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/tinymath/tinymath.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
$(TEST_LIBC_TINYMATH_OBJS): \
|
||||
|
|
|
@ -47,7 +47,7 @@ o/$(MODE)/test/libc/unicode/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/unicode/unicode.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/unicode
|
||||
|
|
|
@ -53,7 +53,7 @@ o/$(MODE)/test/libc/x/%.com.dbg: \
|
|||
o/$(MODE)/test/libc/x/x.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/libc/x
|
||||
|
|
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 \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
#───────────────────────────────────────────────────────────────────────────────
|
||||
|
|
|
@ -37,7 +37,7 @@ o/$(MODE)/test/net/http/%.com.dbg: \
|
|||
o/$(MODE)/test/net/http/%.o \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/net/http
|
||||
|
|
|
@ -38,7 +38,7 @@ o/$(MODE)/test/net/https/%.com.dbg: \
|
|||
o/$(MODE)/test/net/https/%.o \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/net/https
|
||||
|
|
|
@ -66,7 +66,7 @@ o/$(MODE)/test/tool/args/%.com.dbg: \
|
|||
$(TEST_TOOL_ARGS_A).pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/tool/args
|
||||
|
|
|
@ -66,7 +66,7 @@ o/$(MODE)/test/tool/build/lib/%.com.dbg: \
|
|||
$(TEST_TOOL_BUILD_LIB_A).pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/tool/build/lib
|
||||
|
|
|
@ -68,7 +68,7 @@ o/$(MODE)/test/tool/net/%.com.dbg: \
|
|||
$(TEST_TOOL_NET_A).pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/tool/net
|
||||
|
|
|
@ -74,7 +74,7 @@ o/$(MODE)/test/tool/plinko/%.com.dbg: \
|
|||
$(TEST_TOOL_PLINKO_A).pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/test/tool/plinko/plinko_test.com.runs: \
|
||||
|
|
|
@ -55,7 +55,7 @@ o/$(MODE)/test/tool/viz/lib/%.com.dbg: \
|
|||
o/$(MODE)/test/tool/viz/lib/vizlib.pkg \
|
||||
$(LIBC_TESTMAIN) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PHONY: o/$(MODE)/test/tool/viz/lib
|
||||
|
|
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;
|
||||
size_t n;
|
||||
p = xslurp("/zip/third_party/chibicc/help.txt", &n);
|
||||
xwrite(1, p, n);
|
||||
__paginate(1, p);
|
||||
_Exit(status);
|
||||
}
|
||||
|
||||
|
@ -447,7 +447,8 @@ static bool run_subprocess(char **argv) {
|
|||
_Exit(1);
|
||||
}
|
||||
// Wait for the child process to finish.
|
||||
do rc = wait(&ws);
|
||||
do
|
||||
rc = wait(&ws);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
return WIFEXITED(ws) && WEXITSTATUS(ws) == 0;
|
||||
}
|
||||
|
|
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: \
|
||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_A) \
|
||||
$(APE) \
|
||||
$(APE_NO_MODIFY_SELF) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/third_party/chibicc/help.txt.zip.o \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.main.o \
|
||||
|
@ -102,7 +102,7 @@ o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \
|
|||
o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC2_A) \
|
||||
$(APE) \
|
||||
$(APE_NO_MODIFY_SELF) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/third_party/chibicc/help.txt.zip.o \
|
||||
o/$(MODE)/third_party/chibicc/chibicc.main.chibicc.o \
|
||||
|
@ -122,7 +122,7 @@ o/$(MODE)/third_party/chibicc/chibicc.com: \
|
|||
o/$(MODE)/third_party/chibicc/as.com.dbg: \
|
||||
$(THIRD_PARTY_CHIBICC_A_DEPS) \
|
||||
$(THIRD_PARTY_CHIBICC_A) \
|
||||
$(APE) \
|
||||
$(APE_NO_MODIFY_SELF) \
|
||||
$(CRT) \
|
||||
o/$(MODE)/third_party/chibicc/as.main.o \
|
||||
$(THIRD_PARTY_CHIBICC_A).pkg
|
||||
|
|
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)
|
||||
float __builtin_copysignf(float, float)
|
||||
long double __builtin_copysignl(long double, long double)
|
||||
void __builtin_ia32_movntq(di *, di)
|
||||
int __builtin_ia32_pmovmskb128(v16qi)
|
||||
T __atomic_load(T *addr, int memorder)
|
||||
void __atomic_clear(_Bool *addr, int memorder)
|
||||
_Bool __atomic_test_and_set(void *addr, int memorder)
|
||||
T __atomic_sub_fetch(T *addr, T amt, int memorder)
|
||||
T __atomic_fetch_add(T *addr, T amt, int memorder)
|
||||
T __sync_lock_test_and_set(T *addr, T value, ...)
|
||||
void __sync_lock_release(T *addr, ...)
|
||||
|
||||
|
||||
BUILTIN OBJECTS
|
||||
|
|
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 \
|
||||
$(THIRD_PARTY_CHIBICC_TEST_A).pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \
|
||||
|
@ -88,7 +88,7 @@ o/$(MODE)/third_party/chibicc/test/%2.com.dbg: \
|
|||
o/$(MODE)/third_party/chibicc/test/%.chibicc2.o \
|
||||
$(THIRD_PARTY_CHIBICC_TEST2_A).pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
.PRECIOUS: $(THIRD_PARTY_CHIBICC_TEST_OBJS)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue