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:
Justine Tunney 2022-05-25 11:31:08 -07:00
parent d44ff6ce1f
commit d230a01222
160 changed files with 2754 additions and 1342 deletions

1
.gitignore vendored
View file

@ -11,4 +11,3 @@ __pycache__
/TAGS
/bx_enh_dbg.ini
/tool/emacs/*.elc
/usr/share/dict/words

View file

@ -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

View file

@ -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 |

View file

@ -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

Binary file not shown.

Binary file not shown.

BIN
build/bootstrap/cp.com Executable file

Binary file not shown.

BIN
build/bootstrap/echo.com Executable file

Binary file not shown.

BIN
build/bootstrap/gzip.com Executable file

Binary file not shown.

BIN
build/bootstrap/make.com Executable file

Binary file not shown.

Binary file not shown.

BIN
build/bootstrap/mkdir.com Executable file

Binary file not shown.

Binary file not shown.

BIN
build/bootstrap/pwd.com Executable file

Binary file not shown.

BIN
build/bootstrap/rm.com Executable file

Binary file not shown.

BIN
build/bootstrap/touch.com Executable file

Binary file not shown.

BIN
build/bootstrap/unbundle.com Executable file

Binary file not shown.

Binary file not shown.

View file

@ -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 =

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 $@ $<

View file

@ -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)))) {

View file

@ -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;
}

View 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/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;
}

View file

@ -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: \

View file

@ -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.

View file

@ -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

View 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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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) */

View file

@ -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();
}
}
}
//////////////////////////////////////////////////////////////////////////////

View file

@ -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);
}

View file

@ -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) {

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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)) {

View file

@ -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;
}
}

View file

@ -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,

View file

@ -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 *,

View file

@ -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;

View file

@ -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 "

View file

@ -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;

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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
View 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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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): \

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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

View file

@ -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

View file

@ -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";

View file

@ -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

View file

@ -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
View 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);
}
}

View file

@ -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;

View file

@ -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)

View file

@ -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): \

View file

@ -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): \

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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));

View file

@ -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): \

View file

@ -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

View file

@ -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): \

View file

@ -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): \

View file

@ -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): \

View file

@ -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

View file

@ -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): \

View file

@ -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

View file

@ -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

View 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"));
}

View file

@ -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)
#───────────────────────────────────────────────────────────────────────────────

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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: \

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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