mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-07 02:10:27 +00:00
commit
4b85809dd8
4529 changed files with 199703 additions and 268223 deletions
4
.vscode/c_cpp_properties.json
vendored
4
.vscode/c_cpp_properties.json
vendored
|
@ -15,7 +15,7 @@
|
|||
"alignas(x)",
|
||||
"alignof(x)",
|
||||
"artificial=",
|
||||
"nodiscard=",
|
||||
"dontdiscard=",
|
||||
"mayalias=",
|
||||
"forceinline=",
|
||||
"forcealign(x)=",
|
||||
|
@ -48,7 +48,7 @@
|
|||
"nosideeffect=",
|
||||
"unreachable=",
|
||||
"thatispacked=",
|
||||
"nothrow=",
|
||||
"dontthrow=",
|
||||
"nocallback=",
|
||||
"relegated=",
|
||||
"hidden=",
|
||||
|
|
39
Makefile
39
Makefile
|
@ -37,7 +37,7 @@
|
|||
#
|
||||
# # basic debugging
|
||||
# make -j8 -O MODE=dbg o/dbg/examples/crashreport.com
|
||||
# o/dbg/examples/crashreport.com
|
||||
# o/examples/crashreport.com
|
||||
# less examples/crashreport.c
|
||||
#
|
||||
# # extremely tiny binaries
|
||||
|
@ -60,7 +60,7 @@
|
|||
# build/config.mk
|
||||
|
||||
SHELL = /bin/sh
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win7 win10
|
||||
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win7 win10 xnu
|
||||
SANITY := $(shell build/sanitycheck $$PPID)
|
||||
|
||||
.SUFFIXES:
|
||||
|
@ -69,7 +69,10 @@ SANITY := $(shell build/sanitycheck $$PPID)
|
|||
.PHONY: all o bins check test depend tags
|
||||
|
||||
all: o
|
||||
o: o/$(MODE)/ape \
|
||||
o: o/$(MODE)
|
||||
|
||||
o/$(MODE): \
|
||||
o/$(MODE)/ape \
|
||||
o/$(MODE)/dsp \
|
||||
o/$(MODE)/net \
|
||||
o/$(MODE)/libc \
|
||||
|
@ -108,13 +111,13 @@ include libc/rand/rand.mk # │
|
|||
include libc/unicode/unicode.mk # │
|
||||
include third_party/dlmalloc/dlmalloc.mk #─┘
|
||||
include libc/mem/mem.mk #─┐
|
||||
include libc/ohmyplus/ohmyplus.mk # ├──DYNAMIC RUNTIME
|
||||
include libc/zipos/zipos.mk # │ You can now use stdio
|
||||
include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc()
|
||||
include libc/time/time.mk # │
|
||||
include libc/zipos/zipos.mk # ├──DYNAMIC RUNTIME
|
||||
include third_party/gdtoa/gdtoa.mk # │ You can now use stdio
|
||||
include libc/time/time.mk # │ You can finally call malloc()
|
||||
include libc/thread/thread.mk # │
|
||||
include libc/alg/alg.mk # │
|
||||
include libc/stdio/stdio.mk # │
|
||||
include libc/thread/thread.mk # │
|
||||
include third_party/libcxx/libcxx.mk # │
|
||||
include net/net.mk # │
|
||||
include libc/log/log.mk # │
|
||||
include third_party/bzip2/bzip2.mk # │
|
||||
|
@ -138,14 +141,16 @@ include third_party/third_party.mk
|
|||
include libc/testlib/testlib.mk
|
||||
include tool/viz/lib/vizlib.mk
|
||||
include third_party/linenoise/linenoise.mk
|
||||
include third_party/maxmind/maxmind.mk
|
||||
include third_party/lua/lua.mk
|
||||
include third_party/make/make.mk
|
||||
include third_party/argon2/argon2.mk
|
||||
include third_party/smallz4/smallz4.mk
|
||||
include third_party/sqlite3/sqlite3.mk
|
||||
include third_party/mbedtls/test/test.mk
|
||||
include third_party/quickjs/quickjs.mk
|
||||
include third_party/lz4cli/lz4cli.mk
|
||||
include third_party/infozip/infozip.mk
|
||||
include third_party/zip/zip.mk
|
||||
include tool/build/lib/buildlib.mk
|
||||
include third_party/chibicc/chibicc.mk
|
||||
include third_party/chibicc/test/test.mk
|
||||
|
@ -157,6 +162,11 @@ include examples/examples.mk
|
|||
include examples/pyapp/pyapp.mk
|
||||
include tool/decode/lib/decodelib.mk
|
||||
include tool/decode/decode.mk
|
||||
include tool/lambda/lib/lib.mk
|
||||
include tool/lambda/lambda.mk
|
||||
include tool/plinko/lib/lib.mk
|
||||
include tool/plinko/plinko.mk
|
||||
include test/tool/plinko/test.mk
|
||||
include tool/hash/hash.mk
|
||||
include tool/net/net.mk
|
||||
include tool/viz/viz.mk
|
||||
|
@ -167,6 +177,7 @@ include test/libc/intrin/test.mk
|
|||
include test/libc/mem/test.mk
|
||||
include test/libc/nexgen32e/test.mk
|
||||
include test/libc/runtime/test.mk
|
||||
include test/libc/thread/test.mk
|
||||
include test/libc/sock/test.mk
|
||||
include test/libc/bits/test.mk
|
||||
include test/libc/str/test.mk
|
||||
|
@ -210,7 +221,7 @@ CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
|
|||
|
||||
bins: $(BINS)
|
||||
check: $(CHECKS)
|
||||
test: $(TESTS) all
|
||||
test: $(TESTS)
|
||||
depend: o/$(MODE)/depend
|
||||
tags: TAGS HTAGS
|
||||
|
||||
|
@ -249,7 +260,6 @@ COSMOPOLITAN_OBJECTS = \
|
|||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_MSWSOCK \
|
||||
LIBC_OHMYPLUS \
|
||||
LIBC_X \
|
||||
THIRD_PARTY_GETOPT \
|
||||
LIBC_LOG \
|
||||
|
@ -270,7 +280,9 @@ COSMOPOLITAN_OBJECTS = \
|
|||
LIBC_CALLS \
|
||||
LIBC_RAND \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_NT_KERNELBASE \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_SHELL32 \
|
||||
LIBC_NT_GDI32 \
|
||||
LIBC_NT_COMDLG32 \
|
||||
|
@ -283,6 +295,7 @@ COSMOPOLITAN_OBJECTS = \
|
|||
THIRD_PARTY_COMPILER_RT \
|
||||
LIBC_THREAD \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_INTRIN \
|
||||
|
@ -302,11 +315,11 @@ COSMOPOLITAN_HEADERS = \
|
|||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT \
|
||||
LIBC_OHMYPLUS \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
|
|
39
README.md
39
README.md
|
@ -22,8 +22,8 @@ If you're doing your development work on Linux or BSD then you need just
|
|||
five files to get started. Here's what you do on Linux:
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-1.0.zip
|
||||
unzip cosmopolitan-amalgamation-1.0.zip
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan.zip
|
||||
unzip cosmopolitan.zip
|
||||
printf 'main() { printf("hello world\\n"); }\n' >hello.c
|
||||
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
|
||||
-fno-omit-frame-pointer -pg -mnop-mcount \
|
||||
|
@ -72,14 +72,45 @@ repository that bootstraps using a vendored static gcc9 executable.
|
|||
No further dependencies are required.
|
||||
|
||||
```sh
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan-1.0.tar.gz
|
||||
tar xf cosmopolitan-1.0.tar.gz # see releases page
|
||||
wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz
|
||||
tar xf cosmopolitan.tar.gz # see releases page
|
||||
cd cosmopolitan
|
||||
make -j16
|
||||
o//examples/hello.com
|
||||
find o -name \*.com | xargs ls -rShal | less
|
||||
```
|
||||
|
||||
## GDB
|
||||
|
||||
Here's the recommended `~/.gdbinit` config:
|
||||
|
||||
```
|
||||
set host-charset UTF-8
|
||||
set target-charset UTF-8
|
||||
set target-wide-charset UTF-8
|
||||
set osabi none
|
||||
set complaints 0
|
||||
set confirm off
|
||||
set history save on
|
||||
set history filename ~/.gdb_history
|
||||
define asm
|
||||
layout asm
|
||||
layout reg
|
||||
end
|
||||
define src
|
||||
layout src
|
||||
layout reg
|
||||
end
|
||||
src
|
||||
```
|
||||
|
||||
You normally run the `.com.dbg` file under gdb. If you need to debug the
|
||||
`.com` file itself, then you can load the debug symbols independently as
|
||||
|
||||
```
|
||||
gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
|
||||
```
|
||||
|
||||
## Support Vector
|
||||
|
||||
| Platform | Min Version | Circa |
|
||||
|
|
77
ape/ape.S
77
ape/ape.S
|
@ -660,6 +660,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
|
||||
#if SupportsSystemv() || SupportsMetal()
|
||||
.section .elf.phdrs,"a",@progbits
|
||||
|
||||
.long PT_LOAD
|
||||
.long PF_R|PF_X
|
||||
.stub ape_rom_offset,quad
|
||||
|
@ -668,6 +669,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
.stub ape_rom_filesz,quad
|
||||
.stub ape_rom_memsz,quad
|
||||
.stub ape_rom_align,quad
|
||||
|
||||
.long PT_LOAD
|
||||
.long PF_R|PF_W
|
||||
.stub ape_ram_offset,quad
|
||||
|
@ -676,14 +678,32 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
.stub ape_ram_filesz,quad
|
||||
.stub ape_ram_memsz,quad
|
||||
.stub ape_ram_align,quad
|
||||
|
||||
// APE Stack Configuration
|
||||
//
|
||||
// We actually respect this when allocating a deterministically
|
||||
// addressed stack on Windows and other operating systems. However
|
||||
// there's a few caveats:
|
||||
//
|
||||
// - If ape_stack_pf has PF_X then OpenBSD probably won't work
|
||||
// - We don't bother creating a deterministic stack in MODE=tiny
|
||||
//
|
||||
// With that said, here's some examples of configuration:
|
||||
//
|
||||
// STATIC_SYMBOL("ape_stack_pf", "7"); // RWX
|
||||
// STATIC_STACK_ADDR(0x6fffffff0000);
|
||||
// STATIC_STACK_SIZE(65536);
|
||||
//
|
||||
// @see ape.lds for defaults
|
||||
.long PT_GNU_STACK
|
||||
.long PF_R|PF_W
|
||||
.stub ape_stack_offset,quad
|
||||
.stub ape_stack_vaddr,quad
|
||||
.stub ape_stack_paddr,quad
|
||||
.stub ape_stack_filesz,quad
|
||||
.stub ape_stack_memsz,quad
|
||||
.stub ape_stack_align,quad
|
||||
.stub ape_stack_pf,long # override w/ PF_X for execstack
|
||||
.stub ape_stack_offset,quad # ignored
|
||||
.stub ape_stack_vaddr,quad # is mmap()'d with MAP_FIXED
|
||||
.stub ape_stack_paddr,quad # ignored
|
||||
.stub ape_stack_filesz,quad # ignored
|
||||
.stub ape_stack_memsz,quad # is mmap(size) argument
|
||||
.stub ape_stack_align,quad # must be 16+
|
||||
|
||||
#if SupportsOpenbsd() || SupportsNetbsd()
|
||||
.long PT_NOTE
|
||||
.long PF_R
|
||||
|
@ -1070,18 +1090,12 @@ str.error:
|
|||
str.crlf:
|
||||
.asciz "\r\n"
|
||||
.endobj str.crlf
|
||||
str.cpuid:
|
||||
.asciz "cpuid"
|
||||
.endobj str.cpuid
|
||||
str.oldskool:
|
||||
.asciz "oldskool"
|
||||
.endobj str.oldskool
|
||||
str.e820:
|
||||
.asciz "e820"
|
||||
.endobj str.e820
|
||||
str.long:
|
||||
.asciz "nolong"
|
||||
.endobj str.long
|
||||
str.oldcpu:
|
||||
.asciz "oldcpu"
|
||||
.endobj str.oldcpu
|
||||
|
||||
// Serial Line Configuration (8250 UART 16550)
|
||||
// If it's hacked, it'll at least get hacked very slowly.
|
||||
|
@ -1264,7 +1278,7 @@ longmodeloader:
|
|||
lcheck: pushf # check for i8086 / i8088 / i80186
|
||||
pop %ax
|
||||
test $0x80,%ah # see intel manual volume 1 20.1.2
|
||||
jnz 9f # we now assume 32bit is supported
|
||||
jnz 10f # we now assume 32bit is supported
|
||||
pushfl # now check for i386 or early i486
|
||||
pop %eax # test ability to change cpuid bit
|
||||
mov %eax,%ecx
|
||||
|
@ -1275,7 +1289,7 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
|||
pushfl
|
||||
pop %eax
|
||||
cmp %eax,%ecx
|
||||
je 12f # we assume cpuid inst is available
|
||||
je 10f # we assume cpuid inst is available
|
||||
or %ebx,%eax # puts cpuid bit in the on position
|
||||
push %eax
|
||||
popfl
|
||||
|
@ -1293,11 +1307,7 @@ lcheck: pushf # check for i8086 / i8088 / i80186
|
|||
jne 10f
|
||||
xor %ax,%ax
|
||||
1: ret
|
||||
9: mov $REAL(str.oldskool),%di
|
||||
jmp 20f
|
||||
10: mov $REAL(str.long),%di
|
||||
jmp 20f
|
||||
12: mov $REAL(str.cpuid),%di
|
||||
10: mov $REAL(str.oldcpu),%di
|
||||
20: call rldie
|
||||
.endfn lcheck
|
||||
|
||||
|
@ -1615,5 +1625,26 @@ ape_idata_ro:
|
|||
__data_start:
|
||||
.previous
|
||||
|
||||
.section .dataepilogue,"aw",@progbits
|
||||
.type __data_end,@object
|
||||
.globl __data_end
|
||||
.hidden __data_end
|
||||
__data_end:
|
||||
.previous
|
||||
|
||||
.section .bssprologue,"aw",@nobits
|
||||
.type __bss_start,@object
|
||||
.globl __bss_start
|
||||
.hidden __bss_start
|
||||
__bss_start:
|
||||
.previous
|
||||
|
||||
.section .bssepilogue,"aw",@nobits
|
||||
.type __bss_end,@object
|
||||
.globl __bss_end
|
||||
.hidden __bss_end
|
||||
__bss_end:
|
||||
.previous
|
||||
|
||||
.end
|
||||
|
18
ape/ape.lds
18
ape/ape.lds
|
@ -177,6 +177,8 @@
|
|||
#include "ape/macros.internal.h"
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/elf/pf2prot.internal.h"
|
||||
#include "libc/nt/pedef.internal.h"
|
||||
#include "libc/zip.h"
|
||||
|
||||
|
@ -342,7 +344,7 @@ SECTIONS {
|
|||
/*END: Read Only Data (only needed for initialization) */
|
||||
/*END: Read Only Data */
|
||||
} :Rom
|
||||
|
||||
|
||||
.tdata . : {
|
||||
_tdata_start = .;
|
||||
*(SORT_BY_ALIGNMENT(.tdata))
|
||||
|
@ -358,6 +360,8 @@ SECTIONS {
|
|||
|
||||
.data . : {
|
||||
/*BEGIN: Read/Write Data */
|
||||
KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*)))
|
||||
/*BEGIN: NT FORK COPYING */
|
||||
KEEP(*(.dataprologue))
|
||||
*(.data .data.*)
|
||||
KEEP(*(SORT_BY_NAME(.sort.data.*)))
|
||||
|
@ -378,6 +382,8 @@ SECTIONS {
|
|||
. = ALIGN(__SIZEOF_POINTER__);
|
||||
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
|
||||
KEEP(*(.piro.pad.data))
|
||||
KEEP(*(.dataepilogue))
|
||||
/*END: NT FORK COPYING */
|
||||
. = ALIGN(PAGESIZE);
|
||||
HIDDEN(_edata = .);
|
||||
PROVIDE_HIDDEN(edata = .);
|
||||
|
@ -404,6 +410,8 @@ SECTIONS {
|
|||
/*BEGIN: bss memory that's addressable */
|
||||
|
||||
.bss ALIGN(64) : {
|
||||
/*BEGIN: NT FORK COPYING */
|
||||
KEEP(*(.bssprologue))
|
||||
KEEP(*(SORT_BY_NAME(.piro.bss.init.*)))
|
||||
*(.piro.bss)
|
||||
KEEP(*(SORT_BY_NAME(.piro.bss.sort.*)))
|
||||
|
@ -418,6 +426,8 @@ SECTIONS {
|
|||
|
||||
KEEP(*(SORT_BY_NAME(.sort.bss.*)))
|
||||
|
||||
KEEP(*(.bssepilogue))
|
||||
/*END: NT FORK COPYING */
|
||||
. = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */
|
||||
HIDDEN(_end = .);
|
||||
PROVIDE_HIDDEN(end = .);
|
||||
|
@ -477,9 +487,9 @@ PFSTUB4(ape_elf_phnum, (ape_phdrs_end - ape_phdrs) / 56);
|
|||
PFSTUB4(ape_elf_shnum, 0);
|
||||
PFSTUB4(ape_elf_shstrndx, 0);
|
||||
|
||||
HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE));
|
||||
HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE));
|
||||
HIDDEN(__privileged_size = (ROUNDUP(__privileged_end, PAGESIZE) -
|
||||
ROUNDDOWN(__privileged_start, PAGESIZE)));
|
||||
ROUNDDOWN(__privileged_start, PAGESIZE)));
|
||||
|
||||
HIDDEN(ape_rom_offset = 0);
|
||||
HIDDEN(ape_rom_vaddr = ADDR(.head));
|
||||
|
@ -497,6 +507,8 @@ HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr);
|
|||
HIDDEN(ape_ram_align = PAGESIZE);
|
||||
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
|
||||
|
||||
HIDDEN(ape_stack_pf = DEFINED(ape_stack_pf) ? ape_stack_pf : PF_R | PF_W);
|
||||
HIDDEN(ape_stack_prot = _PF2PROT(ape_stack_pf));
|
||||
HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz);
|
||||
HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE);
|
||||
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -5,6 +5,7 @@
|
|||
#
|
||||
# - `make`
|
||||
# - Backtraces
|
||||
# - Syscall tracing
|
||||
# - Function tracing
|
||||
# - Reasonably small
|
||||
# - Reasonably optimized
|
||||
|
@ -13,6 +14,7 @@ ifeq ($(MODE),)
|
|||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
$(FTRACE) \
|
||||
-DSYSDEBUG \
|
||||
-Og
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
|
@ -23,6 +25,8 @@ endif
|
|||
# - `make MODE=opt`
|
||||
# - Backtraces
|
||||
# - More optimized
|
||||
# - Syscall tracing
|
||||
# - Function tracing
|
||||
# - Reasonably small
|
||||
# - No memory corruption detection
|
||||
# - assert() / CHECK_xx() may leak code into binary for debuggability
|
||||
|
@ -35,7 +39,9 @@ CONFIG_CPPFLAGS += \
|
|||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
$(FTRACE) \
|
||||
-O3
|
||||
-DSYSDEBUG \
|
||||
-O3 \
|
||||
-fmerge-all-constants
|
||||
TARGET_ARCH ?= \
|
||||
-march=native
|
||||
endif
|
||||
|
@ -55,7 +61,7 @@ CONFIG_CPPFLAGS += \
|
|||
-Wa,-msse2avx \
|
||||
-DSUPPORT_VECTOR=1
|
||||
CONFIG_CCFLAGS += \
|
||||
-O3
|
||||
-O3 -fmerge-all-constants
|
||||
DEFAULT_COPTS += \
|
||||
-mred-zone
|
||||
TARGET_ARCH ?= \
|
||||
|
@ -122,10 +128,12 @@ CONFIG_CPPFLAGS += \
|
|||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
$(FTRACE) \
|
||||
-DSYSDEBUG \
|
||||
-O2 \
|
||||
-fno-inline
|
||||
CONFIG_COPTS += \
|
||||
-fsanitize=address
|
||||
-fsanitize=address \
|
||||
-fsanitize=undefined
|
||||
TARGET_ARCH ?= \
|
||||
-msse3
|
||||
OVERRIDE_CCFLAGS += \
|
||||
|
@ -287,7 +295,7 @@ endif
|
|||
# LLVM Mode
|
||||
ifeq ($(MODE), llvm)
|
||||
TARGET_ARCH ?= -msse3
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -O2
|
||||
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -DSYSDEBUG -O2
|
||||
AS = clang
|
||||
CC = clang
|
||||
CXX = clang++
|
||||
|
|
|
@ -100,7 +100,8 @@ SANITIZER = \
|
|||
NO_MAGIC = \
|
||||
-mno-fentry \
|
||||
-fno-stack-protector \
|
||||
-fwrapv
|
||||
-fwrapv \
|
||||
-fno-sanitize=all
|
||||
|
||||
OLD_CODE = \
|
||||
-fno-strict-aliasing \
|
||||
|
@ -148,7 +149,6 @@ DEFAULT_CFLAGS = \
|
|||
-std=gnu2x
|
||||
|
||||
DEFAULT_CXXFLAGS = \
|
||||
-std=gnu++11 \
|
||||
-fno-rtti \
|
||||
-fno-exceptions \
|
||||
-fuse-cxa-atexit \
|
||||
|
@ -169,7 +169,7 @@ DEFAULT_LDFLAGS = \
|
|||
--gc-sections \
|
||||
--build-id=none \
|
||||
--no-dynamic-linker \
|
||||
-zmax-page-size=0x1000
|
||||
-zmax-page-size=0x1000 #--cref -Map=$@.map
|
||||
|
||||
ZIPOBJ_FLAGS = \
|
||||
-b$(IMAGE_BASE_VIRTUAL)
|
||||
|
@ -301,6 +301,9 @@ OBJECTIFY.greg.c = \
|
|||
-fno-instrument-functions \
|
||||
-fno-optimize-sibling-calls \
|
||||
-fno-sanitize=all \
|
||||
-ffreestanding \
|
||||
-mno-fentry \
|
||||
-fwrapv \
|
||||
-c
|
||||
|
||||
OBJECTIFY.ansi.c = $(CC) $(OBJECTIFY.c.flags) -ansi -Wextra -Werror -pedantic-errors -c
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@"
|
||||
|
||||
# ctags doesn't understand function prototypes, e.g.
|
||||
# bool isheap(void *p) nothrow nocallback;
|
||||
# bool isheap(void *p) dontthrow nocallback;
|
||||
set -- --regex-c='/^[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)(.*/\2/b' "$@"
|
||||
|
||||
# ctags doesn't understand function pointers, e.g.
|
||||
|
|
|
@ -31,7 +31,7 @@ o/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds)
|
|||
o/%.inc: %.h ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) -D__ASSEMBLER__ -P $<
|
||||
o/%.pkg: ; @$(COMPILE) -APACKAGE -T$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) $(filter %.o,$^)
|
||||
o/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
|
||||
o/%.h.okk: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
o/%.okk: % ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
||||
o/%.zip.o: o/% ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
|
@ -60,7 +60,8 @@ o/$(MODE)/%.o: %.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx
|
|||
o/$(MODE)/%.o: o/$(MODE)/%.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.h.ok: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
|
||||
o/$(MODE)/%.h.okk: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
o/$(MODE)/%.hh.ok: %.hh ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
o/$(MODE)/%.okk: % ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
|
||||
o/$(MODE)/%.cxx.o: %.c ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) -xc++ $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
||||
|
@ -77,7 +78,9 @@ 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) $<
|
||||
o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
|
||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||
|
||||
o/%.a:
|
||||
|
|
|
@ -37,4 +37,3 @@ sad16x8n:
|
|||
jnz 0b
|
||||
1: .leafepilogue
|
||||
.endfn sad16x8n,globl,hidden
|
||||
.source __FILE__
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
clamp4int256$core:
|
||||
.leafprologue
|
||||
|
|
|
@ -72,7 +72,8 @@ static const float PLM_VIDEO_PIXEL_ASPECT_RATIO[] = {
|
|||
0.6735, /* 3:4? */
|
||||
0.7031, /* MPEG-1 / MPEG-2 video encoding divergence? */
|
||||
0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815,
|
||||
1.0255, 1.0695, 1.0950, 1.1575, 1.2051};
|
||||
1.0255, 1.0695, 1.0950, 1.1575, 1.2051,
|
||||
};
|
||||
|
||||
static const float PLM_VIDEO_PICTURE_RATE[] = {
|
||||
23.976, /* NTSC-Film */
|
||||
|
|
|
@ -101,7 +101,7 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
|
|||
if (!off) off = (dar - 1) / 2;
|
||||
f = dar < 1 ? 1 / dar : dar;
|
||||
s = 3 * f + 4;
|
||||
fweights = gc(xcalloc(s, sizeof(double)));
|
||||
fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
|
||||
res = NewSamplingSolution(dn, s);
|
||||
weights = res->weights;
|
||||
indices = res->indices;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "dsp/tty/tty.h"
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
|
@ -30,7 +31,7 @@
|
|||
static int ttysetcursor(int fd, bool visible) {
|
||||
struct NtConsoleCursorInfo ntcursor;
|
||||
char code[8] = "\e[?25l";
|
||||
if (IsTerminalInarticulate()) return 0;
|
||||
if (__nocolor) return 0;
|
||||
if (visible) code[5] = 'h';
|
||||
if (SupportsWindows()) {
|
||||
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
||||
|
|
|
@ -31,13 +31,6 @@ int ttysetraw(struct termios *conf, int64_t flags) {
|
|||
conf->c_cflag &= ~(CSIZE | PARENB);
|
||||
conf->c_cflag |= CS8;
|
||||
conf->c_iflag |= IUTF8;
|
||||
/* if (flags & kTtyLfToCrLf) { */
|
||||
/* /\* conf->c_oflag &= ~(OLCUC | OCRNL | ONLRET | OFILL | OFDEL); *\/ */
|
||||
/* /\* conf->c_oflag |= ONLCR | ONOCR; *\/ */
|
||||
/* conf->c_oflag |= ONLCR; */
|
||||
/* } else { */
|
||||
/* conf->c_oflag &= ~OPOST; */
|
||||
/* } */
|
||||
if (!(flags & kTtySigs)) {
|
||||
conf->c_iflag &= ~(IGNBRK | BRKINT);
|
||||
conf->c_lflag &= ~(ISIG);
|
||||
|
|
|
@ -731,19 +731,19 @@ static bool ChunkEq(struct TtyRgb c[hasatleast 4],
|
|||
}
|
||||
|
||||
static struct TtyRgb *CopyChunk(struct TtyRgb chunk[hasatleast 4],
|
||||
const struct TtyRgb *c, size_t n) {
|
||||
chunk[TL] = c[0 + 0];
|
||||
chunk[TR] = c[0 + 1];
|
||||
chunk[BL] = c[n + 0];
|
||||
chunk[BR] = c[n + 1];
|
||||
const struct TtyRgb *c, size_t xn) {
|
||||
chunk[TL] = c[00 + 0];
|
||||
chunk[TR] = c[00 + 1];
|
||||
chunk[BL] = c[xn + 0];
|
||||
chunk[BR] = c[xn + 1];
|
||||
return chunk;
|
||||
}
|
||||
|
||||
static dontinline char *CopyRun(char *v, size_t n,
|
||||
struct TtyRgb lastchunk[hasatleast 4],
|
||||
const struct TtyRgb **c, size_t *x,
|
||||
struct TtyRgb *bg, struct TtyRgb *fg,
|
||||
struct Glyph *glyph) {
|
||||
struct TtyRgb lastchunk[hasatleast 4],
|
||||
const struct TtyRgb **c, size_t *x,
|
||||
struct TtyRgb *bg, struct TtyRgb *fg,
|
||||
struct Glyph *glyph) {
|
||||
struct TtyRgb chunk[4];
|
||||
if (memcmp(glyph, &kGlyphs[1][0], sizeof(*glyph)) == 0) {
|
||||
if (!ttyeq(*bg, *fg)) {
|
||||
|
@ -766,17 +766,18 @@ static dontinline char *CopyRun(char *v, size_t n,
|
|||
/**
|
||||
* Maps 2×2 pixel chunks onto ANSI UNICODE cells.
|
||||
* @note h/t Nick Black for his quadrant blitting work on notcurses
|
||||
* @note yn and xn need to be even
|
||||
*/
|
||||
char *ttyraster(char *v, const struct TtyRgb *c, size_t yn, size_t n,
|
||||
char *ttyraster(char *v, const struct TtyRgb *c, size_t yn, size_t xn,
|
||||
struct TtyRgb bg, struct TtyRgb fg) {
|
||||
unsigned y, x;
|
||||
struct Pick p;
|
||||
struct Glyph glyph;
|
||||
struct TtyRgb chun[4], lastchunk[4];
|
||||
for (y = 0; y < yn; y += 2, c += n) {
|
||||
for (y = 0; y < yn; y += 2, c += xn) {
|
||||
if (y) *v++ = '\r', *v++ = '\n';
|
||||
for (x = 0; x < n; x += 2, c += 2) {
|
||||
CopyChunk(chun, c, n);
|
||||
for (x = 0; x < xn; x += 2, c += 2) {
|
||||
CopyChunk(chun, c, xn);
|
||||
if (ttyquant()->alg == kTtyQuantTrue) {
|
||||
if (ttyquant()->blocks == kTtyBlocksCp437) {
|
||||
p = PickBlockCp437True(chun[TL], chun[TR], chun[BL], chun[BR]);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
// Returns index of minimum uint16 in array.
|
||||
//
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
// Returns index of minimum positive int16 in array.
|
||||
//
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/macros.internal.h"
|
||||
.source __FILE__
|
||||
|
||||
// Dispatches to fastest windex() implementation.
|
||||
.initbss 300,_init_windex
|
||||
|
|
|
@ -18,9 +18,12 @@
|
|||
* make -j12 o//examples/auto-launch-gdb-on-crash.com
|
||||
* o//examples/auto-launch-gdb-on-crash.com
|
||||
*
|
||||
* Backtrace is logged instead if run outside interactive terminal.
|
||||
* Environmental factors such as GDB, MAKEFLAGS, ADDR2LINE, TERM, and
|
||||
* isatty(STDERR_FILENO) should also be taken into consideration:
|
||||
* Backtrace is logged instead if run outside interactive terminal. We
|
||||
* also don't auto-launch GDB on non-Linux since the development tools
|
||||
* on other platforms generally can't be relied upon to correctly debug
|
||||
* binaries built with a Linux toolchain. Environmental factors such as
|
||||
* GDB, MAKEFLAGS, ADDR2LINE, TERM, and isatty(STDERR_FILENO) should
|
||||
* also be taken into consideration:
|
||||
*
|
||||
* $ export GDB=eoatuhshtuone
|
||||
* $ o//examples/auto-launch-gdb-on-crash.com
|
||||
|
@ -37,7 +40,7 @@
|
|||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
showcrashreports();
|
||||
ShowCrashReports();
|
||||
asm("int3"); /* cf. __die(), perror("msg"), abort(), exit(1), _Exit(1) */
|
||||
return 0;
|
||||
}
|
||||
|
|
62
examples/auto-memory-safety-crash.c
Normal file
62
examples/auto-memory-safety-crash.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#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/bits/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* ASAN static memory safety crash example.
|
||||
*
|
||||
* make -j8 MODE=dbg o/dbg/examples/auto-memory-safety-crash.com
|
||||
* o/dbg/examples/auto-memory-safety-crash.com
|
||||
*
|
||||
* You should see:
|
||||
*
|
||||
* global redzone 1-byte store at 0x42700d shadow 0x8007ce01
|
||||
* ./o/dbg/examples/auto-memory-safety-crash.com
|
||||
* x
|
||||
* ........................................GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
|
||||
* |0 |0 |0 |0 |5 |-18 |-18 |-18 |-18
|
||||
* f.☼▼ä f.☼▼ä f☼▼D hello
|
||||
* 000000400000-000000427000 .text
|
||||
* 000000427000-000000429000 .data ←address
|
||||
* 00007fff0000-00008000ffff
|
||||
* 000080070000-00008008ffff ←shadow
|
||||
* 0e007fff0000-0e008000ffff
|
||||
* 100047d20000-100047d3ffff
|
||||
* 6ffffffe0000-6fffffffffff
|
||||
* the memory in question belongs to the symbols
|
||||
* buffer [0x427000,0x42700c] size 13
|
||||
* the crash was caused by
|
||||
* 0x00000000004046f3: __die at libc/log/die.c:40
|
||||
* 0x0000000000404aed: __asan_report_store at libc/intrin/asan.c:1183
|
||||
* 0x0000000000402552: main at examples/auto-memory-safety-crash.c:27
|
||||
* 0x000000000040268d: cosmo at libc/runtime/cosmo.S:64
|
||||
* 0x00000000004021ae: _start at libc/crt/crt.S:77
|
||||
*
|
||||
* @see libc/intrin/asancodes.h for meaning of G, etc. and negative numbers
|
||||
* @see libc/nexgen32e/kcp437.S for meaning of symbols
|
||||
*/
|
||||
|
||||
char buffer[13] = "hello";
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!IsAsan()) {
|
||||
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
exit(1);
|
||||
}
|
||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||
int i = 13;
|
||||
asm("" : "+r"(i)); /* prevent compiler being smart */
|
||||
buffer[i] = 1;
|
||||
return 0;
|
||||
}
|
74
examples/auto-memory-safety-crash2.c
Normal file
74
examples/auto-memory-safety-crash2.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
#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/bits/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* ASAN heap memory safety crash example.
|
||||
*
|
||||
* make -j8 MODE=dbg o/dbg/examples/auto-memory-safety-crash2.com
|
||||
* o/dbg/examples/auto-memory-safety-crash2.com
|
||||
*
|
||||
* You should see:
|
||||
*
|
||||
* heap overrun 1-byte store at 0x10008004002d shadow 0x20090000005
|
||||
* ./o/dbg/examples/auto-memory-safety-crash2.com
|
||||
* x
|
||||
* OOOOOOOOOOOUUUUUUUUUUUUUUUU.............OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
|
||||
* |-7 |-6 |-6 |0 |5 |-7 |-7 |-7 |-7
|
||||
* »!@ ÿ▄:Y╩≥= S hello ∙∙∙∙∙∙∙ ♪ GT◘&@ á+@ »!@
|
||||
* 000000400000-00000042b000 .text
|
||||
* 00000042b000-00000042d000 .data
|
||||
* 00007fff0000-00008000ffff
|
||||
* 000080070000-00008008ffff
|
||||
* 02008fff0000-02009000ffff ←shadow
|
||||
* 0e007fff0000-0e008000ffff
|
||||
* 10003ab90000-10003abaffff
|
||||
* 100080000000-10008000ffff ←address
|
||||
* 6ffffffe0000-6fffffffffff
|
||||
*
|
||||
* the memory was allocated by
|
||||
* 0x100080040020 64 bytes [dlmalloc]
|
||||
* 0x100080040030 13 bytes [actual]
|
||||
* 402608 main
|
||||
* 402ba0 cosmo
|
||||
* 4021af _start
|
||||
*
|
||||
* the crash was caused by
|
||||
* 0x0000000000404793: __die at libc/log/die.c:40
|
||||
* 0x0000000000404f56: __asan_report_store at libc/intrin/asan.c:1183
|
||||
* 0x0000000000402579: main at examples/auto-memory-safety-crash2.c:30
|
||||
* 0x000000000040270f: cosmo at libc/runtime/cosmo.S:64
|
||||
* 0x00000000004021ae: _start at libc/crt/crt.S:77
|
||||
*
|
||||
* @see libc/intrin/asancodes.h for meaning of U, O, etc. and negative numbers
|
||||
* @see libc/nexgen32e/kcp437.S for meaning of symbols
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!IsAsan()) {
|
||||
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
exit(1);
|
||||
}
|
||||
char *buffer;
|
||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||
buffer = malloc(13);
|
||||
strcpy(buffer, "hello");
|
||||
int i = 13;
|
||||
asm("" : "+r"(i)); /* prevent compiler being smart */
|
||||
buffer[i] = 1;
|
||||
asm("" : "+r"(buffer)); /* prevent compiler being smart */
|
||||
return 0;
|
||||
}
|
39
examples/auto-memory-safety-crash3.c
Normal file
39
examples/auto-memory-safety-crash3.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
#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/bits/bits.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* ASAN use-after-free memory safety crash example.
|
||||
*
|
||||
* make -j8 MODE=dbg o/dbg/examples/auto-memory-safety-crash3.com
|
||||
* o/dbg/examples/auto-memory-safety-crash3.com
|
||||
*
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!IsAsan()) {
|
||||
printf("this example is intended for MODE=asan or MODE=dbg\n");
|
||||
exit(1);
|
||||
}
|
||||
char *buffer;
|
||||
ShowCrashReports(); /* not needed but yoinks appropriate symbols */
|
||||
buffer = malloc(13);
|
||||
strcpy(buffer, "hello");
|
||||
free(buffer);
|
||||
asm("" : "+r"(buffer)); /* prevent compiler being smart */
|
||||
buffer[0] = 1;
|
||||
return 0;
|
||||
}
|
|
@ -7,19 +7,30 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
showcrashreports();
|
||||
ShowCrashReports();
|
||||
|
||||
if (IsDebuggerPresent(false)) {
|
||||
printf("debugger found!\r\n");
|
||||
DebugBreak();
|
||||
return 0;
|
||||
kprintf("debugger found!%n");
|
||||
} else {
|
||||
kprintf("try running: gdb %s%n", argv[0]);
|
||||
kprintf("try running: o//tool/build/strace.com %s%n", argv[0]);
|
||||
}
|
||||
printf("try running: gdb %s\r\n", argv[0]);
|
||||
return 1;
|
||||
|
||||
asm volatile("mov\t%4,%%r10\n\t"
|
||||
"mov\t%5,%%r8\n\t"
|
||||
"mov\t%6,%%r9\n\t"
|
||||
"int3"
|
||||
: /* no outputs */
|
||||
: "a"(0), "D"(1), "S"(2), "d"(3), "g"(4), "g"(5), "g"(6)
|
||||
: "r8", "r9", "r10");
|
||||
|
||||
printf("recovered from SIGTRAP without handler\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -73,14 +73,14 @@ void GetOpts(int argc, char *argv[]) {
|
|||
|
||||
int cp(const char *src, const char *dst) {
|
||||
if (endswith(dst, "/") || isdirectory(dst)) {
|
||||
dst = _gc(xasprintf("%s/%s", dst, basename));
|
||||
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;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
|
38
examples/cplusplus-stl.cc
Normal file
38
examples/cplusplus-stl.cc
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*-mode:c++;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8-*-│
|
||||
│vi: set net ft=c++ ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/libcxx/map"
|
||||
#include "third_party/libcxx/string"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
printf("std::map + std::string example\n");
|
||||
std::map<std::string, int> m{
|
||||
{"CPU", 10},
|
||||
{"GPU", 15},
|
||||
{"RAM", 20},
|
||||
};
|
||||
printf("m[\"CPU\"] is %d\n", m["CPU"]);
|
||||
printf("m[\"RAM\"] is %d\n", m["RAM"]);
|
||||
printf("m[\"GPU\"] is %d\n", m["GPU"]);
|
||||
printf("setting cpu to 25\n");
|
||||
m["CPU"] = 25; // update an existing value
|
||||
printf("m[\"CPU\"] is %d\n", m["CPU"]);
|
||||
printf("m[\"RAM\"] is %d\n", m["RAM"]);
|
||||
printf("m[\"GPU\"] is %d\n", m["GPU"]);
|
||||
}
|
|
@ -24,6 +24,6 @@
|
|||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile int64_t x;
|
||||
showcrashreports();
|
||||
ShowCrashReports();
|
||||
return 1 / (x = 0);
|
||||
}
|
||||
|
|
52
examples/crashreport2.c
Normal file
52
examples/crashreport2.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
#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/log/log.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* @fileoverview CTRL+\ debugging example
|
||||
*
|
||||
* make -j8 -O o//examples/crashreport2.com
|
||||
* o//examples/crashreport2.com
|
||||
*
|
||||
* Assuming you call ShowCrashReports() from main(), you can press
|
||||
* `CTRL+\` at anny time to generate a `SIGQUIT` message that lets you
|
||||
* debug wrongness and freezups.
|
||||
*
|
||||
* On supported platforms, this will cause GDB to automatically attach.
|
||||
* The nice thing about this, is you can start stepping through your
|
||||
* code at the precice instruction where the interrupt happened. See
|
||||
* `libc/log/attachdebugger.c` to see how it works.
|
||||
*
|
||||
* If you wish to suppress the auto-GDB behavior, then:
|
||||
*
|
||||
* export GDB=
|
||||
*
|
||||
* Or alternatively:
|
||||
*
|
||||
* extern int __isworker;
|
||||
* __isworker = true;
|
||||
*
|
||||
* Will cause your `SIGQUIT` handler to just print a crash report
|
||||
* instead. This is useful for production software that might be running
|
||||
* in a terminal environment like GNU Screen, but it's not desirable to
|
||||
* have ten worker processes trying to attach GDB at once.
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
volatile int64_t x;
|
||||
ShowCrashReports();
|
||||
printf("please press ctrl+\\ and see what happens...\n");
|
||||
sigsuspend(0);
|
||||
printf("\n\n");
|
||||
printf("congratulations! your program is now resuming\n");
|
||||
return 0;
|
||||
}
|
|
@ -36,7 +36,7 @@ int main(int argc, char *argv[]) {
|
|||
fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n");
|
||||
CHECK_NE(-1, sigaction(SIGINT, &saint, NULL));
|
||||
for (;;) {
|
||||
rc = read(0, buf, BUFSIZ);
|
||||
rc = read(0, buf, 512);
|
||||
if (rc != -1) {
|
||||
got = rc;
|
||||
} else {
|
||||
|
|
|
@ -65,11 +65,26 @@
|
|||
#define HeaderEqualCase(H, S) \
|
||||
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
|
||||
|
||||
int sock;
|
||||
|
||||
static bool TuneSocket(int fd, int a, int b, int x) {
|
||||
if (!b) return false;
|
||||
return setsockopt(fd, a, b, &x, sizeof(x)) != -1;
|
||||
}
|
||||
|
||||
static void Write(const void *p, size_t n) {
|
||||
ssize_t rc;
|
||||
rc = write(1, p, n);
|
||||
if (rc == -1 && errno == EPIPE) {
|
||||
close(sock);
|
||||
exit(128 + SIGPIPE);
|
||||
}
|
||||
if (rc != n) {
|
||||
fprintf(stderr, "write failed: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int TlsSend(void *c, const unsigned char *p, size_t n) {
|
||||
int rc;
|
||||
NOISEF("begin send %zu", n);
|
||||
|
@ -106,8 +121,7 @@ static wontreturn void PrintUsage(FILE *f, int rc) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!NoDebug()) showcrashreports();
|
||||
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
|
||||
if (!NoDebug()) ShowCrashReports();
|
||||
|
||||
/*
|
||||
* Read flags.
|
||||
|
@ -226,19 +240,17 @@ int main(int argc, char *argv[]) {
|
|||
*/
|
||||
mbedtls_ssl_config conf;
|
||||
mbedtls_ssl_context ssl;
|
||||
mbedtls_x509_crt *cachain = 0;
|
||||
mbedtls_ctr_drbg_context drbg;
|
||||
if (usessl) {
|
||||
mbedtls_ssl_init(&ssl);
|
||||
mbedtls_ctr_drbg_init(&drbg);
|
||||
mbedtls_ssl_config_init(&conf);
|
||||
cachain = GetSslRoots();
|
||||
CHECK_EQ(0, mbedtls_ctr_drbg_seed(&drbg, GetEntropy, 0, "justine", 7));
|
||||
CHECK_EQ(0, mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT));
|
||||
mbedtls_ssl_conf_authmode(&conf, authmode);
|
||||
mbedtls_ssl_conf_ca_chain(&conf, cachain, 0);
|
||||
mbedtls_ssl_conf_ca_chain(&conf, GetSslRoots(), 0);
|
||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &drbg);
|
||||
if (!IsTiny()) mbedtls_ssl_conf_dbg(&conf, TlsDebug, 0);
|
||||
CHECK_EQ(0, mbedtls_ssl_setup(&ssl, &conf));
|
||||
|
@ -258,7 +270,7 @@ int main(int argc, char *argv[]) {
|
|||
/*
|
||||
* Connect to server.
|
||||
*/
|
||||
int ret, sock;
|
||||
int ret;
|
||||
CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
|
||||
addr->ai_protocol, false,
|
||||
&(struct timeval){-60})));
|
||||
|
@ -283,6 +295,8 @@ int main(int argc, char *argv[]) {
|
|||
CHECK_EQ(n, write(sock, request, n));
|
||||
}
|
||||
|
||||
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
|
||||
|
||||
/*
|
||||
* Handle response.
|
||||
*/
|
||||
|
@ -330,7 +344,7 @@ int main(int argc, char *argv[]) {
|
|||
break;
|
||||
}
|
||||
if (method == kHttpHead) {
|
||||
CHECK_EQ(hdrlen, write(1, p, hdrlen));
|
||||
Write(p, hdrlen);
|
||||
goto Finished;
|
||||
} else if (msg.status == 204 || msg.status == 304) {
|
||||
goto Finished;
|
||||
|
@ -348,32 +362,32 @@ int main(int argc, char *argv[]) {
|
|||
t = kHttpClientStateBodyLengthed;
|
||||
paylen = rc;
|
||||
if (paylen > i - hdrlen) {
|
||||
CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen));
|
||||
Write(p + hdrlen, i - hdrlen);
|
||||
} else {
|
||||
CHECK_EQ(paylen, write(1, p + hdrlen, paylen));
|
||||
Write(p + hdrlen, paylen);
|
||||
goto Finished;
|
||||
}
|
||||
} else {
|
||||
t = kHttpClientStateBody;
|
||||
CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen));
|
||||
Write(p + hdrlen, i - hdrlen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kHttpClientStateBody:
|
||||
if (!g) goto Finished;
|
||||
CHECK_EQ(g, write(1, p + i - g, g));
|
||||
Write(p + i - g, g);
|
||||
break;
|
||||
case kHttpClientStateBodyLengthed:
|
||||
CHECK(g);
|
||||
if (i - hdrlen > paylen) g = hdrlen + paylen - (i - g);
|
||||
CHECK_EQ(g, write(1, p + i - g, g));
|
||||
Write(p + i - g, g);
|
||||
if (i - hdrlen >= paylen) goto Finished;
|
||||
break;
|
||||
case kHttpClientStateBodyChunked:
|
||||
Chunked:
|
||||
CHECK_NE(-1, (rc = Unchunk(&u, p + hdrlen, i - hdrlen, &paylen)));
|
||||
if (rc) {
|
||||
CHECK_EQ(paylen, write(1, p + hdrlen, paylen));
|
||||
Write(p + hdrlen, paylen);
|
||||
goto Finished;
|
||||
}
|
||||
break;
|
||||
|
@ -397,7 +411,6 @@ Finished:
|
|||
mbedtls_ssl_free(&ssl);
|
||||
mbedtls_ctr_drbg_free(&drbg);
|
||||
mbedtls_ssl_config_free(&conf);
|
||||
mbedtls_x509_crt_free(cachain);
|
||||
mbedtls_ctr_drbg_free(&drbg);
|
||||
}
|
||||
|
||||
|
|
62
examples/datauri.c
Normal file
62
examples/datauri.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#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/log/log.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "net/http/http.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/stb/stb_image.h"
|
||||
|
||||
#define USAGE \
|
||||
" [FLAGS] FILE...\n\
|
||||
Utility for printing data:base64 URIs.\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-h Help\n"
|
||||
|
||||
void PrintUsage(int rc, FILE *f) {
|
||||
fputs("Usage: ", f);
|
||||
fputs(program_invocation_name, f);
|
||||
fputs(USAGE, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void PrintUri(const char *path) {
|
||||
size_t n;
|
||||
void *img, *src, *mime;
|
||||
int opt, i;
|
||||
if (!(img = gc(xslurp(path, &n)))) exit(2);
|
||||
fputs("data:", stdout);
|
||||
fputs(FindContentType(path, -1), stdout);
|
||||
fputs(";base64,", stdout);
|
||||
fputs(gc(EncodeBase64(img, n, 0)), stdout);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
while ((i = getopt(argc, argv, "?h")) != -1) {
|
||||
switch (i) {
|
||||
case '?':
|
||||
case 'h':
|
||||
PrintUsage(0, stdout);
|
||||
default:
|
||||
PrintUsage(1, stderr);
|
||||
}
|
||||
}
|
||||
if (optind == argc) {
|
||||
PrintUsage(1, stderr);
|
||||
}
|
||||
for (i = optind; i < argc; ++i) {
|
||||
PrintUri(argv[i]);
|
||||
}
|
||||
}
|
|
@ -8,135 +8,146 @@ EXAMPLES_MAINS_S = $(filter %.S,$(EXAMPLES_FILES))
|
|||
EXAMPLES_MAINS_C = $(filter %.c,$(EXAMPLES_FILES))
|
||||
EXAMPLES_MAINS_CC = $(filter %.cc,$(EXAMPLES_FILES))
|
||||
|
||||
EXAMPLES_SRCS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
EXAMPLES_SRCS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
$(EXAMPLES_MAINS_CC)
|
||||
|
||||
EXAMPLES_MAINS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
EXAMPLES_MAINS = \
|
||||
$(EXAMPLES_MAINS_S) \
|
||||
$(EXAMPLES_MAINS_C) \
|
||||
$(EXAMPLES_MAINS_CC)
|
||||
|
||||
EXAMPLES_OBJS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.o) \
|
||||
EXAMPLES_OBJS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.o) \
|
||||
$(EXAMPLES_MAINS_CC:%.cc=o/$(MODE)/%.o)
|
||||
|
||||
EXAMPLES_COMS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.com) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.com) \
|
||||
EXAMPLES_COMS = \
|
||||
$(EXAMPLES_MAINS_S:%.S=o/$(MODE)/%.com) \
|
||||
$(EXAMPLES_MAINS_C:%.c=o/$(MODE)/%.com) \
|
||||
$(EXAMPLES_MAINS_CC:%.cc=o/$(MODE)/%.com)
|
||||
|
||||
EXAMPLES_BINS = \
|
||||
$(EXAMPLES_COMS) \
|
||||
EXAMPLES_BINS = \
|
||||
$(EXAMPLES_COMS) \
|
||||
$(EXAMPLES_COMS:%=%.dbg)
|
||||
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
DSP_SCALE \
|
||||
DSP_TTY \
|
||||
LIBC_ALG \
|
||||
LIBC_BITS \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_OHMYPLUS \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LINENOISE \
|
||||
THIRD_PARTY_LUA \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_QUICKJS \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_BUILD_LIB \
|
||||
EXAMPLES_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
DSP_SCALE \
|
||||
DSP_TTY \
|
||||
LIBC_ALG \
|
||||
LIBC_BITS \
|
||||
LIBC_CALLS \
|
||||
LIBC_DNS \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_USER32 \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_RAND \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_THREAD \
|
||||
LIBC_TIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
LIBC_ZIPOS \
|
||||
NET_HTTP \
|
||||
NET_HTTPS \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_DLMALLOC \
|
||||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_LIBCXX \
|
||||
THIRD_PARTY_LINENOISE \
|
||||
THIRD_PARTY_LUA \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_QUICKJS \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
TOOL_BUILD_LIB \
|
||||
TOOL_VIZ_LIB
|
||||
|
||||
EXAMPLES_DEPS := \
|
||||
EXAMPLES_DEPS := \
|
||||
$(call uniq,$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/examples/examples.pkg: \
|
||||
$(EXAMPLES_OBJS) \
|
||||
o/$(MODE)/examples/examples.pkg: \
|
||||
$(EXAMPLES_OBJS) \
|
||||
$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/examples/unbourne.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
o/$(MODE)/examples/unbourne.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED \
|
||||
-fpie
|
||||
|
||||
o/$(MODE)/examples/%.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/examples/%.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/%.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(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) \
|
||||
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)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/ispell.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/ispell.o \
|
||||
o/$(MODE)/usr/share/dict/words.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/examples/ispell.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/ispell.o \
|
||||
o/$(MODE)/usr/share/dict/words.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/nesemu1.o \
|
||||
o/$(MODE)/usr/share/rom/mario.nes.zip.o \
|
||||
o/$(MODE)/usr/share/rom/zelda.nes.zip.o \
|
||||
o/$(MODE)/usr/share/rom/tetris.nes.zip.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/examples/nesemu1.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/nesemu1.o \
|
||||
o/$(MODE)/usr/share/rom/mario.nes.zip.o \
|
||||
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)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/examples/hello.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/hello.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
o/$(MODE)/examples/nesemu1.com: \
|
||||
o/$(MODE)/examples/nesemu1.com.dbg \
|
||||
o/$(MODE)/third_party/zip/zip.com \
|
||||
o/$(MODE)/tool/build/symtab.com
|
||||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -ASYMTAB o/$(MODE)/tool/build/symtab.com \
|
||||
-o o/$(MODE)/examples/.nesemu1/.symtab $<
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
|
||||
o/$(MODE)/examples/.nesemu1/.symtab
|
||||
|
||||
o/$(MODE)/examples/hello.com.dbg: \
|
||||
$(EXAMPLES_DEPS) \
|
||||
o/$(MODE)/examples/hello.o \
|
||||
o/$(MODE)/examples/examples.pkg \
|
||||
$(CRT) \
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
|
@ -149,6 +160,6 @@ usr/share/dict/words: usr/share/dict/words.gz
|
|||
@$(GZ) $(ZFLAGS) -d <$< >$@
|
||||
|
||||
.PHONY: o/$(MODE)/examples
|
||||
o/$(MODE)/examples: \
|
||||
o/$(MODE)/examples/package \
|
||||
o/$(MODE)/examples: \
|
||||
o/$(MODE)/examples/package \
|
||||
$(EXAMPLES_BINS)
|
||||
|
|
|
@ -8,14 +8,26 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
STATIC_YOINK("strerror");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 3) {
|
||||
fputs("USAGE: EXEC.COM PROG ARGV₀ [ARGV₁...]\n", stderr);
|
||||
sigset_t ss;
|
||||
if (argc < 2) {
|
||||
fputs("USAGE: EXEC.COM PROG [ARGV₀...]\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// block arbitrary signal so __printargs() looks cooler
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGPWR);
|
||||
sigprocmask(SIG_BLOCK, &ss, 0);
|
||||
|
||||
execv(argv[1], argv + 2);
|
||||
return 127;
|
||||
}
|
||||
|
|
23
examples/forkexec.c
Normal file
23
examples/forkexec.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#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/stdio/stdio.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int pid;
|
||||
if (argc < 3) {
|
||||
fputs("USAGE: FORKEXEC.COM PROG ARGV₀ [ARGV₁...]\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
if (!fork()) {
|
||||
execv(argv[1], argv + 2);
|
||||
return 127;
|
||||
}
|
||||
}
|
25
examples/forkexecwait.c
Normal file
25
examples/forkexecwait.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
#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/stdio/stdio.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int pid;
|
||||
volatile void *p;
|
||||
if (argc < 3) {
|
||||
fputs("USAGE: FORKEXECWAIT.COM PROG ARGV₀ [ARGV₁...]\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
if (!fork()) {
|
||||
execv(argv[1], argv + 2);
|
||||
return 127;
|
||||
}
|
||||
wait(0);
|
||||
}
|
|
@ -8,13 +8,17 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/nt/process.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
dontinline void dostuff(const char *s) {
|
||||
int i, us;
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
|
||||
int main(int argc, char *argv[]) {
|
||||
int c, n;
|
||||
char a[22];
|
||||
char a[22], *p;
|
||||
if ((c = GetCpuCount())) {
|
||||
n = int64toarray_radix10(c, a);
|
||||
a[n++] = '\n';
|
||||
return write(1, a, n) == n ? 0 : 1;
|
||||
p = FormatInt64(a, c);
|
||||
*p++ = '\n';
|
||||
return write(1, a, p - a) == p - a ? 0 : 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -209,6 +209,7 @@ const struct Function {
|
|||
{"getrandom", GetRandom}, //
|
||||
{"inc", inc}, //
|
||||
{"knuth", knuth}, //
|
||||
{"lemur64", lemur64}, //
|
||||
{"libc", libc}, //
|
||||
{"moby", moby}, //
|
||||
{"mt19937", _mt19937}, //
|
||||
|
|
|
@ -44,8 +44,8 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
// clang-format off
|
||||
|
||||
/* clang-format off */
|
||||
#define DICT "usr/share/dict/hangman"
|
||||
#define MAXERR 7
|
||||
#define MINSCORE 0
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#endif
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
STATIC_YOINK("mmap"); // TODO: fix bandaid for MODE=asan
|
||||
|
||||
int main() {
|
||||
printf("%s\n", "hello world");
|
||||
return 0;
|
||||
|
|
101
examples/img.c
101
examples/img.c
|
@ -7,23 +7,98 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "net/http/http.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/stb/stb_image.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Utility for printing HTML <img> tags.
|
||||
*/
|
||||
#define USAGE \
|
||||
" [FLAGS] IMG...\n\
|
||||
Utility for printing HTML <img> tags.\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-h Help\n\
|
||||
-a Wrap with <a> tag\n\
|
||||
-u Embed data:base64 URI\n"
|
||||
|
||||
int scale;
|
||||
bool linktag;
|
||||
bool datauri;
|
||||
bool sizeonly;
|
||||
|
||||
void PrintUsage(int rc, FILE *f) {
|
||||
fputs("Usage: ", f);
|
||||
fputs(program_invocation_name, f);
|
||||
fputs(USAGE, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void PrintImg(const char *path) {
|
||||
size_t n;
|
||||
int opt, i, yn, xn, cn, w, h;
|
||||
void *img, *pix, *src, *mime;
|
||||
if (!(img = gc(xslurp(path, &n)))) exit(2);
|
||||
if (!(pix = gc(stbi_load_from_memory(img, n, &xn, &yn, &cn, 0)))) exit(3);
|
||||
if (linktag) {
|
||||
printf("<a href=\"%s\"\n >", path);
|
||||
}
|
||||
src = path;
|
||||
if (datauri) {
|
||||
src = xasprintf("data:%s;base64,%s", FindContentType(path, -1),
|
||||
gc(EncodeBase64(img, n, &n)));
|
||||
}
|
||||
w = (xn + (1 << scale) / 2) >> scale;
|
||||
h = (yn + (1 << scale) / 2) >> scale;
|
||||
if (sizeonly) {
|
||||
printf("width=\"%d\" height=\"%d\"", w, h);
|
||||
} else {
|
||||
printf("<img width=\"%d\" height=\"%d\" alt=\"[%s]\"\n src=\"%s\">", w,
|
||||
h, path, src);
|
||||
}
|
||||
if (linktag) {
|
||||
printf("</a>");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
void *p;
|
||||
size_t n;
|
||||
int yn, xn, cn;
|
||||
if (argc != 2) return 1;
|
||||
if (!(p = xslurp(argv[1], &n))) return 2;
|
||||
if (!(p = stbi_load_from_memory(p, n, &xn, &yn, &cn, 0))) return 3;
|
||||
printf("<img src=\"%s\" width=\"%d\" height=\"%d\"\n"
|
||||
" alt=\"[%s]\">\n",
|
||||
argv[1], (xn + 1) >> 1, (yn + 1) >> 1, argv[1]);
|
||||
return 0;
|
||||
if (!NoDebug()) ShowCrashReports();
|
||||
int i;
|
||||
while ((i = getopt(argc, argv, "?huas01234")) != -1) {
|
||||
switch (i) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
scale = i - '0';
|
||||
break;
|
||||
case 's':
|
||||
sizeonly = true;
|
||||
break;
|
||||
case 'a':
|
||||
linktag = true;
|
||||
break;
|
||||
case 'u':
|
||||
datauri = true;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
PrintUsage(0, stdout);
|
||||
default:
|
||||
PrintUsage(1, stderr);
|
||||
}
|
||||
}
|
||||
if (optind == argc) {
|
||||
PrintUsage(1, stderr);
|
||||
}
|
||||
for (i = optind; i < argc; ++i) {
|
||||
PrintImg(argv[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ void SpellChecker(void) {
|
|||
printf("word: ");
|
||||
fflush(stdout);
|
||||
if (getline(&line, &linesize, stdin) > 0) {
|
||||
query = strtolower(chomp(line));
|
||||
query = strtolower(_chomp(line));
|
||||
if (critbit0_contains(&words, query)) {
|
||||
printf("ok\r\n");
|
||||
} else {
|
||||
|
@ -147,13 +147,13 @@ void SpellChecker(void) {
|
|||
void LoadWords(void) {
|
||||
CHECK_NOTNULL((f = fopen("/zip/usr/share/dict/words", "r")));
|
||||
while (getline(&line, &linesize, f) > 0) {
|
||||
critbit0_insert(&words, strtolower(chomp(line)));
|
||||
critbit0_insert(&words, strtolower(_chomp(line)));
|
||||
}
|
||||
CHECK_NE(-1, fclose(f));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
showcrashreports();
|
||||
if (!NoDebug()) ShowCrashReports();
|
||||
LoadWords();
|
||||
SpellChecker();
|
||||
return 0;
|
||||
|
|
|
@ -154,7 +154,7 @@ void editorSetStatusMessage(const char *fmt, ...);
|
|||
* matches and keywords. The file name matches are used in order to match
|
||||
* a given syntax with a given file name: if a match pattern starts with a
|
||||
* dot, it is matched as the last past of the filename, for example ".c".
|
||||
* Otherwise the pattern is just searched inside the filenme, like "Makefile").
|
||||
* Otherwise the pattern is just searched inside the filename, like "Makefile").
|
||||
*
|
||||
* The list of keywords to highlight is just a list of words, however if they
|
||||
* a trailing '|' character is added at the end, they are highlighted in
|
||||
|
@ -249,7 +249,10 @@ fatal:
|
|||
int editorReadKey(int64_t fd) {
|
||||
int nread;
|
||||
char c, seq[3];
|
||||
if ((nread = read(fd, &c, 1)) == -1) exit(1);
|
||||
do {
|
||||
nread = read(fd, &c, 1);
|
||||
if (nread == -1) exit(1);
|
||||
} while (!nread);
|
||||
|
||||
while (1) {
|
||||
switch (c) {
|
||||
|
@ -390,7 +393,7 @@ int is_separator(int c) {
|
|||
|
||||
/* Return true if the specified row last char is part of a multi line comment
|
||||
* that starts at this row or at one before, and does not end at the end
|
||||
* of the row but spawns to the next row. */
|
||||
* of the row but spans to the next row. */
|
||||
int editorRowHasOpenComment(erow *row) {
|
||||
if (row->hl && row->rsize && row->hl[row->rsize - 1] == HL_MLCOMMENT &&
|
||||
(row->rsize < 2 || (row->render[row->rsize - 2] != '*' ||
|
||||
|
@ -651,7 +654,7 @@ void editorFreeRow(erow *row) {
|
|||
free(row->hl);
|
||||
}
|
||||
|
||||
/* Remove the row at the specified position, shifting the remainign on the
|
||||
/* Remove the row at the specified position, shifting the remaining on the
|
||||
* top. */
|
||||
void editorDelRow(int at) {
|
||||
erow *row;
|
||||
|
@ -667,7 +670,7 @@ void editorDelRow(int at) {
|
|||
|
||||
/* Turn the editor rows into a single heap-allocated string.
|
||||
* Returns the pointer to the heap-allocated string and populate the
|
||||
* integer pointed by 'buflen' with the size of the string, escluding
|
||||
* integer pointed by 'buflen' with the size of the string, excluding
|
||||
* the final nulterm. */
|
||||
char *editorRowsToString(int *buflen) {
|
||||
char *buf = NULL, *p;
|
||||
|
|
23
examples/linenoise.c
Normal file
23
examples/linenoise.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#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/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/linenoise/linenoise.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *line;
|
||||
while ((line = linenoiseWithHistory("IN> ", "foo"))) {
|
||||
fputs("OUT> ", stdout);
|
||||
fputs(line, stdout);
|
||||
fputs("\n", stdout);
|
||||
free(line);
|
||||
}
|
||||
return 0;
|
||||
}
|
20
examples/loadavg.c
Normal file
20
examples/loadavg.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#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/log/check.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
double x[3];
|
||||
CHECK_NE(-1, getloadavg(x, 3));
|
||||
printf("%g %g %g\n", x[0], x[1], x[2]);
|
||||
return 0;
|
||||
}
|
|
@ -26,7 +26,6 @@
|
|||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/ohmyplus/vector.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
@ -43,6 +42,7 @@
|
|||
#include "libc/zip.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/libcxx/vector"
|
||||
#include "tool/viz/lib/knobs.h"
|
||||
|
||||
STATIC_YOINK("zip_uri_support");
|
||||
|
@ -1673,7 +1673,7 @@ char* GetLine(void) {
|
|||
static char* line;
|
||||
static size_t linesize;
|
||||
if (getline(&line, &linesize, stdin) > 0) {
|
||||
return chomp(line);
|
||||
return _chomp(line);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1703,7 +1703,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
|
|||
if ((ffplay = commandvenv("FFPLAY", "ffplay"))) {
|
||||
devnull = open("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
pipe2(pipefds, O_CLOEXEC);
|
||||
if (!(playpid_ = vfork())) {
|
||||
if (!(playpid_ = fork())) {
|
||||
const char* const args[] = {
|
||||
"ffplay", "-nodisp", "-loglevel", "quiet", "-fflags",
|
||||
"nobuffer", "-ac", "1", "-ar", "1789773",
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/gdb.h"
|
||||
#include "libc/log/log.h"
|
||||
|
@ -152,7 +153,7 @@ void Draw(void) {
|
|||
int main(int argc, char *argv[]) {
|
||||
struct sigaction sa[2] = {{.sa_handler = OnShutdown},
|
||||
{.sa_handler = OnInvalidate}};
|
||||
showcrashreports();
|
||||
if (!NoDebug()) ShowCrashReports();
|
||||
Setup();
|
||||
Enter();
|
||||
GetTtySize();
|
||||
|
|
|
@ -7,94 +7,8 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
const struct AuxiliaryValue {
|
||||
const char *fmt;
|
||||
long *id;
|
||||
const char *name;
|
||||
const char *description;
|
||||
} kAuxiliaryValues[] = {
|
||||
{"%012lx", &AT_EXECFD, "AT_EXECFD", "file descriptor of program"},
|
||||
{"%012lx", &AT_PHDR, "AT_PHDR", "address of elf program headers"},
|
||||
{"%012lx", &AT_PHENT, "AT_PHENT", "size of program header entry"},
|
||||
{"%012lx", &AT_PHNUM, "AT_PHNUM", "number of program headers"},
|
||||
{"%012lx", &AT_PAGESZ, "AT_PAGESZ", "system page size"},
|
||||
{"%012lx", &AT_BASE, "AT_BASE", "base address of the program interpreter"},
|
||||
{"%012lx", &AT_ENTRY, "AT_ENTRY", "entry address of executable"},
|
||||
{"%012lx", &AT_NOTELF, "AT_NOTELF", "set if not an elf"},
|
||||
{"%-12d", &AT_UID, "AT_UID", "real user id of thread"},
|
||||
{"%-12d", &AT_EUID, "AT_EUID", "effective user id of thread"},
|
||||
{"%-12d", &AT_GID, "AT_GID", "real group id of thread"},
|
||||
{"%-12d", &AT_EGID, "AT_EGID", "effective group id of thread"},
|
||||
{"%-12d", &AT_CLKTCK, "AT_CLKTCK", "frequency of times() counts"},
|
||||
{"%012lx", &AT_OSRELDATE, "AT_OSRELDATE",
|
||||
"freebsd release number, e.g. 1200086"},
|
||||
{"%012lx", &AT_PLATFORM, "AT_PLATFORM",
|
||||
"string identifying hardware platform"},
|
||||
{"%012lx", &AT_DCACHEBSIZE, "AT_DCACHEBSIZE", "data cache block size"},
|
||||
{"%012lx", &AT_ICACHEBSIZE, "AT_ICACHEBSIZE",
|
||||
"instruction cache block size"},
|
||||
{"%012lx", &AT_UCACHEBSIZE, "AT_UCACHEBSIZE", "unified cache block size"},
|
||||
{"%012lx", &AT_SECURE, "AT_SECURE",
|
||||
"for set{u,g}id binz & security blankets"},
|
||||
{"%-12s", &AT_BASE_PLATFORM, "AT_BASE_PLATFORM",
|
||||
"string identifying real platform"},
|
||||
{"%012lx", &AT_RANDOM, "AT_RANDOM", "address of sixteen random bytes"},
|
||||
{"%-12s", &AT_EXECFN, "AT_EXECFN", "pathname used to execute program"},
|
||||
{"%012lx", &AT_SYSINFO_EHDR, "AT_SYSINFO_EHDR",
|
||||
"linux virtual dso page address"},
|
||||
{"%012lx", &AT_FLAGS, "AT_FLAGS", "unused?"},
|
||||
{"%012lx", &AT_HWCAP, "AT_HWCAP", "cpu stuff"},
|
||||
{"%012lx", &AT_HWCAP2, "AT_HWCAP2", "more cpu stuff"},
|
||||
};
|
||||
|
||||
const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
|
||||
if (x == *kAuxiliaryValues[i].id) {
|
||||
return kAuxiliaryValues + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char **envp) {
|
||||
long key;
|
||||
unsigned i;
|
||||
unsigned long *auxp;
|
||||
char fmt[64], **env;
|
||||
struct AuxiliaryValue *auxinfo;
|
||||
uint32_t varlen;
|
||||
char16_t var[PATH_MAX];
|
||||
printf("\nArguments:\n");
|
||||
for (i = 0; i < __argc; ++i) {
|
||||
printf(" ☼ %s\n", argv[i]);
|
||||
}
|
||||
printf("\nEnvironment:\n");
|
||||
for (env = envp; *env; ++env) {
|
||||
printf(" ☼ %s\n", *env);
|
||||
}
|
||||
printf("\nAuxiliary Values:\n");
|
||||
for (auxp = __auxv; *auxp; auxp += 2) {
|
||||
if ((auxinfo = DescribeAuxv(auxp[0]))) {
|
||||
stpcpy(stpcpy(stpcpy(fmt, "%16s[%4ld] = "), auxinfo->fmt), " # %s\n");
|
||||
printf(fmt, auxinfo->name, auxp[0], auxp[1], auxinfo->description);
|
||||
} else {
|
||||
printf("%16s[%4ld] = %012lx\n", "unknown", auxp[0], auxp[1]);
|
||||
}
|
||||
}
|
||||
printf("\nSpecial Directories:\n");
|
||||
printf(" ☼ kTmpPath = %`'s\n", kTmpPath);
|
||||
printf(" ☼ kNtSystemDirectory = %`'s\n", kNtSystemDirectory);
|
||||
printf(" ☼ kNtWindowsDirectory = %`'s\n", kNtWindowsDirectory);
|
||||
printf(" ☼ program_executable_name = %`'s\n", program_executable_name);
|
||||
return 0;
|
||||
int main() {
|
||||
__printargs("");
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
if (isprime) {
|
||||
int64toarray_radix10(i, buf);
|
||||
FormatInt64(buf, i);
|
||||
fputs(buf, stdout);
|
||||
fputc('\n', stdout);
|
||||
if (k++ % 100 == 0) {
|
||||
|
|
72
examples/rlimit.c
Normal file
72
examples/rlimit.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#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/strace.internal.h"
|
||||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/rlim.h"
|
||||
#include "libc/sysv/consts/rlimit.h"
|
||||
|
||||
/**
|
||||
* @fileoverview tool for printing and changing system resource limits
|
||||
*
|
||||
* This is what you do if you want to not accidentally bomb your system
|
||||
* with runaway code. If you haven't accidentally bombed your UNIX
|
||||
* system before then you're not pushing it hard enough.
|
||||
*/
|
||||
|
||||
static void SetLimit(int resource, uint64_t soft, uint64_t hard) {
|
||||
struct rlimit old;
|
||||
struct rlimit lim = {soft, hard};
|
||||
if (resource == 127) return;
|
||||
if (setrlimit(resource, &lim) == -1) {
|
||||
if (!getrlimit(resource, &old)) {
|
||||
lim.rlim_max = MIN(hard, old.rlim_max);
|
||||
lim.rlim_cur = MIN(soft, lim.rlim_max);
|
||||
if (!setrlimit(resource, &lim)) {
|
||||
fprintf(stderr, "%sNOTE: SETRLIMIT(%s) DOWNGRADED TO {%,ld, %,ld}\n",
|
||||
__strace_rlimit_name(resource), lim.rlim_cur, lim.rlim_max);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "ERROR: SETRLIMIT(%s, %,ld, %,ld) FAILED %m%n",
|
||||
__strace_rlimit_name(resource), soft, hard);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, rc;
|
||||
struct rlimit rlim;
|
||||
|
||||
// // example of how you might change the limits
|
||||
// SetLimit(RLIMIT_CPU, 3, 33);
|
||||
// SetLimit(RLIMIT_NPROC, 4, 128);
|
||||
// SetLimit(RLIMIT_NOFILE, 32, 128);
|
||||
// SetLimit(RLIMIT_SIGPENDING, 16, 1024);
|
||||
// SetLimit(RLIMIT_AS, 8 * 1024 * 1024, 1l * 1024 * 1024 * 1024);
|
||||
// SetLimit(RLIMIT_RSS, 8 * 1024 * 1024, 1l * 1024 * 1024 * 1024);
|
||||
// SetLimit(RLIMIT_DATA, 8 * 1024 * 1024, 1l * 1024 * 1024 * 1024);
|
||||
// SetLimit(RLIMIT_FSIZE, 8 * 1000 * 1000, 1l * 1000 * 1000 * 1000);
|
||||
|
||||
for (i = 0; i < RLIM_NLIMITS; ++i) {
|
||||
rc = getrlimit(i, &rlim);
|
||||
printf("SETRLIMIT(%-20s, %,16ld, %,16ld) → %d %s\n",
|
||||
__strace_rlimit_name(i), rlim.rlim_cur, rlim.rlim_max, rc,
|
||||
!rc ? "" : strerror(errno));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -101,7 +101,7 @@ int main(int argc, char *argv[]) {
|
|||
sigaddset(&chldmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||
ts1 = nowl();
|
||||
CHECK_NE(-1, (pid = vfork()));
|
||||
CHECK_NE(-1, (pid = fork()));
|
||||
if (!pid) {
|
||||
sigaction(SIGINT, &dflt, 0);
|
||||
sigaction(SIGQUIT, &dflt, 0);
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Prints sequence of numbers.
|
||||
|
@ -16,6 +17,7 @@
|
|||
|
||||
int main(int argc, char *argv[]) {
|
||||
long a, b, i;
|
||||
char buf[21], *p;
|
||||
switch (argc) {
|
||||
case 2:
|
||||
a = 1;
|
||||
|
@ -29,6 +31,9 @@ int main(int argc, char *argv[]) {
|
|||
return 1;
|
||||
}
|
||||
for (i = a; i <= b; ++i) {
|
||||
printf("%ld\n", i);
|
||||
p = buf;
|
||||
p = FormatInt64(p, i);
|
||||
*p++ = '\n';
|
||||
write(1, buf, p - buf);
|
||||
}
|
||||
}
|
||||
|
|
72
examples/setitimer.c
Normal file
72
examples/setitimer.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
#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/struct/itimerval.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/itimer.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
volatile bool gotalrm;
|
||||
|
||||
void OnSigAlrm(int sig, siginfo_t *si, ucontext_t *ctx) {
|
||||
gotalrm = true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
printf("first tutorial: set singleshot alarm for 1.5 seconds from now\n");
|
||||
|
||||
// setup alarm in 1.5 seconds
|
||||
// this timer tears itself down once it's handled
|
||||
struct itimerval shot = {{0, 0}, {1, 500000}};
|
||||
struct sigaction handler = {.sa_sigaction = OnSigAlrm,
|
||||
.sa_flags = SA_RESETHAND | SA_SIGINFO};
|
||||
CHECK_EQ(0, sigaction(SIGALRM, &handler, 0));
|
||||
CHECK_EQ(0, setitimer(ITIMER_REAL, &shot, 0));
|
||||
|
||||
// wait for alarm
|
||||
pause();
|
||||
printf("got singleshot alarm!\n\n");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
printf("second tutorial: interval timer\n");
|
||||
|
||||
// setup timer every 1.5 seconds
|
||||
struct sigaction oldalrm;
|
||||
struct sigaction sigalrm = {.sa_sigaction = OnSigAlrm,
|
||||
.sa_flags = SA_SIGINFO};
|
||||
CHECK_EQ(0, sigaction(SIGALRM, &sigalrm, &oldalrm));
|
||||
struct itimerval oldtimer;
|
||||
struct itimerval timer = {{1, 500000}, {1, 500000}};
|
||||
CHECK_EQ(0, setitimer(ITIMER_REAL, &timer, &oldtimer));
|
||||
|
||||
// wait for three timeouts
|
||||
int i = 0;
|
||||
int n = 3;
|
||||
while (i < n) {
|
||||
pause();
|
||||
if (gotalrm) {
|
||||
++i;
|
||||
printf("got timeout %d out of %d\n", i, n);
|
||||
gotalrm = false;
|
||||
}
|
||||
}
|
||||
|
||||
// teardown timer
|
||||
CHECK_EQ(0, setitimer(ITIMER_REAL, &oldtimer, 0));
|
||||
CHECK_EQ(0, sigaction(SIGALRM, &oldalrm, 0));
|
||||
}
|
|
@ -47,8 +47,8 @@ void PrintMetric(const char *name, long double d) {
|
|||
mils = fmodl(d * 1000, 1000);
|
||||
mics = fmodl(d * 1000000, 1000);
|
||||
p = stpcpy(p, name), *p++ = '\t';
|
||||
p += int64toarray_radix10(mins, p), *p++ = 'm';
|
||||
p += int64toarray_radix10(secs, p), *p++ = '.';
|
||||
p = FormatInt64(p, mins), *p++ = 'm';
|
||||
p = FormatInt64(p, secs), *p++ = '.';
|
||||
*p++ = '0' + mils / 100;
|
||||
*p++ = '0' + mils / 10 % 10;
|
||||
*p++ = '0' + mils % 10;
|
||||
|
@ -69,7 +69,7 @@ int main(int argc, char *argv[]) {
|
|||
long double real;
|
||||
char exebuf[PATH_MAX];
|
||||
if (argc >= 2) {
|
||||
if ((exepath = commandv(argv[1], exebuf))) {
|
||||
if ((exepath = commandv(argv[1], exebuf, sizeof(exebuf)))) {
|
||||
real = nowl();
|
||||
argv[1] = exepath;
|
||||
if ((ws = xvspawn(OnChild, argv + 1, &r)) != -1) {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (touch(argv[i], 0644) == -1) {
|
||||
if (touch(argv[i], 0666) == -1) {
|
||||
fprintf(stderr, "ERROR: %s: %s\n", argv[i], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "libc/x/x.h"
|
||||
|
||||
#define CTRL(C) ((C) ^ 0b01000000)
|
||||
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
|
||||
#define ENABLE_SAFE_PASTE "\e[?2004h"
|
||||
#define ENABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006h"
|
||||
#define DISABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006l"
|
||||
|
@ -46,7 +47,7 @@ void onkilled(int sig) {
|
|||
}
|
||||
|
||||
void restoretty(void) {
|
||||
write(1, DISABLE_MOUSE_TRACKING, strlen(DISABLE_MOUSE_TRACKING));
|
||||
WRITE(1, DISABLE_MOUSE_TRACKING);
|
||||
ioctl(1, TCSETS, &oldterm);
|
||||
}
|
||||
|
||||
|
@ -72,9 +73,9 @@ int rawmode(void) {
|
|||
t.c_cflag |= CS8;
|
||||
t.c_iflag |= IUTF8;
|
||||
ioctl(1, TCSETS, &t);
|
||||
write(1, ENABLE_SAFE_PASTE, strlen(ENABLE_SAFE_PASTE));
|
||||
write(1, ENABLE_MOUSE_TRACKING, strlen(ENABLE_MOUSE_TRACKING));
|
||||
write(1, PROBE_DISPLAY_SIZE, strlen(PROBE_DISPLAY_SIZE));
|
||||
WRITE(1, ENABLE_SAFE_PASTE);
|
||||
WRITE(1, ENABLE_MOUSE_TRACKING);
|
||||
WRITE(1, PROBE_DISPLAY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,12 +16,22 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
|
||||
/**
|
||||
* @fileoverview How to change CPU state on signal delivery
|
||||
*
|
||||
* This program redefines division by zero so that it has a definition.
|
||||
* The definition is the meaning of life, the universe, and everything.
|
||||
* Normally crash signals like `SIGSEGV`, `SIGILL`, and `SIGFPE` aren't
|
||||
* recoverable. This example shows how it actually can be done with Xed
|
||||
* and this example should work on all supported platforms even Windows
|
||||
*/
|
||||
|
||||
void handler(int sig, siginfo_t *si, ucontext_t *ctx) {
|
||||
struct XedDecodedInst xedd;
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
||||
xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15);
|
||||
ctx->uc_mcontext.rip += xedd.length;
|
||||
ctx->uc_mcontext.rax = 42;
|
||||
ctx->uc_mcontext.rax = 42; // set the DIV result registers rdx:rax
|
||||
ctx->uc_mcontext.rdx = 0;
|
||||
}
|
||||
|
||||
|
|
24
examples/uname.c
Normal file
24
examples/uname.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
#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/struct/utsname.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct utsname names;
|
||||
if (uname(&names)) return 1;
|
||||
printf("%-10s %s\n", "sysname", names.sysname);
|
||||
printf("%-10s %s\n", "nodename", names.nodename);
|
||||
printf("%-10s %s\n", "release", names.release);
|
||||
printf("%-10s %s\n", "version", names.version);
|
||||
printf("%-10s %s\n", "machine", names.machine);
|
||||
printf("%-10s %s\n", "domainname", names.domainname);
|
||||
return 0;
|
||||
}
|
|
@ -5731,7 +5731,7 @@ retry:
|
|||
linenoiseSetFreeHintsCallback(free);
|
||||
linenoiseSetHintsCallback(ShellHint);
|
||||
linenoiseSetCompletionCallback(ShellCompletion);
|
||||
if ((p = linenoiseWithHistory("$ ", "unbourne"))) {
|
||||
if ((p = linenoiseWithHistory(">: ", "unbourne"))) {
|
||||
nr = min(strlen(p), IBUFSIZ - 2);
|
||||
memcpy(buf, p, nr);
|
||||
buf[nr++] = '\n';
|
||||
|
|
|
@ -55,8 +55,8 @@ int fgethex(FILE *f) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[argc]) {
|
||||
int err;
|
||||
unsigned c, i, j, l;
|
||||
enum XedError err;
|
||||
struct XedDecodedInst xedd;
|
||||
unsigned char buf[XED_MAX_INSTRUCTION_BYTES];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
|
|
@ -8,10 +8,10 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
void *bsearch(const void *, const void *, size_t, size_t,
|
||||
int cmp(const void *, const void *))
|
||||
paramsnonnull() nothrow nosideeffect;
|
||||
paramsnonnull() dontthrow nosideeffect;
|
||||
void *bsearch_r(const void *, const void *, size_t, size_t,
|
||||
int cmp(const void *, const void *, void *), void *)
|
||||
paramsnonnull((1, 2, 5)) nothrow nosideeffect;
|
||||
paramsnonnull((1, 2, 5)) dontthrow nosideeffect;
|
||||
void djbsort(int32_t *, size_t);
|
||||
void qsort(void *, size_t, size_t, int (*)(const void *, const void *))
|
||||
paramsnonnull();
|
||||
|
@ -19,9 +19,9 @@ void qsort_r(void *, size_t, size_t,
|
|||
int cmp(const void *, const void *, void *), void *arg)
|
||||
paramsnonnull((1, 4));
|
||||
int tarjan(int, const int (*)[2], int, int[], int[], int *)
|
||||
paramsnonnull((2, 4)) nocallback nothrow;
|
||||
paramsnonnull((2, 4)) nocallback dontthrow;
|
||||
|
||||
#define __algalloc returnspointerwithnoaliases nothrow nocallback nodiscard
|
||||
#define __algalloc returnspointerwithnoaliases dontthrow nocallback dontdiscard
|
||||
|
||||
char *replacestr(const char *, const char *, const char *)
|
||||
paramsnonnull() __algalloc;
|
||||
|
|
|
@ -14,7 +14,7 @@ forceinline void *bisect(const void *k, const void *data, size_t n, size_t size,
|
|||
r = n - 1;
|
||||
p = data;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
m = (l & r) + ((l ^ r) >> 1);
|
||||
c = cmp(k, p + m * size, arg);
|
||||
if (c > 0) {
|
||||
l = m + 1;
|
||||
|
|
|
@ -11,15 +11,15 @@ struct critbit0 {
|
|||
size_t count;
|
||||
};
|
||||
|
||||
bool critbit0_contains(struct critbit0 *, const char *) nothrow nosideeffect
|
||||
bool critbit0_contains(struct critbit0 *, const char *) dontthrow nosideeffect
|
||||
paramsnonnull();
|
||||
bool critbit0_insert(struct critbit0 *, const char *) paramsnonnull();
|
||||
bool critbit0_delete(struct critbit0 *, const char *) nothrow paramsnonnull();
|
||||
void critbit0_clear(struct critbit0 *) nothrow paramsnonnull();
|
||||
bool critbit0_delete(struct critbit0 *, const char *) dontthrow paramsnonnull();
|
||||
void critbit0_clear(struct critbit0 *) dontthrow paramsnonnull();
|
||||
char *critbit0_get(struct critbit0 *, const char *);
|
||||
intptr_t critbit0_allprefixed(struct critbit0 *, const char *,
|
||||
intptr_t (*)(const char *, void *), void *)
|
||||
paramsnonnull((1, 2, 3)) nothrow;
|
||||
paramsnonnull((1, 2, 3)) dontthrow;
|
||||
bool critbit0_emplace(struct critbit0 *, char *, size_t) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -12,7 +12,9 @@ void __assert_fail(const char *, const char *, int) hidden wontreturn relegated;
|
|||
((void)((EXPR) || (__assert_fail(#EXPR, __FILE__, __LINE__), 0)))
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define static_assert _Static_assert
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
34
libc/bits/asmflag.h
Normal file
34
libc/bits/asmflag.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/*
|
||||
* Constraints for virtual machine flags.
|
||||
* @note we beseech clang devs for flag constraints
|
||||
*/
|
||||
#ifdef __GCC_ASM_FLAG_OUTPUTS__ /* GCC6+ CLANG10+ */
|
||||
#define CFLAG_CONSTRAINT "=@ccc"
|
||||
#define CFLAG_ASM(OP) OP
|
||||
#define ZFLAG_CONSTRAINT "=@ccz"
|
||||
#define ZFLAG_ASM(OP) OP
|
||||
#define OFLAG_CONSTRAINT "=@cco"
|
||||
#define OFLAG_ASM(OP) OP
|
||||
#define SFLAG_CONSTRAINT "=@ccs"
|
||||
#define SFLAG_ASM(SP) SP
|
||||
#define ABOVE_CONSTRAINT "=@cca" /* i.e. !ZF && !CF */
|
||||
#define ABOVEFLAG_ASM(OP) OP
|
||||
#else
|
||||
#define CFLAG_CONSTRAINT "=q"
|
||||
#define CFLAG_ASM(OP) OP "\n\tsetc\t%b0"
|
||||
#define ZFLAG_CONSTRAINT "=q"
|
||||
#define ZFLAG_ASM(OP) OP "\n\tsetz\t%b0"
|
||||
#define OFLAG_CONSTRAINT "=q"
|
||||
#define OFLAG_ASM(OP) OP "\n\tseto\t%b0"
|
||||
#define SFLAG_CONSTRAINT "=q"
|
||||
#define SFLAG_ASM(SP) OP "\n\tsets\t%b0"
|
||||
#define ABOVE_CONSTRAINT "=@cca"
|
||||
#define ABOVEFLAG_ASM(OP) OP "\n\tseta\t%b0"
|
||||
#endif
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_ASMFLAG_H_ */
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
|
@ -31,8 +32,8 @@ COSMOPOLITAN_C_START_
|
|||
})
|
||||
#define atomic_init(PTR, VAL) atomic_store(PTR, VAL)
|
||||
#define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL))
|
||||
#define atomic_compare_exchange_strong(X, Y, Z) lockcmpxchg(X, Y, Z)
|
||||
#define atomic_compare_exchange_weak(X, Y, Z) lockcmpxchg(X, Y, Z)
|
||||
#define atomic_compare_exchange_strong(X, Y, Z) _lockcmpxchg(X, Y, Z)
|
||||
#define atomic_compare_exchange_weak(X, Y, Z) _lockcmpxchg(X, Y, Z)
|
||||
#define atomic_load_explicit(PTR, ORDER) atomic_load(PTR)
|
||||
#define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL)
|
||||
#define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0)
|
||||
|
|
45
libc/bits/bitop.h
Normal file
45
libc/bits/bitop.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_BITOP_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_BITOP_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define bts(MEM, BIT) __BitOp("bts", BIT, MEM) /** bit test and set */
|
||||
#define btr(MEM, BIT) __BitOp("btr", BIT, MEM) /** bit test and reset */
|
||||
#define btc(MEM, BIT) __BitOp("btc", BIT, MEM) /** bit test and complement */
|
||||
#define lockbts(MEM, BIT) __BitOp("lock bts", BIT, MEM)
|
||||
#define lockbtr(MEM, BIT) __BitOp("lock btr", BIT, MEM)
|
||||
#define lockbtc(MEM, BIT) __BitOp("lock btc", BIT, MEM)
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define __BitOp(OP, BIT, MEM) \
|
||||
({ \
|
||||
bool OldBit; \
|
||||
if (__builtin_constant_p(BIT)) { \
|
||||
asm(CFLAG_ASM(OP "%z1\t%2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), \
|
||||
"+m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]) \
|
||||
: "J"((BIT) % (sizeof((MEM)[0]) * CHAR_BIT)) \
|
||||
: "cc"); \
|
||||
} else if (sizeof((MEM)[0]) == 2) { \
|
||||
asm(CFLAG_ASM(OP "\t%w2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||
: "r"(BIT) \
|
||||
: "cc"); \
|
||||
} else if (sizeof((MEM)[0]) == 4) { \
|
||||
asm(CFLAG_ASM(OP "\t%k2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||
: "r"(BIT) \
|
||||
: "cc"); \
|
||||
} else if (sizeof((MEM)[0]) == 8) { \
|
||||
asm(CFLAG_ASM(OP "\t%q2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||
: "r"(BIT) \
|
||||
: "cc"); \
|
||||
} \
|
||||
OldBit; \
|
||||
})
|
||||
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_BITOP_H_ */
|
181
libc/bits/bits.h
181
libc/bits/bits.h
|
@ -21,11 +21,6 @@ unsigned long roundup2pow(unsigned long) libcesque pureconst;
|
|||
unsigned long roundup2log(unsigned long) libcesque pureconst;
|
||||
unsigned long rounddown2pow(unsigned long) libcesque pureconst;
|
||||
unsigned long hamming(unsigned long, unsigned long) pureconst;
|
||||
intptr_t lockxchg(void *, void *, size_t);
|
||||
bool cmpxchg(void *, intptr_t, intptr_t, size_t);
|
||||
bool lockcmpxchg(void *, intptr_t, intptr_t, size_t);
|
||||
intptr_t atomic_load(void *, size_t);
|
||||
intptr_t atomic_store(void *, intptr_t, size_t);
|
||||
unsigned bextra(const unsigned *, size_t, char);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
|
@ -136,84 +131,6 @@ unsigned bextra(const unsigned *, size_t, char);
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
||||
/*
|
||||
* Constraints for virtual machine flags.
|
||||
* @note we beseech clang devs for flag constraints
|
||||
*/
|
||||
#ifdef __GCC_ASM_FLAG_OUTPUTS__ /* GCC6+ CLANG10+ */
|
||||
#define CFLAG_CONSTRAINT "=@ccc"
|
||||
#define CFLAG_ASM(OP) OP
|
||||
#define ZFLAG_CONSTRAINT "=@ccz"
|
||||
#define ZFLAG_ASM(OP) OP
|
||||
#define OFLAG_CONSTRAINT "=@cco"
|
||||
#define OFLAG_ASM(OP) OP
|
||||
#define SFLAG_CONSTRAINT "=@ccs"
|
||||
#define SFLAG_ASM(SP) SP
|
||||
#define ABOVE_CONSTRAINT "=@cca" /* i.e. !ZF && !CF */
|
||||
#define ABOVEFLAG_ASM(OP) OP
|
||||
#else
|
||||
#define CFLAG_CONSTRAINT "=q"
|
||||
#define CFLAG_ASM(OP) OP "\n\tsetc\t%b0"
|
||||
#define ZFLAG_CONSTRAINT "=q"
|
||||
#define ZFLAG_ASM(OP) OP "\n\tsetz\t%b0"
|
||||
#define OFLAG_CONSTRAINT "=q"
|
||||
#define OFLAG_ASM(OP) OP "\n\tseto\t%b0"
|
||||
#define SFLAG_CONSTRAINT "=q"
|
||||
#define SFLAG_ASM(SP) OP "\n\tsets\t%b0"
|
||||
#define ABOVE_CONSTRAINT "=@cca"
|
||||
#define ABOVEFLAG_ASM(OP) OP "\n\tseta\t%b0"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Reads scalar from memory w/ one operation.
|
||||
*
|
||||
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @return *(MEM)
|
||||
* @note defeats compiler load tearing optimizations
|
||||
* @note alignas(𝑘) is implied if compiler knows type
|
||||
* @note alignas(𝑘) only avoids multi-core / cross-page edge cases
|
||||
* @see Intel's Six-Thousand Page Manual V.3A §8.2.3.1
|
||||
* @see atomic_store()
|
||||
*/
|
||||
#define atomic_load(MEM) \
|
||||
({ \
|
||||
autotype(MEM) Mem = (MEM); \
|
||||
typeof(*Mem) Reg; \
|
||||
asm("mov\t%1,%0" : "=r"(Reg) : "m"(*Mem)); \
|
||||
Reg; \
|
||||
})
|
||||
|
||||
/**
|
||||
* Saves scalar to memory w/ one operation.
|
||||
*
|
||||
* This is guaranteed to happen in either one or zero operations,
|
||||
* depending on whether or not it's possible for *(MEM) to be read
|
||||
* afterwards. This macro only forbids compiler from using >1 ops.
|
||||
*
|
||||
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param VAL is uint𝑘_t w/ better encoding for immediates (constexpr)
|
||||
* @return VAL
|
||||
* @note alignas(𝑘) on nexgen32e only needed for end of page gotcha
|
||||
* @note alignas(𝑘) is implied if compiler knows type
|
||||
* @note needed to defeat store tearing optimizations
|
||||
* @see Intel Six-Thousand Page Manual Manual V.3A §8.2.3.1
|
||||
* @see atomic_load()
|
||||
*/
|
||||
#define atomic_store(MEM, VAL) \
|
||||
({ \
|
||||
autotype(VAL) Val = (VAL); \
|
||||
typeof(&Val) Mem = (MEM); \
|
||||
asm("mov%z1\t%1,%0" : "=m"(*Mem) : "r"(Val)); \
|
||||
Val; \
|
||||
})
|
||||
|
||||
#define bts(MEM, BIT) __BitOp("bts", BIT, MEM) /** bit test and set */
|
||||
#define btr(MEM, BIT) __BitOp("btr", BIT, MEM) /** bit test and reset */
|
||||
#define btc(MEM, BIT) __BitOp("btc", BIT, MEM) /** bit test and complement */
|
||||
#define lockbts(MEM, BIT) __BitOp("lock bts", BIT, MEM)
|
||||
#define lockbtr(MEM, BIT) __BitOp("lock btr", BIT, MEM)
|
||||
#define lockbtc(MEM, BIT) __BitOp("lock btc", BIT, MEM)
|
||||
|
||||
#define lockinc(MEM) __ArithmeticOp1("lock inc", MEM)
|
||||
#define lockdec(MEM) __ArithmeticOp1("lock dec", MEM)
|
||||
#define locknot(MEM) __ArithmeticOp1("lock not", MEM)
|
||||
|
@ -225,66 +142,6 @@ unsigned bextra(const unsigned *, size_t, char);
|
|||
#define lockandeq(MEM, VAL) __ArithmeticOp2("lock and", VAL, MEM)
|
||||
#define lockoreq(MEM, VAL) __ArithmeticOp2("lock or", VAL, MEM)
|
||||
|
||||
/**
|
||||
* Exchanges *MEMORY into *LOCALVAR w/ one operation.
|
||||
*
|
||||
* @param MEMORY is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param LOCALVAR is uint𝑘_t[hasatleast 1]
|
||||
* @return LOCALVAR[0]
|
||||
* @see xchg()
|
||||
*/
|
||||
#define lockxchg(MEMORY, LOCALVAR) \
|
||||
({ \
|
||||
asm("xchg\t%0,%1" : "+%m"(*(MEMORY)), "+r"(*(LOCALVAR))); \
|
||||
*(LOCALVAR); \
|
||||
})
|
||||
|
||||
/**
|
||||
* Compares and exchanges.
|
||||
*
|
||||
* @param IFTHING is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @return true if value was exchanged, otherwise false
|
||||
* @see lockcmpxchg()
|
||||
*/
|
||||
#define cmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
autotype(IFTHING) IfThing = (IFTHING); \
|
||||
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
|
||||
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
|
||||
asm volatile(ZFLAG_ASM("cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
|
||||
: "r"(ReplaceItWithMe) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
})
|
||||
|
||||
/**
|
||||
* Compares and exchanges w/ one operation.
|
||||
*
|
||||
* @param IFTHING is uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @return true if value was exchanged, otherwise false
|
||||
* @see lockcmpxchg()
|
||||
*/
|
||||
#define lockcmpxchg(IFTHING, ISEQUALTOME, REPLACEITWITHME) \
|
||||
({ \
|
||||
bool DidIt; \
|
||||
autotype(IFTHING) IfThing = (IFTHING); \
|
||||
typeof(*IfThing) IsEqualToMe = (ISEQUALTOME); \
|
||||
typeof(*IfThing) ReplaceItWithMe = (REPLACEITWITHME); \
|
||||
asm volatile(ZFLAG_ASM("lock cmpxchg\t%3,%1") \
|
||||
: ZFLAG_CONSTRAINT(DidIt), "+m"(*IfThing), "+a"(IsEqualToMe) \
|
||||
: "r"(ReplaceItWithMe) \
|
||||
: "cc"); \
|
||||
DidIt; \
|
||||
})
|
||||
|
||||
#define IsAddressCanonicalForm(P) \
|
||||
({ \
|
||||
intptr_t p2 = (intptr_t)(P); \
|
||||
(0xffff800000000000l <= p2 && p2 <= 0x00007fffffffffffl); \
|
||||
})
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § bits » implementation details ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
@ -301,44 +158,6 @@ unsigned bextra(const unsigned *, size_t, char);
|
|||
MEM; \
|
||||
})
|
||||
|
||||
#define __BitOp(OP, BIT, MEM) \
|
||||
({ \
|
||||
bool OldBit; \
|
||||
if (__builtin_constant_p(BIT)) { \
|
||||
asm(CFLAG_ASM(OP "%z1\t%2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), \
|
||||
"+m"((MEM)[(BIT) / (sizeof((MEM)[0]) * CHAR_BIT)]) \
|
||||
: "J"((BIT) % (sizeof((MEM)[0]) * CHAR_BIT)) \
|
||||
: "cc"); \
|
||||
} else if (sizeof((MEM)[0]) == 2) { \
|
||||
asm(CFLAG_ASM(OP "\t%w2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||
: "r"(BIT) \
|
||||
: "cc"); \
|
||||
} else if (sizeof((MEM)[0]) == 4) { \
|
||||
asm(CFLAG_ASM(OP "\t%k2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||
: "r"(BIT) \
|
||||
: "cc"); \
|
||||
} else if (sizeof((MEM)[0]) == 8) { \
|
||||
asm(CFLAG_ASM(OP "\t%q2,%1") \
|
||||
: CFLAG_CONSTRAINT(OldBit), "+m"((MEM)[0]) \
|
||||
: "r"(BIT) \
|
||||
: "cc"); \
|
||||
} \
|
||||
OldBit; \
|
||||
})
|
||||
|
||||
#else
|
||||
#define cmpxchg(MEM, CMP, VAL) \
|
||||
cmpxchg(MEM, (intptr_t)(CMP), (intptr_t)(VAL), sizeof(*(MEM)))
|
||||
#define lockcmpxchg(MEM, CMP, VAL) \
|
||||
lockcmpxchg(MEM, (intptr_t)(CMP), (intptr_t)(VAL), sizeof(*(MEM)))
|
||||
#define lockxchg(MEM, VAR) \
|
||||
lockxchg(MEM, VAR, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAR))))
|
||||
#define atomic_store(MEM, VAL) \
|
||||
atomic_store(MEM, VAL, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAL))))
|
||||
#define atomic_load(MEM) atomic_load(MEM, sizeof(*(MEM)))
|
||||
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
32
libc/bits/midpoint.h
Normal file
32
libc/bits/midpoint.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_
|
||||
#include "libc/assert.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && defined(__x86__)
|
||||
/**
|
||||
* Computes `(a + b) / 2` assuming unsigned.
|
||||
*
|
||||
* This implementation is the fastest on AMD Zen architecture.
|
||||
*/
|
||||
#define _midpoint(a, b) \
|
||||
({ \
|
||||
typeof((a) + (b)) a_ = (a); \
|
||||
typeof(a_) b_ = (b); \
|
||||
assert(a_ >= 0); \
|
||||
assert(b_ >= 0); \
|
||||
asm("add\t%1,%0\n\t" \
|
||||
"rcr\t%0" \
|
||||
: "+r"(a_) \
|
||||
: "r"(b_)); \
|
||||
a_; \
|
||||
})
|
||||
#else
|
||||
/**
|
||||
* Computes `(a + b) / 2` assuming unsigned.
|
||||
*/
|
||||
#define _midpoint(a, b) (((a) & (b)) + ((a) ^ (b)) / 2)
|
||||
#endif /* __GNUC__ && !__STRICT_ANSI__ && x86 */
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_MIDPOINT_H_ */
|
|
@ -19,7 +19,7 @@
|
|||
#include "libc/calls/math.h"
|
||||
|
||||
/**
|
||||
* Adds two microsecond timestamps.
|
||||
* Adds two nanosecond timestamps.
|
||||
*/
|
||||
struct timespec AddTimespec(struct timespec x, struct timespec y) {
|
||||
x.tv_sec += y.tv_sec;
|
||||
|
|
|
@ -16,7 +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/intrin/cmpxchg.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -41,7 +41,7 @@ int atfork(void *fn, void *arg) {
|
|||
for (;;) {
|
||||
i = g_atfork.i;
|
||||
if (i == ARRAYLEN(g_atfork.p)) return enomem();
|
||||
if (cmpxchg(&g_atfork.i, i, i + 1)) {
|
||||
if (_cmpxchg(&g_atfork.i, i, i + 1)) {
|
||||
g_atfork.p[i] = (struct AtForkCallback){.fn = fn, .arg = arg};
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
#include "libc/sysv/consts/s.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
#define _POSIX_VERSION 200809L
|
||||
#define _POSIX2_VERSION _POSIX_VERSION
|
||||
#define _XOPEN_VERSION 700
|
||||
|
||||
#define EOF -1 /* end of file */
|
||||
#define WEOF -1u /* end of file (multibyte) */
|
||||
#define _IOFBF 0 /* fully buffered */
|
||||
|
@ -48,14 +52,14 @@
|
|||
#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK)
|
||||
#define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK)
|
||||
|
||||
#define WCOREDUMP(s) ((s)&0x80)
|
||||
#define WEXITSTATUS(s) (((s)&0xff00) >> 8)
|
||||
#define WCOREDUMP(s) (0x80 & (s))
|
||||
#define WEXITSTATUS(s) ((0xff00 & (s)) >> 8)
|
||||
#define WIFCONTINUED(s) ((s) == 0xffff)
|
||||
#define WIFEXITED(s) (!WTERMSIG(s))
|
||||
#define WIFSIGNALED(s) (((s)&0xffff) - 1u < 0xffu)
|
||||
#define WIFSTOPPED(s) ((short)((((s)&0xffff) * 0x10001) >> 8) > 0x7f00)
|
||||
#define WIFSIGNALED(s) ((0xffff & (s)) - 1u < 0xffu)
|
||||
#define WIFSTOPPED(s) ((short)(((0xffff & (s)) * 0x10001) >> 8) > 0x7f00)
|
||||
#define WSTOPSIG(s) WEXITSTATUS(s)
|
||||
#define WTERMSIG(s) ((s)&0x7f)
|
||||
#define WTERMSIG(s) (127 & (s))
|
||||
#define W_STOPCODE(s) ((s) << 8 | 0177)
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
@ -66,8 +70,8 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
typedef int sig_atomic_t;
|
||||
|
||||
DIR *fdopendir(int) nodiscard;
|
||||
DIR *opendir(const char *) nodiscard;
|
||||
DIR *fdopendir(int) dontdiscard;
|
||||
DIR *opendir(const char *) dontdiscard;
|
||||
bool fileexists(const char *);
|
||||
bool isdirectory(const char *);
|
||||
bool isexecutable(const char *);
|
||||
|
@ -75,19 +79,18 @@ bool isregularfile(const char *);
|
|||
bool issymlink(const char *);
|
||||
bool32 isatty(int) nosideeffect;
|
||||
bool32 ischardev(int) nosideeffect;
|
||||
char *commandv(const char *, char[hasatleast PATH_MAX]);
|
||||
char *get_current_dir_name(void) nodiscard;
|
||||
char *commandv(const char *, char *, size_t);
|
||||
char *get_current_dir_name(void) dontdiscard;
|
||||
char *getcwd(char *, size_t);
|
||||
char *realpath(const char *, char *);
|
||||
char *replaceuser(const char *) nodiscard;
|
||||
char *replaceuser(const char *) dontdiscard;
|
||||
char *ttyname(int);
|
||||
int access(const char *, int) nothrow;
|
||||
int access(const char *, int) dontthrow;
|
||||
int arch_prctl();
|
||||
int chdir(const char *);
|
||||
int chmod(const char *, uint32_t);
|
||||
int chown(const char *, uint32_t, uint32_t);
|
||||
int chroot(const char *);
|
||||
int clone(int (*)(void *), void *, int, void *, ...);
|
||||
int close(int);
|
||||
int closedir(DIR *);
|
||||
int creat(const char *, uint32_t);
|
||||
|
@ -105,7 +108,7 @@ int execvpe(const char *, char *const[], char *const[]);
|
|||
int faccessat(int, const char *, int, uint32_t);
|
||||
int fadvise(int, uint64_t, uint64_t, int);
|
||||
int fchdir(int);
|
||||
int fchmod(int, uint32_t) nothrow;
|
||||
int fchmod(int, uint32_t) dontthrow;
|
||||
int fchmodat(int, const char *, uint32_t, int);
|
||||
int fchown(int, uint32_t, uint32_t);
|
||||
int fchownat(int, const char *, uint32_t, uint32_t, int);
|
||||
|
@ -120,16 +123,24 @@ int fsync(int);
|
|||
int ftruncate(int, int64_t);
|
||||
int getdents(unsigned, void *, unsigned, long *);
|
||||
int getdomainname(char *, size_t);
|
||||
int getegid(void) nosideeffect;
|
||||
int geteuid(void) nosideeffect;
|
||||
int getgid(void) nosideeffect;
|
||||
int gethostname(char *, size_t);
|
||||
int getloadavg(double *, int);
|
||||
int getpgid(int);
|
||||
int getpgrp(void) nosideeffect;
|
||||
int getpid(void);
|
||||
int getppid(void);
|
||||
int getpriority(int, unsigned);
|
||||
int getrlimit(int, struct rlimit *);
|
||||
int getrusage(int, struct rusage *);
|
||||
int getsid(int) nosideeffect;
|
||||
int gettid(void);
|
||||
int getuid(void) nosideeffect;
|
||||
int kill(int, int);
|
||||
int killpg(int, int);
|
||||
int link(const char *, const char *) nothrow;
|
||||
int link(const char *, const char *) dontthrow;
|
||||
int linkat(int, const char *, int, const char *, int);
|
||||
int lstat(const char *, struct stat *);
|
||||
int lutimes(const char *, const struct timeval[2]);
|
||||
|
@ -147,7 +158,6 @@ int munlock(const void *, size_t);
|
|||
int munlockall(void);
|
||||
int nice(int);
|
||||
int open(const char *, int, ...);
|
||||
int openanon(char *, unsigned);
|
||||
int openat(int, const char *, int, ...);
|
||||
int pause(void);
|
||||
int personality(uint64_t);
|
||||
|
@ -155,7 +165,7 @@ int pipe(int[hasatleast 2]);
|
|||
int pipe2(int[hasatleast 2], int);
|
||||
int posix_fadvise(int, uint64_t, uint64_t, int);
|
||||
int posix_madvise(void *, uint64_t, int);
|
||||
int prctl();
|
||||
int prctl(int, ...);
|
||||
int raise(int);
|
||||
int reboot(int);
|
||||
int remove(const char *);
|
||||
|
@ -166,18 +176,22 @@ int rmdir(const char *);
|
|||
int sched_getaffinity(int, uint64_t, void *);
|
||||
int sched_setaffinity(int, uint64_t, const void *);
|
||||
int sched_yield(void);
|
||||
int seccomp(unsigned, unsigned, void *);
|
||||
int setegid(uint32_t);
|
||||
int seteuid(uint32_t);
|
||||
int setgid(uint32_t);
|
||||
int setgid(int);
|
||||
int setpgid(int, int);
|
||||
int setpgrp(void);
|
||||
int setpriority(int, unsigned, int);
|
||||
int setregid(uint32_t, uint32_t);
|
||||
int setresgid(uint32_t, uint32_t, uint32_t);
|
||||
int setresuid(uint32_t, uint32_t, uint32_t);
|
||||
int getresgid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int getresuid(uint32_t *, uint32_t *, uint32_t *);
|
||||
int setreuid(uint32_t, uint32_t);
|
||||
int setrlimit(int, const struct rlimit *);
|
||||
int setsid(void);
|
||||
int setuid(uint32_t);
|
||||
int setuid(int);
|
||||
int sigignore(int);
|
||||
int siginterrupt(int, int);
|
||||
int sigprocmask(int, const struct sigset *, struct sigset *);
|
||||
|
@ -192,6 +206,7 @@ int sysinfo(struct sysinfo *);
|
|||
int touch(const char *, uint32_t);
|
||||
int truncate(const char *, uint64_t);
|
||||
int ttyname_r(int, char *, size_t);
|
||||
int umask(int);
|
||||
int uname(struct utsname *);
|
||||
int unlink(const char *);
|
||||
int unlink_s(const char **);
|
||||
|
@ -202,13 +217,13 @@ int wait3(int *, int, struct rusage *);
|
|||
int wait4(int, int *, int, struct rusage *);
|
||||
int waitpid(int, int *, int);
|
||||
intptr_t syscall(int, ...);
|
||||
long ptrace(int, int, void *, void *);
|
||||
long ptrace(int, ...);
|
||||
long telldir(DIR *);
|
||||
long times(struct tms *);
|
||||
size_t GetFileSize(const char *);
|
||||
size_t getfiledescriptorsize(int);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
||||
ssize_t getfiledescriptorsize(int);
|
||||
ssize_t lseek(int, int64_t, unsigned);
|
||||
ssize_t pread(int, void *, size_t, int64_t);
|
||||
ssize_t preadv(int, struct iovec *, int, int64_t);
|
||||
|
@ -222,16 +237,12 @@ ssize_t splice(int, int64_t *, int, int64_t *, size_t, uint32_t);
|
|||
ssize_t vmsplice(int, const struct iovec *, int64_t, uint32_t);
|
||||
ssize_t write(int, const void *, size_t);
|
||||
struct dirent *readdir(DIR *);
|
||||
uint32_t getegid(void) nosideeffect;
|
||||
uint32_t geteuid(void) nosideeffect;
|
||||
uint32_t getgid(void) nosideeffect;
|
||||
uint32_t getpgrp(void) nosideeffect;
|
||||
uint32_t getsid(int) nosideeffect;
|
||||
uint32_t gettid(void) nosideeffect;
|
||||
uint32_t getuid(void) nosideeffect;
|
||||
uint32_t umask(int32_t);
|
||||
void rewinddir(DIR *);
|
||||
void sync(void);
|
||||
int pledge(const char *, const char *);
|
||||
|
||||
int clone(int (*)(void *), void *, size_t, int, void *, int *, void *, size_t,
|
||||
int *);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § system calls » formatting ─╬─│┼
|
||||
|
|
|
@ -44,7 +44,9 @@ LIBC_CALLS_A_DIRECTDEPS = \
|
|||
LIBC_NT_IPHLPAPI \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_NT_POWERPROF \
|
||||
LIBC_NT_PDH \
|
||||
LIBC_NT_PSAPI \
|
||||
LIBC_NT_POWRPROF \
|
||||
LIBC_NT_WS2_32 \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
|
@ -63,8 +65,12 @@ $(LIBC_CALLS_A).pkg: \
|
|||
$(LIBC_CALLS_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/libc/calls/vdsofunc.greg.o \
|
||||
o/$(MODE)/libc/calls/directmap.o \
|
||||
o/$(MODE)/libc/calls/directmap-nt.o \
|
||||
o/$(MODE)/libc/calls/raise.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffreestanding \
|
||||
$(NO_MAGIC)
|
||||
|
||||
o/$(MODE)/libc/calls/termios2linux.o \
|
||||
|
@ -78,6 +84,9 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: \
|
|||
-O3
|
||||
|
||||
# TODO(jart): make va_arg optimize well in default mode
|
||||
o//libc/calls/open.o \
|
||||
o//libc/calls/openat.o \
|
||||
o//libc/calls/prctl.o \
|
||||
o//libc/calls/ioctl.o \
|
||||
o//libc/calls/ioctl_default.o \
|
||||
o//libc/calls/ioctl_fioclex-nt.o \
|
||||
|
@ -96,11 +105,18 @@ o//libc/calls/fcntl.o: \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-Os
|
||||
|
||||
# must use alloca() or path_max*2*2
|
||||
o/$(MODE)/libc/calls/execl.o \
|
||||
o/$(MODE)/libc/calls/execle.o \
|
||||
o/$(MODE)/libc/calls/execlp.o \
|
||||
o/$(MODE)/libc/calls/copyfile.o \
|
||||
o/$(MODE)/libc/calls/execve-nt.o \
|
||||
o/$(MODE)/libc/calls/linkat-nt.o \
|
||||
o/$(MODE)/libc/calls/renameat-nt.o \
|
||||
o/$(MODE)/libc/calls/execve-sysv.o \
|
||||
o/$(MODE)/libc/calls/symlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/readlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/describeopenflags.greg.o \
|
||||
o/$(MODE)/libc/calls/mkntenvblock.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
|
@ -27,9 +28,10 @@
|
|||
|
||||
textwindows int sys_chdir_nt(const char *path) {
|
||||
uint32_t n;
|
||||
int e, ms, len;
|
||||
int e, ms, err, len;
|
||||
char16_t path16[PATH_MAX], var[4];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (!len) return enoent();
|
||||
if (len && path16[len - 1] != u'\\') {
|
||||
if (len + 2 > PATH_MAX) return enametoolong();
|
||||
path16[len + 0] = u'\\';
|
||||
|
@ -39,7 +41,7 @@ textwindows int sys_chdir_nt(const char *path) {
|
|||
* chdir() seems flaky on windows 7
|
||||
* in a similar way to rmdir() sigh
|
||||
*/
|
||||
for (ms = 1;; ms *= 2) {
|
||||
for (err = errno, ms = 1;; ms *= 2) {
|
||||
if (SetCurrentDirectory(path16)) {
|
||||
/*
|
||||
* Now we need to set a magic environment variable.
|
||||
|
@ -68,12 +70,12 @@ textwindows int sys_chdir_nt(const char *path) {
|
|||
if (ms <= 512 &&
|
||||
(e == kNtErrorFileNotFound || e == kNtErrorAccessDenied)) {
|
||||
Sleep(ms);
|
||||
errno = err;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
errno = e;
|
||||
return -1;
|
||||
return __fix_enotdir(-1, path16);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -30,10 +31,14 @@
|
|||
* @see fchdir()
|
||||
*/
|
||||
int chdir(const char *path) {
|
||||
if (IsAsan() && !__asan_is_valid(path, 1)) return efault();
|
||||
if (!IsWindows()) {
|
||||
return sys_chdir(path);
|
||||
int rc;
|
||||
if (!path || (IsAsan() && !__asan_is_valid(path, 1))) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_chdir(path);
|
||||
} else {
|
||||
return sys_chdir_nt(path);
|
||||
rc = sys_chdir_nt(path);
|
||||
}
|
||||
STRACE("%s(%#s) → %d% m", "chdir", path, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
33
libc/calls/chroot.c
Normal file
33
libc/calls/chroot.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
|
||||
/**
|
||||
* Changes root directory.
|
||||
*
|
||||
* @raise ENOSYS on Windows
|
||||
*/
|
||||
int chroot(const char *path) {
|
||||
int rc;
|
||||
rc = sys_chroot(path);
|
||||
STRACE("chroot(%s) → %d% m", path, rc);
|
||||
return rc;
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
|
@ -25,6 +26,8 @@
|
|||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
|
||||
|
||||
/**
|
||||
* Returns nanosecond time.
|
||||
*
|
||||
|
@ -39,14 +42,20 @@
|
|||
* @see strftime(), gettimeofday()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int clock_gettime(int clockid, struct timespec *ts) {
|
||||
int rc;
|
||||
noinstrument int clock_gettime(int clockid, struct timespec *ts) {
|
||||
int rc, e;
|
||||
axdx_t ad;
|
||||
if (!ts) return efault();
|
||||
if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) return efault();
|
||||
if (clockid == -1) return einval();
|
||||
if (!IsWindows()) {
|
||||
if ((rc = sys_clock_gettime(clockid, ts)) == -1 && errno == ENOSYS) {
|
||||
char buf[45];
|
||||
if (!ts) {
|
||||
rc = efault();
|
||||
} else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
|
||||
rc = efault();
|
||||
} else if (clockid == -1) {
|
||||
rc = einval();
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
if ((rc = __clock_gettime(clockid, ts))) {
|
||||
errno = e;
|
||||
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
|
||||
assert(ad.ax != -1);
|
||||
if (SupportsXnu() && ad.ax) {
|
||||
|
@ -56,8 +65,32 @@ int clock_gettime(int clockid, struct timespec *ts) {
|
|||
ts->tv_nsec *= 1000;
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
} else {
|
||||
return sys_clock_gettime_nt(clockid, ts);
|
||||
rc = sys_clock_gettime_nt(clockid, ts);
|
||||
}
|
||||
if (!__time_critical) {
|
||||
STRACE("clock_gettime(%d, [%s]) → %d% m", clockid,
|
||||
__strace_timespec(buf, sizeof(buf), rc, ts), rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns fast system clock_gettime() if it exists.
|
||||
*/
|
||||
void *__get_clock_gettime(void) {
|
||||
void *vdso;
|
||||
static bool once;
|
||||
static void *result;
|
||||
if (!once) {
|
||||
if ((vdso = __vdsofunc("__vdso_clock_gettime"))) {
|
||||
__clock_gettime = result = vdso;
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const void *const __clock_gettime_ctor[] initarray = {
|
||||
__get_clock_gettime,
|
||||
};
|
||||
|
|
|
@ -16,25 +16,41 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sock/ntstdin.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_close_nt(struct Fd *fd) {
|
||||
bool32 ok;
|
||||
if (fd->kind == kFdFile && GetFileType(fd->handle) == kNtFileTypeDisk) {
|
||||
/*
|
||||
* Like Linux, closing a file on Windows doesn't guarantee it's
|
||||
* immediately synced to disk. But unlike Linux, this could cause
|
||||
* subsequent operations, e.g. unlink() to break w/ access error.
|
||||
*/
|
||||
int e;
|
||||
bool ok = true;
|
||||
|
||||
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
|
||||
GetFileType(fd->handle) == kNtFileTypeDisk)) {
|
||||
// Like Linux, closing a file on Windows doesn't guarantee it's
|
||||
// immediately synced to disk. But unlike Linux, this could cause
|
||||
// subsequent operations, e.g. unlink() to break w/ access error.
|
||||
e = errno;
|
||||
FlushFileBuffers(fd->handle);
|
||||
errno = e;
|
||||
}
|
||||
|
||||
// if this file descriptor is wrapped in a named pipe worker thread
|
||||
// then we need to close our copy of the worker thread handle. it's
|
||||
// also required that whatever install a worker use malloc, so free
|
||||
if (fd->worker) {
|
||||
if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false;
|
||||
fd->worker = 0;
|
||||
} else {
|
||||
if (!CloseHandle(fd->handle)) ok = false;
|
||||
}
|
||||
ok = CloseHandle(fd->handle);
|
||||
if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
|
||||
ok &= CloseHandle(fd->extra);
|
||||
if (!CloseHandle(fd->extra)) ok = false;
|
||||
}
|
||||
return ok ? 0 : __winerr();
|
||||
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
@ -31,36 +31,52 @@
|
|||
* This function may be used for file descriptors returned by socket,
|
||||
* accept, epoll_create, and zipos file descriptors too.
|
||||
*
|
||||
* This function should never be called twice for the same file
|
||||
* descriptor, regardless of whether or not an error happened. However
|
||||
* that doesn't mean the error should be ignored.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @error EINTR means a signal was received while closing (possibly
|
||||
* because linger is enabled) in which case close() does not need to
|
||||
* be called again, since the fd will close in the background, and
|
||||
* chances are that on linux, the fd is already closed, even if the
|
||||
* underlying resource isn't closed yet
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int close(int fd) {
|
||||
int rc;
|
||||
if (fd == -1) return 0;
|
||||
if (fd < 0) return einval();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = weaken(__zipos_close)(fd);
|
||||
if (fd == -1) {
|
||||
rc = 0;
|
||||
} else if (fd < 0) {
|
||||
rc = einval();
|
||||
} else {
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
rc = sys_close(fd);
|
||||
} else if (IsMetal()) {
|
||||
rc = 0;
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
|
||||
rc = weaken(__zipos_close)(fd);
|
||||
} else {
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdEpoll) {
|
||||
rc = weaken(sys_close_epoll_nt)(fd);
|
||||
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) {
|
||||
rc = weaken(sys_closesocket_nt)(g_fds.p + fd);
|
||||
} else if (fd < g_fds.n && (g_fds.p[fd].kind == kFdFile ||
|
||||
g_fds.p[fd].kind == kFdConsole ||
|
||||
g_fds.p[fd].kind == kFdProcess)) {
|
||||
rc = sys_close_nt(g_fds.p + fd);
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
rc = sys_close(fd);
|
||||
} else if (IsMetal()) {
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = ebadf();
|
||||
if (fd < g_fds.n && g_fds.p[fd].kind == kFdEpoll) {
|
||||
rc = weaken(sys_close_epoll_nt)(fd);
|
||||
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) {
|
||||
rc = weaken(sys_closesocket_nt)(g_fds.p + fd);
|
||||
} else if (fd < g_fds.n && (g_fds.p[fd].kind == kFdFile ||
|
||||
g_fds.p[fd].kind == kFdConsole ||
|
||||
g_fds.p[fd].kind == kFdProcess)) {
|
||||
rc = sys_close_nt(g_fds.p + fd);
|
||||
} else {
|
||||
STRACE("close(%d) unknown kind: %d", fd, g_fds.p[fd].kind);
|
||||
rc = ebadf();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!__vforked) {
|
||||
__releasefd(fd);
|
||||
}
|
||||
}
|
||||
__releasefd(fd);
|
||||
SYSDEBUG("close(%d) -> %d", fd, rc);
|
||||
STRACE("%s(%d) → %d% m", "close", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,60 +16,69 @@
|
|||
│ 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/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static noasan bool EndsWithIgnoreCase(const char *p, size_t n, const char *s) {
|
||||
size_t i, m;
|
||||
m = __strlen(s);
|
||||
if (n >= m) {
|
||||
for (i = n - m; i < n; ++i) {
|
||||
if (kToLower[p[i] & 255] != (*s++ & 255)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
static bool IsExePath(const char *s, size_t n) {
|
||||
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".exe") ||
|
||||
READ32LE(s + n - 4) == READ32LE(".EXE"));
|
||||
}
|
||||
|
||||
static noasan bool AccessCommand(const char *name,
|
||||
char path[hasatleast PATH_MAX], size_t namelen,
|
||||
const char *suffix, size_t pathlen) {
|
||||
static bool IsComPath(const char *s, size_t n) {
|
||||
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".com") ||
|
||||
READ32LE(s + n - 4) == READ32LE(".COM"));
|
||||
}
|
||||
|
||||
static bool IsComDbgPath(const char *s, size_t n) {
|
||||
return n >= 8 && (READ64LE(s + n - 8) == READ64LE(".com.dbg") ||
|
||||
READ64LE(s + n - 8) == READ64LE(".COM.DBG"));
|
||||
}
|
||||
|
||||
static bool AccessCommand(const char *name, char *path, size_t pathsz,
|
||||
size_t namelen, int *err, const char *suffix,
|
||||
size_t pathlen) {
|
||||
size_t suffixlen;
|
||||
suffixlen = __strlen(suffix);
|
||||
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return -1;
|
||||
suffixlen = strlen(suffix);
|
||||
if (pathlen + 1 + namelen + suffixlen + 1 > pathsz) return false;
|
||||
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
|
||||
path[pathlen] = !IsWindows() ? '/'
|
||||
: __memchr(path, '\\', pathlen) ? '\\'
|
||||
: '/';
|
||||
path[pathlen] = !IsWindows() ? '/'
|
||||
: memchr(path, '\\', pathlen) ? '\\'
|
||||
: '/';
|
||||
pathlen++;
|
||||
}
|
||||
__repmovsb(path + pathlen, name, namelen);
|
||||
__repmovsb(path + pathlen + namelen, suffix, suffixlen + 1);
|
||||
return isexecutable(path);
|
||||
memcpy(path + pathlen, name, namelen);
|
||||
memcpy(path + pathlen + namelen, suffix, suffixlen + 1);
|
||||
if (!access(path, X_OK)) return true;
|
||||
if (errno == EACCES || *err != EACCES) *err = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
|
||||
size_t namelen, const char *suffix) {
|
||||
static bool SearchPath(const char *name, char *path, size_t pathsz,
|
||||
size_t namelen, int *err, const char *suffix) {
|
||||
char sep;
|
||||
size_t i;
|
||||
const char *p;
|
||||
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
|
||||
if (!(p = getenv("PATH"))) p = "/bin:/usr/local/bin:/usr/bin";
|
||||
sep = IsWindows() && strchr(p, ';') ? ';' : ':';
|
||||
for (;;) {
|
||||
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) {
|
||||
if (i < PATH_MAX) {
|
||||
for (i = 0; p[i] && p[i] != sep; ++i) {
|
||||
if (i < pathsz) {
|
||||
path[i] = p[i];
|
||||
}
|
||||
}
|
||||
if (AccessCommand(name, path, namelen, suffix, i)) {
|
||||
if (AccessCommand(name, path, pathsz, namelen, err, suffix, i)) {
|
||||
return true;
|
||||
}
|
||||
if (p[i] == ':' || p[i] == ';') {
|
||||
if (p[i] == sep) {
|
||||
p += i + 1;
|
||||
} else {
|
||||
break;
|
||||
|
@ -78,21 +87,36 @@ static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
|
|||
return false;
|
||||
}
|
||||
|
||||
static noasan bool FindCommand(const char *name,
|
||||
char pathbuf[hasatleast PATH_MAX],
|
||||
size_t namelen, const char *suffix) {
|
||||
if (memchr(name, '/', namelen) || memchr(name, '\\', namelen)) {
|
||||
pathbuf[0] = 0;
|
||||
return AccessCommand(name, pathbuf, namelen, suffix, 0);
|
||||
static bool FindCommand(const char *name, char *pb, size_t pbsz, size_t namelen,
|
||||
bool pri, const char *suffix, int *err) {
|
||||
if (pri && (memchr(name, '/', namelen) || memchr(name, '\\', namelen))) {
|
||||
pb[0] = 0;
|
||||
return AccessCommand(name, pb, pbsz, namelen, err, suffix, 0);
|
||||
}
|
||||
return ((IsWindows() &&
|
||||
(AccessCommand(name, pathbuf, namelen, suffix,
|
||||
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
|
||||
AccessCommand(name, pathbuf, namelen, suffix,
|
||||
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf) ||
|
||||
AccessCommand(name, pathbuf, namelen, suffix,
|
||||
stpcpy(pathbuf, ".") - pathbuf))) ||
|
||||
SearchPath(name, pathbuf, namelen, suffix));
|
||||
if (IsWindows() && pri &&
|
||||
pbsz > max(strlen(kNtSystemDirectory), strlen(kNtWindowsDirectory))) {
|
||||
return AccessCommand(name, pb, pbsz, namelen, err, suffix,
|
||||
stpcpy(pb, kNtSystemDirectory) - pb) ||
|
||||
AccessCommand(name, pb, pbsz, namelen, err, suffix,
|
||||
stpcpy(pb, kNtWindowsDirectory) - pb);
|
||||
}
|
||||
return (IsWindows() &&
|
||||
(pbsz > 1 && AccessCommand(name, pb, pbsz, namelen, err, suffix,
|
||||
stpcpy(pb, ".") - pb))) ||
|
||||
SearchPath(name, pb, pbsz, namelen, err, suffix);
|
||||
}
|
||||
|
||||
static bool FindVerbatim(const char *name, char *pb, size_t pbsz,
|
||||
size_t namelen, bool pri, int *err) {
|
||||
return FindCommand(name, pb, pbsz, namelen, pri, "", err);
|
||||
}
|
||||
|
||||
static bool FindSuffixed(const char *name, char *pb, size_t pbsz,
|
||||
size_t namelen, bool pri, int *err) {
|
||||
return !IsExePath(name, namelen) && !IsComPath(name, namelen) &&
|
||||
!IsComDbgPath(name, namelen) &&
|
||||
(FindCommand(name, pb, pbsz, namelen, pri, ".com", err) ||
|
||||
FindCommand(name, pb, pbsz, namelen, pri, ".exe", err));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,29 +128,36 @@ static noasan bool FindCommand(const char *name,
|
|||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
||||
int olderr;
|
||||
char *commandv(const char *name, char *pathbuf, size_t pathbufsz) {
|
||||
int e, f;
|
||||
char *res;
|
||||
size_t namelen;
|
||||
res = 0;
|
||||
if (!name) {
|
||||
efault();
|
||||
return 0;
|
||||
}
|
||||
if (!(namelen = __strlen(name))) {
|
||||
} else if (!(namelen = strlen(name))) {
|
||||
enoent();
|
||||
return 0;
|
||||
}
|
||||
if (namelen + 1 > PATH_MAX) {
|
||||
} else if (namelen + 1 > pathbufsz) {
|
||||
enametoolong();
|
||||
return 0;
|
||||
}
|
||||
if (FindCommand(name, pathbuf, namelen, "") ||
|
||||
(!EndsWithIgnoreCase(name, namelen, ".exe") &&
|
||||
!EndsWithIgnoreCase(name, namelen, ".com") &&
|
||||
!EndsWithIgnoreCase(name, namelen, ".com.dbg") &&
|
||||
(FindCommand(name, pathbuf, namelen, ".com") ||
|
||||
FindCommand(name, pathbuf, namelen, ".exe")))) {
|
||||
return pathbuf;
|
||||
} else {
|
||||
return 0;
|
||||
e = errno;
|
||||
f = ENOENT;
|
||||
if ((IsWindows() &&
|
||||
(FindSuffixed(name, pathbuf, pathbufsz, namelen, true, &f) ||
|
||||
FindVerbatim(name, pathbuf, pathbufsz, namelen, true, &f) ||
|
||||
FindSuffixed(name, pathbuf, pathbufsz, namelen, false, &f) ||
|
||||
FindVerbatim(name, pathbuf, pathbufsz, namelen, false, &f))) ||
|
||||
(!IsWindows() &&
|
||||
(FindVerbatim(name, pathbuf, pathbufsz, namelen, true, &f) ||
|
||||
FindSuffixed(name, pathbuf, pathbufsz, namelen, true, &f) ||
|
||||
FindVerbatim(name, pathbuf, pathbufsz, namelen, false, &f) ||
|
||||
FindSuffixed(name, pathbuf, pathbufsz, namelen, false, &f)))) {
|
||||
errno = e;
|
||||
res = pathbuf;
|
||||
} else {
|
||||
errno = f;
|
||||
}
|
||||
}
|
||||
STRACE("commandv(%#s, %p, %'zu) → %#s% m", name, pathbuf, pathbufsz, res);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
|
@ -27,6 +28,7 @@
|
|||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -66,12 +68,12 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
|
|||
int64_t inoffset, outoffset;
|
||||
int rc, srcfd, dstfd, oflags, omode;
|
||||
rc = -1;
|
||||
if ((srcfd = sys_openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
|
||||
if (sys_fstat(srcfd, &st) != -1) {
|
||||
if ((srcfd = openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
|
||||
if (fstat(srcfd, &st) != -1) {
|
||||
omode = st.st_mode & 0777;
|
||||
oflags = O_WRONLY | O_CREAT;
|
||||
if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL;
|
||||
if ((dstfd = sys_openat(AT_FDCWD, dst, oflags, omode)) != -1) {
|
||||
if ((dstfd = openat(AT_FDCWD, dst, oflags, omode)) != -1) {
|
||||
remaining = st.st_size;
|
||||
ftruncate(dstfd, remaining);
|
||||
inoffset = 0;
|
||||
|
@ -86,13 +88,13 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
|
|||
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
|
||||
amtime[0] = st.st_atim;
|
||||
amtime[1] = st.st_mtim;
|
||||
sys_utimensat(dstfd, NULL, amtime, 0);
|
||||
utimensat(dstfd, NULL, amtime, 0);
|
||||
}
|
||||
}
|
||||
rc |= sys_close(dstfd);
|
||||
rc |= close(dstfd);
|
||||
}
|
||||
}
|
||||
rc |= sys_close(srcfd);
|
||||
rc |= close(srcfd);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -108,7 +110,7 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int copyfile(const char *src, const char *dst, int flags) {
|
||||
if (!IsWindows()) {
|
||||
if (!IsWindows() || startswith(src, "/zip/") || startswith(dst, "/zip/")) {
|
||||
return sys_copyfile(src, dst, flags);
|
||||
} else {
|
||||
return sys_copyfile_nt(src, dst, flags);
|
||||
|
|
|
@ -35,6 +35,6 @@
|
|||
* @see open(), touch()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
nodiscard int creat(const char *file, uint32_t mode) {
|
||||
dontdiscard int creat(const char *file, uint32_t mode) {
|
||||
return openat(AT_FDCWD, file, O_CREAT | O_WRONLY | O_TRUNC, mode);
|
||||
}
|
||||
|
|
110
libc/calls/createfileflags.c
Normal file
110
libc/calls/createfileflags.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
// code size optimization
|
||||
// <sync libc/sysv/consts.sh>
|
||||
#define _O_APPEND 0x00000400 // kNtFileAppendData
|
||||
#define _O_CREAT 0x00000040 // kNtOpenAlways
|
||||
#define _O_EXCL 0x00000080 // kNtCreateNew
|
||||
#define _O_TRUNC 0x00000200 // kNtCreateAlways
|
||||
#define _O_DIRECTORY 0x00010000 // kNtFileFlagBackupSemantics
|
||||
#define _O_TMPFILE 0x00410000 // AttributeTemporary|FlagDeleteOnClose
|
||||
#define _O_DIRECT 0x00004000 // kNtFileFlagNoBuffering
|
||||
#define _O_NDELAY 0x00000800 // kNtFileFlagWriteThrough
|
||||
#define _O_RANDOM 0x80000000 // kNtFileFlagRandomAccess
|
||||
#define _O_SEQUENTIAL 0x40000000 // kNtFileFlagSequentialScan
|
||||
#define _O_COMPRESSED 0x20000000 // kNtFileAttributeCompressed
|
||||
#define _O_INDEXED 0x10000000 // !kNtFileAttributeNotContentIndexed
|
||||
#define _O_NONBLOCK 0x00000800
|
||||
#define _O_CLOEXEC 0x00080000
|
||||
// </sync libc/sysv/consts.sh>
|
||||
|
||||
textwindows int GetNtOpenFlags(int flags, int mode, uint32_t *out_perm,
|
||||
uint32_t *out_share, uint32_t *out_disp,
|
||||
uint32_t *out_attr) {
|
||||
uint32_t perm, share, disp, attr;
|
||||
|
||||
switch (flags & O_ACCMODE) {
|
||||
case O_RDONLY:
|
||||
perm = kNtFileGenericRead | kNtGenericExecute;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
perm = kNtFileGenericWrite | kNtGenericExecute;
|
||||
break;
|
||||
case O_RDWR:
|
||||
perm = kNtFileGenericRead | kNtFileGenericWrite | kNtGenericExecute;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (flags & _O_APPEND) {
|
||||
perm = kNtFileAppendData;
|
||||
}
|
||||
|
||||
if (flags & _O_EXCL) {
|
||||
share = kNtFileShareExclusive;
|
||||
} else {
|
||||
share = kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete;
|
||||
}
|
||||
|
||||
if ((flags & _O_CREAT) && (flags & _O_EXCL)) {
|
||||
disp = kNtCreateNew;
|
||||
} else if ((flags & _O_CREAT) && (flags & _O_TRUNC)) {
|
||||
disp = kNtCreateAlways;
|
||||
} else if (flags & _O_CREAT) {
|
||||
disp = kNtOpenAlways;
|
||||
} else if (flags & _O_TRUNC) {
|
||||
disp = kNtTruncateExisting;
|
||||
} else {
|
||||
disp = kNtOpenExisting;
|
||||
}
|
||||
|
||||
if ((flags & _O_TMPFILE) == _O_TMPFILE) {
|
||||
attr = kNtFileAttributeTemporary | kNtFileFlagDeleteOnClose;
|
||||
} else {
|
||||
attr = kNtFileAttributeNormal;
|
||||
if (flags & _O_DIRECTORY) {
|
||||
attr |= kNtFileFlagBackupSemantics;
|
||||
}
|
||||
if (~mode & 0200) {
|
||||
attr |= kNtFileAttributeReadonly;
|
||||
}
|
||||
}
|
||||
|
||||
if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed;
|
||||
if (flags & _O_COMPRESSED) attr |= kNtFileAttributeCompressed;
|
||||
if (flags & _O_SEQUENTIAL) attr |= kNtFileFlagSequentialScan;
|
||||
if (flags & _O_RANDOM) attr |= kNtFileFlagRandomAccess;
|
||||
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
|
||||
if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough;
|
||||
|
||||
if (out_perm) *out_perm = perm;
|
||||
if (out_share) *out_share = share;
|
||||
if (out_disp) *out_disp = disp;
|
||||
if (out_attr) *out_attr = attr;
|
||||
return 0;
|
||||
}
|
|
@ -16,32 +16,35 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/reverse.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/intrin/lockxadd.h"
|
||||
#include "libc/nt/process.h"
|
||||
|
||||
static const char kPipeNamePrefix[] = "\\\\?\\pipe\\cosmo\\";
|
||||
|
||||
static textwindows size_t UintToChar16Array(char16_t *a, uint64_t i) {
|
||||
size_t j = 0;
|
||||
static textwindows char16_t *UintToChar16Array(char16_t p[21], uint64_t x) {
|
||||
char t;
|
||||
size_t a, b, i = 0;
|
||||
do {
|
||||
a[j++] = i % 10 + '0';
|
||||
i /= 10;
|
||||
} while (i > 0);
|
||||
a[j] = 0;
|
||||
reverse(a, j);
|
||||
return j;
|
||||
p[i++] = x % 10 + '0';
|
||||
x = x / 10;
|
||||
} while (x > 0);
|
||||
if (i) {
|
||||
for (a = 0, b = i - 1; a < b; ++a, --b) {
|
||||
t = p[a];
|
||||
p[a] = p[b];
|
||||
p[b] = t;
|
||||
}
|
||||
}
|
||||
return p + i;
|
||||
}
|
||||
|
||||
textwindows char16_t *CreatePipeName(char16_t *a) {
|
||||
static long x;
|
||||
unsigned i;
|
||||
for (i = 0; kPipeNamePrefix[i]; ++i) a[i] = kPipeNamePrefix[i];
|
||||
i += UintToChar16Array(a + i, GetCurrentProcessId());
|
||||
a[i++] = u'-';
|
||||
i += UintToChar16Array(a + i, GetCurrentProcessId());
|
||||
a[i++] = u'-';
|
||||
i += UintToChar16Array(a + i, x++);
|
||||
a[i] = u'\0';
|
||||
char16_t *p = a;
|
||||
const char *q = "\\\\?\\pipe\\cosmo\\";
|
||||
while (*q) *p++ = *q++;
|
||||
p = UintToChar16Array(p, GetCurrentProcessId());
|
||||
*p++ = '-';
|
||||
p = UintToChar16Array(p, _lockxadd(&x, 1));
|
||||
*p = 0;
|
||||
return a;
|
||||
}
|
||||
|
|
38
libc/calls/describeclockname.c
Normal file
38
libc/calls/describeclockname.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- 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/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
|
||||
/**
|
||||
* Describes clock_gettime() clock argument.
|
||||
*/
|
||||
char *DescribeClockName(int x) {
|
||||
int i;
|
||||
char *s;
|
||||
_Alignas(char) static char buf[32];
|
||||
if ((s = GetMagnumStr(kClockNames, x))) {
|
||||
stpcpy(stpcpy(buf, "CLOCK_"), s);
|
||||
return buf;
|
||||
} else {
|
||||
FormatInt32(buf, x);
|
||||
return buf;
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
@ -28,21 +28,19 @@
|
|||
noasan const char *DescribeFrame(int x) {
|
||||
/* asan runtime depends on this function */
|
||||
char *p;
|
||||
static char buf[128];
|
||||
static char buf[32];
|
||||
if (IsShadowFrame(x)) {
|
||||
p = buf;
|
||||
p = __stpcpy(p, " shadow of ");
|
||||
p = __fixcpy(p, UNSHADOW(ADDR(x)), 48);
|
||||
ksnprintf(buf, sizeof(buf), " /*shadow:%.12p*/", UNSHADOW(ADDR(x)));
|
||||
return buf;
|
||||
return " shadow ";
|
||||
return " /*shadow*/ ";
|
||||
} else if (IsAutoFrame(x)) {
|
||||
return " automap";
|
||||
return " /*automap*/";
|
||||
} else if (IsFixedFrame(x)) {
|
||||
return " fixed ";
|
||||
return " /*fixed*/ ";
|
||||
} else if (IsArenaFrame(x)) {
|
||||
return " arena ";
|
||||
return " /*arena*/ ";
|
||||
} else if (IsStaticStackFrame(x)) {
|
||||
return " stack ";
|
||||
return " /*stack*/ ";
|
||||
} else {
|
||||
return "";
|
||||
}
|
|
@ -20,19 +20,32 @@
|
|||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
noasan char *DescribeMapping(int prot, int flags, char p[hasatleast 8]) {
|
||||
/* asan runtime depends on this function */
|
||||
static noasan char DescribeMapType(int flags) {
|
||||
switch (flags & MAP_TYPE) {
|
||||
case MAP_FILE:
|
||||
return 'f';
|
||||
case MAP_PRIVATE:
|
||||
return 'p';
|
||||
case MAP_SHARED:
|
||||
return 's';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
noasan char *DescribeProt(int prot, char p[hasatleast 4]) {
|
||||
p[0] = (prot & PROT_READ) ? 'r' : '-';
|
||||
p[1] = (prot & PROT_WRITE) ? 'w' : '-';
|
||||
p[2] = (prot & PROT_EXEC) ? 'x' : '-';
|
||||
if (flags & MAP_PRIVATE) {
|
||||
p[3] = 'p';
|
||||
} else if (flags & MAP_SHARED) {
|
||||
p[3] = 's';
|
||||
} else {
|
||||
p[3] = '?';
|
||||
}
|
||||
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : 'f';
|
||||
p[3] = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
noasan char *DescribeMapping(int prot, int flags, char p[hasatleast 8]) {
|
||||
/* asan runtime depends on this function */
|
||||
DescribeProt(prot, p);
|
||||
p[3] = DescribeMapType(flags);
|
||||
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : '-';
|
||||
p[5] = (flags & MAP_GROWSDOWN) ? 'S' : '-';
|
||||
p[6] = (flags & MAP_FIXED) ? 'F' : '-';
|
||||
p[7] = 0;
|
41
libc/calls/describeopenflags.greg.c
Normal file
41
libc/calls/describeopenflags.greg.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 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/itoa.h"
|
||||
#include "libc/fmt/magnumstrs.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/sysv/consts/sol.h"
|
||||
|
||||
/**
|
||||
* Describes clock_gettime() clock argument.
|
||||
*/
|
||||
char *DescribeOpenFlags(int x) {
|
||||
char *s;
|
||||
int i, n;
|
||||
struct DescribeFlags *d;
|
||||
_Alignas(char) static char openflags[128];
|
||||
// TODO(jart): unify DescribeFlags and MagnumStr data structures
|
||||
for (n = 0; kOpenFlags[n].x != MAGNUM_TERMINATOR;) ++n;
|
||||
d = alloca(n * sizeof(struct DescribeFlags));
|
||||
for (i = 0; i < n; ++i) {
|
||||
d[i].flag = MAGNUM_NUMBER(kOpenFlags, i);
|
||||
d[i].name = MAGNUM_STRING(kOpenFlags, i);
|
||||
}
|
||||
return DescribeFlags(openflags, sizeof(openflags), d, n, "O_", x);
|
||||
}
|
102
libc/calls/directmap-nt.c
Normal file
102
libc/calls/directmap-nt.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/processmemorycounters.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
|
||||
int flags, int fd, int64_t off) {
|
||||
size_t i;
|
||||
bool iscow;
|
||||
int64_t handle;
|
||||
uint32_t oldprot;
|
||||
struct DirectMap dm;
|
||||
struct ProtectNt fl;
|
||||
const struct NtSecurityAttributes *sec;
|
||||
struct NtProcessMemoryCountersEx memcount;
|
||||
|
||||
if (fd != -1) {
|
||||
handle = g_fds.p[fd].handle;
|
||||
} else {
|
||||
handle = kNtInvalidHandleValue;
|
||||
}
|
||||
|
||||
if (flags & MAP_PRIVATE) {
|
||||
sec = 0; // MAP_PRIVATE isn't inherited across fork()
|
||||
} else {
|
||||
sec = &kNtIsInheritable; // MAP_SHARED gives us zero-copy fork()
|
||||
}
|
||||
|
||||
// nt will whine under many circumstances if we change the execute bit
|
||||
// later using mprotect(). the workaround is to always request execute
|
||||
// and then virtualprotect() it away until we actually need it. please
|
||||
// note that open-nt.c always requests an kNtGenericExecute accessmask
|
||||
iscow = false;
|
||||
if (handle != -1) {
|
||||
if (flags & MAP_PRIVATE) {
|
||||
// windows has cow pages but they can't propagate across fork()
|
||||
// that means we only get copy-on-write for the root process :(
|
||||
fl = (struct ProtectNt){kNtPageExecuteWritecopy,
|
||||
kNtFileMapCopy | kNtFileMapExecute};
|
||||
iscow = true;
|
||||
} else {
|
||||
assert(flags & MAP_SHARED);
|
||||
if ((g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY) {
|
||||
fl = (struct ProtectNt){kNtPageExecuteRead,
|
||||
kNtFileMapRead | kNtFileMapExecute};
|
||||
} else {
|
||||
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
|
||||
kNtFileMapWrite | kNtFileMapExecute};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(flags & MAP_ANONYMOUS);
|
||||
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
|
||||
kNtFileMapWrite | kNtFileMapExecute};
|
||||
}
|
||||
|
||||
if ((dm.maphandle = CreateFileMapping(handle, sec, fl.flags1,
|
||||
(size + off) >> 32, (size + off), 0))) {
|
||||
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
|
||||
size, addr))) {
|
||||
if (VirtualProtect(addr, size, __prot2nt(prot, iscow), &oldprot)) {
|
||||
return dm;
|
||||
} else {
|
||||
return dm;
|
||||
UnmapViewOfFile(dm.addr);
|
||||
}
|
||||
}
|
||||
CloseHandle(dm.maphandle);
|
||||
}
|
||||
|
||||
dm.maphandle = kNtInvalidHandleValue;
|
||||
dm.addr = (void *)(intptr_t)-1;
|
||||
return dm;
|
||||
}
|
|
@ -17,8 +17,9 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
@ -31,25 +32,24 @@
|
|||
* support Windows NT and Address Sanitizer. That memory tracking can be
|
||||
* bypassed by calling this function. However the caller is responsible
|
||||
* for passing the magic memory handle on Windows NT to CloseHandle().
|
||||
*
|
||||
* @asyncsignalsafe
|
||||
* @threadsafe
|
||||
*/
|
||||
noasan struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags,
|
||||
int fd, int64_t off) {
|
||||
struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
|
||||
int64_t off) {
|
||||
/* asan runtime depends on this function */
|
||||
char mode[8];
|
||||
struct DirectMap dm;
|
||||
struct DirectMap d;
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
dm.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
|
||||
SYSDEBUG("sys_mmap(0x%p%s, 0x%x, %s, %d, %d) -> 0x%p %s", addr,
|
||||
DescribeFrame((intptr_t)addr >> 16), size,
|
||||
DescribeMapping(prot, flags, mode), (long)fd, off, dm.addr,
|
||||
dm.addr != MAP_FAILED ? "" : strerror(errno));
|
||||
dm.maphandle = kNtInvalidHandleValue;
|
||||
return dm;
|
||||
d.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
|
||||
d.maphandle = kNtInvalidHandleValue;
|
||||
} else if (IsMetal()) {
|
||||
return sys_mmap_metal(addr, size, prot, flags, fd, off);
|
||||
d = sys_mmap_metal(addr, size, prot, flags, fd, off);
|
||||
} else {
|
||||
return sys_mmap_nt(addr, size, prot, flags,
|
||||
fd != -1 ? g_fds.p[fd].handle : kNtInvalidHandleValue,
|
||||
off);
|
||||
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
|
||||
}
|
||||
KERNTRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
|
||||
DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot),
|
||||
DescribeMapFlags(flags), fd, off, d.addr, d.maphandle);
|
||||
return d;
|
||||
}
|
|
@ -17,38 +17,69 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/ntstdin.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Implements dup(), dup2(), and dup3() for Windows NT.
|
||||
* Implements dup(), dup2(), dup3(), and F_DUPFD for Windows.
|
||||
*/
|
||||
textwindows int sys_dup_nt(int oldfd, int newfd, int flags) {
|
||||
int64_t proc;
|
||||
textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
||||
int64_t proc, handle;
|
||||
|
||||
// validate the api usage
|
||||
if (oldfd < 0) return einval();
|
||||
if (flags & ~O_CLOEXEC) return einval();
|
||||
if (oldfd >= g_fds.n ||
|
||||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
|
||||
g_fds.p[oldfd].kind != kFdConsole)) {
|
||||
return ebadf();
|
||||
}
|
||||
|
||||
// allocate a new file descriptor
|
||||
if (newfd == -1) {
|
||||
if ((newfd = __reservefd()) == -1) return -1;
|
||||
if ((newfd = __reservefd(start)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (__ensurefds(newfd) == -1) return -1;
|
||||
if (g_fds.p[newfd].kind) close(newfd);
|
||||
g_fds.p[newfd].kind = kFdReserved;
|
||||
}
|
||||
|
||||
// if this file descriptor is wrapped in a named pipe worker thread
|
||||
// then we should clone the original authentic handle rather than the
|
||||
// stdin worker's named pipe. we won't clone the worker, since that
|
||||
// can always be recreated again on demand.
|
||||
if (g_fds.p[oldfd].worker) {
|
||||
handle = g_fds.p[oldfd].worker->reader;
|
||||
} else {
|
||||
handle = g_fds.p[oldfd].handle;
|
||||
}
|
||||
|
||||
proc = GetCurrentProcess();
|
||||
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
|
||||
0, true, kNtDuplicateSameAccess)) {
|
||||
if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, true,
|
||||
kNtDuplicateSameAccess)) {
|
||||
g_fds.p[newfd].kind = g_fds.p[oldfd].kind;
|
||||
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
|
||||
g_fds.p[newfd].flags = flags;
|
||||
g_fds.p[newfd].mode = g_fds.p[oldfd].mode;
|
||||
g_fds.p[newfd].flags = g_fds.p[oldfd].flags & ~O_CLOEXEC;
|
||||
if (flags & O_CLOEXEC) g_fds.p[newfd].flags |= O_CLOEXEC;
|
||||
if (g_fds.p[oldfd].kind == kFdSocket && weaken(_dupsockfd)) {
|
||||
g_fds.p[newfd].extra =
|
||||
(intptr_t)weaken(_dupsockfd)((struct SockFd *)g_fds.p[oldfd].extra);
|
||||
} else {
|
||||
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
|
||||
}
|
||||
if (g_fds.p[oldfd].worker) {
|
||||
g_fds.p[newfd].worker = weaken(RefNtStdinWorker)(g_fds.p[oldfd].worker);
|
||||
}
|
||||
return newfd;
|
||||
} else {
|
||||
__releasefd(newfd);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
/**
|
||||
|
@ -34,8 +34,8 @@ int dup(int fd) {
|
|||
if (!IsWindows()) {
|
||||
fd2 = sys_dup(fd);
|
||||
} else {
|
||||
fd2 = sys_dup_nt(fd, -1, 0);
|
||||
fd2 = sys_dup_nt(fd, -1, 0, -1);
|
||||
}
|
||||
SYSDEBUG("dup(%d) -> %d", fd, fd2);
|
||||
STRACE("%s(%d) → %d% m", "dup", fd, fd2);
|
||||
return fd2;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sysdebug.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
/**
|
||||
|
@ -32,11 +32,14 @@
|
|||
* @vforksafe
|
||||
*/
|
||||
int dup2(int oldfd, int newfd) {
|
||||
SYSDEBUG("dup2(%d, %d)", oldfd, newfd);
|
||||
if (oldfd == newfd) return newfd;
|
||||
if (!IsWindows()) {
|
||||
return sys_dup3(oldfd, newfd, 0);
|
||||
int rc;
|
||||
if (oldfd == newfd) {
|
||||
rc = newfd;
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_dup3(oldfd, newfd, 0);
|
||||
} else {
|
||||
return sys_dup_nt(oldfd, newfd, 0);
|
||||
rc = sys_dup_nt(oldfd, newfd, 0, -1);
|
||||
}
|
||||
STRACE("dup2(%d, %d) → %d% m", oldfd, newfd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -17,17 +17,17 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/errno.h"
|
||||
|
||||
#define __NR_dup3_linux 0x0124 /*RHEL5:CVE-2010-3301*/
|
||||
|
||||
int32_t sys_dup3(int32_t oldfd, int32_t newfd, int flags) {
|
||||
static bool once, demodernize;
|
||||
int olderr, fd;
|
||||
if (!once) {
|
||||
olderr = errno;
|
||||
fd = __sys_dup3(oldfd, newfd, flags);
|
||||
if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) {
|
||||
if (fd == -1 && errno == ENOSYS) {
|
||||
STRACE("demodernizing %s() due to %s", "dup3", "RHEL5:CVE-2010-3301");
|
||||
demodernize = true;
|
||||
once = true;
|
||||
errno = olderr;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue