mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-12 01:08:00 +00:00
Improve memory safety
This commit makes numerous refinements to cosmopolitan memory handling. The default stack size has been reduced from 2mb to 128kb. A new macro is now provided so you can easily reconfigure the stack size to be any value you want. Work around the breaking change by adding to your main: STATIC_STACK_SIZE(0x00200000); // 2mb stack If you're not sure how much stack you need, then you can use: STATIC_YOINK("stack_usage_logging"); After which you can `sort -nr o/$MODE/stack.log`. Based on the unit test suite, nothing in the Cosmopolitan repository (except for Python) needs a stack size greater than 30kb. There are also new macros for detecting the size and address of the stack at runtime, e.g. GetStackAddr(). We also now support sigaltstack() so if you want to see nice looking crash reports whenever a stack overflow happens, you can put this in main(): ShowCrashReports(); Under `make MODE=dbg` and `make MODE=asan` the unit testing framework will now automatically print backtraces of memory allocations when things like memory leaks happen. Bugs are now fixed in ASAN global variable overrun detection. The memtrack and asan runtimes also handle edge cases now. The new tools helped to identify a few memory leaks, which are fixed by this change. This change should fix an issue reported in #288 with ARG_MAX limits. Fixing this doubled the performance of MKDEPS.COM and AR.COM yet again.
This commit is contained in:
parent
a0b39f886c
commit
226aaf3547
317 changed files with 6474 additions and 3993 deletions
36
Makefile
36
Makefile
|
@ -216,30 +216,25 @@ tags: TAGS HTAGS
|
||||||
o/$(MODE)/.x:
|
o/$(MODE)/.x:
|
||||||
@mkdir -p $(@D) && touch $@
|
@mkdir -p $(@D) && touch $@
|
||||||
|
|
||||||
ifneq ($(findstring 4.,,$(MAKE_VERSION)),$(MAKE_VERSION))
|
|
||||||
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||||
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
$(file >$@,$(SRCS))
|
||||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||||
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
$(file >$@,$(HDRS) $(INCS))
|
||||||
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x))))
|
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x))))
|
||||||
$(file >$@) $(foreach x,$(INCS) $(INCS),$(file >>$@,$(x)))
|
$(file >$@,$(INCS))
|
||||||
else
|
|
||||||
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
|
||||||
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^SRCS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
|
|
||||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
|
||||||
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^HDRS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
|
|
||||||
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x))))
|
|
||||||
$(MAKE) MODE=rel -j8 -pn bopit 2>/dev/null | sed -ne '/^INCS/ {s/.*:= //;s/ */\n/g;p;q}' >$@
|
|
||||||
endif
|
|
||||||
|
|
||||||
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt $(SRCS) $(HDRS) $(INCS)
|
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt $(SRCS) $(HDRS) $(INCS)
|
||||||
@$(COMPILE) -AMKDEPS $(MKDEPS) -o $@ -r o/$(MODE)/ o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt
|
@$(COMPILE) -AMKDEPS $(MKDEPS) -o $@ -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
|
||||||
|
|
||||||
TAGS: o/$(MODE)/srcs.txt $(SRCS)
|
o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
|
||||||
|
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
||||||
|
o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
|
||||||
|
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
|
||||||
|
|
||||||
|
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
|
||||||
@rm -f $@
|
@rm -f $@
|
||||||
@$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@
|
@$(COMPILE) -ATAGS -T$@ $(TAGS) $(TAGSFLAGS) -L $< -o $@
|
||||||
|
|
||||||
HTAGS: o/$(MODE)/hdrs.txt $(HDRS)
|
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
|
||||||
@rm -f $@
|
@rm -f $@
|
||||||
@$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@
|
@$(COMPILE) -ATAGS -T$@ build/htags -L $< -o $@
|
||||||
|
|
||||||
|
@ -326,14 +321,15 @@ COSMOPOLITAN_HEADERS = \
|
||||||
THIRD_PARTY_ZLIB \
|
THIRD_PARTY_ZLIB \
|
||||||
THIRD_PARTY_REGEX
|
THIRD_PARTY_REGEX
|
||||||
|
|
||||||
o/$(MODE)/cosmopolitan.a.txt:
|
o/$(MODE)/cosmopolitan.a: \
|
||||||
printf "%s\n" $(call reverse,$(call uniq,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)))))
|
$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS))
|
||||||
o/$(MODE)/cosmopolitan.a: $(filter-out o/libc/stubs/exit11.o,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS)))
|
|
||||||
o/cosmopolitan.h: \
|
o/cosmopolitan.h: \
|
||||||
o/$(MODE)/tool/build/rollup.com \
|
o/$(MODE)/tool/build/rollup.com \
|
||||||
libc/integral/normalize.inc \
|
libc/integral/normalize.inc \
|
||||||
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS))
|
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS))
|
||||||
@$(COMPILE) -AROLLUP -T$@ $^ >$@
|
$(file >$@.args,libc/integral/normalize.inc $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)))
|
||||||
|
@$(COMPILE) -AROLLUP -T$@ o/$(MODE)/tool/build/rollup.com @$@.args >$@
|
||||||
|
|
||||||
o/cosmopolitan.html: \
|
o/cosmopolitan.html: \
|
||||||
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
|
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
|
||||||
|
|
|
@ -92,4 +92,4 @@ find o -name \*.com | xargs ls -rShal | less
|
||||||
| FreeBSD | 12 | 2018 |
|
| FreeBSD | 12 | 2018 |
|
||||||
| OpenBSD | 6.4 | 2018 |
|
| OpenBSD | 6.4 | 2018 |
|
||||||
| NetBSD | 9.1 | 2020 |
|
| NetBSD | 9.1 | 2020 |
|
||||||
| GNU Make | 3.80 | 2010 |
|
| GNU Make | 4.0 | 2015 |
|
||||||
|
|
|
@ -485,10 +485,10 @@ HIDDEN(ape_ram_align = PAGESIZE);
|
||||||
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
|
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
|
||||||
|
|
||||||
HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz);
|
HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz);
|
||||||
HIDDEN(ape_stack_vaddr = 0x700000000000 - STACKSIZE);
|
HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE);
|
||||||
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);
|
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);
|
||||||
HIDDEN(ape_stack_filesz = 0);
|
HIDDEN(ape_stack_filesz = 0);
|
||||||
HIDDEN(ape_stack_memsz = STACKSIZE);
|
HIDDEN(ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : STACKSIZE);
|
||||||
HIDDEN(ape_stack_align = 16);
|
HIDDEN(ape_stack_align = 16);
|
||||||
|
|
||||||
HIDDEN(ape_note_offset = ape_rom_offset + (ape_note - ape_rom_vaddr));
|
HIDDEN(ape_note_offset = ape_rom_offset + (ape_note - ape_rom_vaddr));
|
||||||
|
|
10
ape/config.h
Normal file
10
ape/config.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef COSMOPOLITAN_APE_CONFIG_H_
|
||||||
|
#define COSMOPOLITAN_APE_CONFIG_H_
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
|
#define STATIC_SYMBOL(NAME, VALUE) \
|
||||||
|
asm(".equ\t" NAME "," VALUE "\n\t" \
|
||||||
|
".globl\t" NAME)
|
||||||
|
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_APE_CONFIG_H_ */
|
38
ape/loader.c
38
ape/loader.c
|
@ -68,59 +68,59 @@ static wontreturn void Exit(int os, long rc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Close(int os, long fd) {
|
static void Close(int os, long fd) {
|
||||||
long ax;
|
long ax, di;
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(ax)
|
: "=a"(ax), "=D"(di)
|
||||||
: "0"(__NR_close), "D"(fd)
|
: "0"(__NR_close), "1"(fd)
|
||||||
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc");
|
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Read(int os, long fd, void *data, unsigned long size) {
|
static long Read(int os, long fd, void *data, unsigned long size) {
|
||||||
bool cf;
|
bool cf;
|
||||||
long ax;
|
long ax, di, si, dx;
|
||||||
asm volatile("clc\n\t"
|
asm volatile("clc\n\t"
|
||||||
"syscall"
|
"syscall"
|
||||||
: "=@ccc"(cf), "=a"(ax)
|
: "=@ccc"(cf), "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||||
: "1"(__NR_read), "D"(fd), "S"(data), "d"(size)
|
: "1"(__NR_read), "2"(fd), "3"(data), "4"(size)
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||||
if (cf) ax = -ax;
|
if (cf) ax = -ax;
|
||||||
return ax;
|
return ax;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Write(int os, long fd, const void *data, unsigned long size) {
|
static void Write(int os, long fd, const void *data, unsigned long size) {
|
||||||
long ax;
|
long ax, di, si, dx;
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(ax)
|
: "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||||
: "0"(__NR_write), "D"(fd), "S"(data), "d"(size)
|
: "0"(__NR_write), "1"(fd), "2"(data), "3"(size)
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Fstat(int os, long fd, union metastat *st) {
|
static long Fstat(int os, long fd, union metastat *st) {
|
||||||
long ax;
|
long ax, di, si;
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(ax)
|
: "=a"(ax), "=D"(di), "=S"(si)
|
||||||
: "0"(__NR_fstat), "D"(fd), "S"(st)
|
: "0"(__NR_fstat), "1"(fd), "2"(st)
|
||||||
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory");
|
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
return ax;
|
return ax;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Msyscall(int os, long p, long n) {
|
static void Msyscall(int os, long p, long n) {
|
||||||
long ax;
|
long ax, di, si;
|
||||||
if (os == OPENBSD) {
|
if (os == OPENBSD) {
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(ax)
|
: "=a"(ax), "=D"(di), "=S"(si)
|
||||||
: "0"(37), "D"(p), "S"(n)
|
: "0"(37), "1"(p), "2"(n)
|
||||||
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
|
: "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static long Open(int os, const char *path, long flags, long mode) {
|
static long Open(int os, const char *path, long flags, long mode) {
|
||||||
bool cf;
|
bool cf;
|
||||||
long ax;
|
long ax, di, si, dx;
|
||||||
asm volatile("clc\n\t"
|
asm volatile("clc\n\t"
|
||||||
"syscall"
|
"syscall"
|
||||||
: "=@ccc"(cf), "=a"(ax)
|
: "=@ccc"(cf), "=a"(ax), "=D"(di), "=S"(si), "=d"(dx)
|
||||||
: "1"(__NR_open), "D"(path), "S"(flags), "d"(mode)
|
: "1"(__NR_open), "2"(path), "3"(flags), "4"(mode)
|
||||||
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
: "rcx", "r8", "r9", "r10", "r11", "memory");
|
||||||
if (cf) ax = -ax;
|
if (cf) ax = -ax;
|
||||||
return ax;
|
return ax;
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -41,6 +41,7 @@ CONFIG_CPPFLAGS += \
|
||||||
|
|
||||||
CONFIG_CCFLAGS += \
|
CONFIG_CCFLAGS += \
|
||||||
$(BACKTRACES) \
|
$(BACKTRACES) \
|
||||||
|
$(FTRACE) \
|
||||||
-O3
|
-O3
|
||||||
|
|
||||||
TARGET_ARCH ?= \
|
TARGET_ARCH ?= \
|
||||||
|
@ -122,7 +123,8 @@ CONFIG_CPPFLAGS += \
|
||||||
CONFIG_CCFLAGS += \
|
CONFIG_CCFLAGS += \
|
||||||
$(BACKTRACES) \
|
$(BACKTRACES) \
|
||||||
$(FTRACE) \
|
$(FTRACE) \
|
||||||
-O2
|
-O2 \
|
||||||
|
-fno-inline
|
||||||
|
|
||||||
CONFIG_COPTS += \
|
CONFIG_COPTS += \
|
||||||
-fsanitize=address
|
-fsanitize=address
|
||||||
|
@ -159,7 +161,6 @@ CONFIG_CCFLAGS += \
|
||||||
-fno-align-labels \
|
-fno-align-labels \
|
||||||
-fno-align-loops \
|
-fno-align-loops \
|
||||||
-fschedule-insns2 \
|
-fschedule-insns2 \
|
||||||
-fomit-frame-pointer \
|
|
||||||
-momit-leaf-frame-pointer \
|
-momit-leaf-frame-pointer \
|
||||||
-foptimize-sibling-calls
|
-foptimize-sibling-calls
|
||||||
TARGET_ARCH ?= \
|
TARGET_ARCH ?= \
|
||||||
|
|
|
@ -88,6 +88,10 @@ export TMPDIR
|
||||||
FTRACE = \
|
FTRACE = \
|
||||||
-pg
|
-pg
|
||||||
|
|
||||||
|
BACKTRACES = \
|
||||||
|
-fno-optimize-sibling-calls \
|
||||||
|
-mno-omit-leaf-frame-pointer
|
||||||
|
|
||||||
SANITIZER = \
|
SANITIZER = \
|
||||||
-fsanitize=address
|
-fsanitize=address
|
||||||
|
|
||||||
|
@ -126,8 +130,7 @@ DEFAULT_COPTS = \
|
||||||
-fstrict-aliasing \
|
-fstrict-aliasing \
|
||||||
-fstrict-overflow \
|
-fstrict-overflow \
|
||||||
-fno-omit-frame-pointer \
|
-fno-omit-frame-pointer \
|
||||||
-fno-semantic-interposition \
|
-fno-semantic-interposition
|
||||||
-mno-omit-leaf-frame-pointer
|
|
||||||
|
|
||||||
MATHEMATICAL = \
|
MATHEMATICAL = \
|
||||||
-O3 \
|
-O3 \
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
MAKEFLAGS += --no-builtin-rules
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
|
||||||
o/%.a: ; @$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ $^
|
|
||||||
o/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
o/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||||
o/%.o: o/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
o/%.o: o/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||||
o/%.s: %.S ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) $<
|
o/%.s: %.S ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) $<
|
||||||
|
@ -36,7 +35,6 @@ o/%.h.okk: %.h ; @$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++
|
||||||
o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
|
||||||
o/%.zip.o: o/% ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
o/%.zip.o: o/% ; @$(COMPILE) -AZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
o/$(MODE)/%.a: ; @$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ $^
|
|
||||||
o/$(MODE)/%: o/$(MODE)/%.dbg ; @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
o/$(MODE)/%: o/$(MODE)/%.dbg ; @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||||
o/$(MODE)/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
o/$(MODE)/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||||
o/$(MODE)/%.o: o/$(MODE)/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
o/$(MODE)/%.o: o/$(MODE)/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
|
||||||
|
@ -82,6 +80,10 @@ o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S
|
||||||
o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
|
||||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||||
|
|
||||||
|
o/%.a:
|
||||||
|
$(file >$@.args,$^)
|
||||||
|
@$(COMPILE) -AARCHIVE -T$@ $(AR) $(ARFLAGS) $@ @$@.args
|
||||||
|
|
||||||
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
|
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
|
||||||
@$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
|
@$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,8 @@ __m128 tty2rgbf_(struct TtyRgb rgbxt) {
|
||||||
|
|
||||||
static int rgb2xterm256_(int r, int g, int b) {
|
static int rgb2xterm256_(int r, int g, int b) {
|
||||||
int cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv;
|
int cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv;
|
||||||
gray = round(r * .299 + g * .587 + b * .114);
|
gray = round(871024 / 4096299. * r + 8788810 / 12288897. * g +
|
||||||
|
887015 / 12288897. * b);
|
||||||
grai = gray > 238 ? 23 : (gray - 3) / 10;
|
grai = gray > 238 ? 23 : (gray - 3) / 10;
|
||||||
ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40;
|
ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40;
|
||||||
ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40;
|
ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/struct/rusage.h"
|
#include "libc/calls/struct/rusage.h"
|
||||||
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/log/check.h"
|
#include "libc/log/check.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
|
|
77
examples/stackoverflow.c
Normal file
77
examples/stackoverflow.c
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#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/limits.h"
|
||||||
|
#include "libc/log/check.h"
|
||||||
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/runtime/stack.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview Stack Overflow Demo
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define N INT_MAX
|
||||||
|
|
||||||
|
STATIC_STACK_SIZE(FRAMESIZE);
|
||||||
|
|
||||||
|
int A(int f(), int n) {
|
||||||
|
if (n < N) {
|
||||||
|
return f(f, n + 1) - 1;
|
||||||
|
} else {
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int (*Ap)(int (*)(), int) = A;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
ShowCrashReports();
|
||||||
|
return !!Ap(Ap, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
error: Uncaught SIGSEGV (Stack Overflow) on rhel5 pid 368
|
||||||
|
./o//examples/stackoverflow.com
|
||||||
|
EUNKNOWN[No error information][0]
|
||||||
|
Linux rhel5 2.6.18-8.el5 #1 SMP Thu Mar 15 19:46:53 EDT 2007
|
||||||
|
|
||||||
|
0x0000000000406896: A at examples/stackoverflow.c:24
|
||||||
|
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||||
|
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||||
|
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||||
|
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||||
|
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||||
|
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||||
|
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||||
|
0x0000000000406898: A at examples/stackoverflow.c:24
|
||||||
|
etc. etc.
|
||||||
|
|
||||||
|
RAX 0000000000000000 RBX 0000000000000001 RDI 000000000040687e ST(0) 0.0
|
||||||
|
RCX 0000000000417125 RDX 000000000041cd70 RSI 0000000000000efe ST(1) 0.0
|
||||||
|
RBP 00006ffffffe1000 RSP 00006ffffffe1000 RIP 0000000000406897 ST(2) 0.0
|
||||||
|
R8 0000000000000000 R9 0000000000000022 R10 0000000000000008 ST(3) 0.0
|
||||||
|
R11 0000000000000293 R12 0000000000000001 R13 00007ffc70b4fc48 ST(4) 0.0
|
||||||
|
R14 00007ffc70b4fc58 R15 00007ffc70b4fd18 VF IF
|
||||||
|
|
||||||
|
XMM0 00000000000000000000000000000000 XMM8 00000000000000000000000000000000
|
||||||
|
XMM1 ffffffffffffeb030000000000000000 XMM9 00000000000000000000000000000000
|
||||||
|
XMM2 0000000000000000ffffffffffffffff XMM10 00000000000000000000000000000000
|
||||||
|
XMM3 00000000000000000000000000000000 XMM11 00000000000000000000000000000000
|
||||||
|
XMM4 00000000000000000000000000000000 XMM12 00000000000000000000000000000000
|
||||||
|
XMM5 00000000000000000000000000000000 XMM13 00000000000000000000000000000000
|
||||||
|
XMM6 00000000000000000000000000000000 XMM14 00000000000000000000000000000000
|
||||||
|
XMM7 00000000000000000000000000000000 XMM15 00000000000000000000000000000000
|
||||||
|
|
||||||
|
100080000000-100080030000 rw-pa-- 3x automap
|
||||||
|
6ffffffe0000-6fffffff0000 rw-paSF 1x stack
|
||||||
|
# 4 frames mapped w/ 0 frames gapped
|
||||||
|
*/
|
|
@ -602,30 +602,16 @@
|
||||||
* shell. If SHELL is defined, we try to map the standard UNIX library
|
* shell. If SHELL is defined, we try to map the standard UNIX library
|
||||||
* routines to ash routines using defines.
|
* routines to ash routines using defines.
|
||||||
*/
|
*/
|
||||||
/* #undef stdout /\* TODO(jart): XXX *\/ */
|
#define Printf out1fmt
|
||||||
/* #undef stderr */
|
|
||||||
/* #undef putc */
|
|
||||||
/* #undef putchar */
|
|
||||||
#undef fileno
|
|
||||||
/* #define stdout out1 */
|
|
||||||
/* #define stderr out2 */
|
|
||||||
#undef printf
|
|
||||||
#define printf out1fmt
|
|
||||||
/* #define putc(c, file) outc(c, file) */
|
|
||||||
/* #define putchar(c) out1c(c) */
|
|
||||||
#define FILE struct output
|
|
||||||
#define fileno(f) ((f)->fd)
|
|
||||||
/* #define ferror outerr */
|
|
||||||
#define INITARGS(argv)
|
#define INITARGS(argv)
|
||||||
#define setprogname(s)
|
#define setprogname(s)
|
||||||
#define getprogname() commandname
|
#define getprogname() commandname
|
||||||
|
|
||||||
#define setlocate(l, s) 0
|
#define setlocate(l, s) 0
|
||||||
#define equal(s1, s2) (strcmp(s1, s2) == 0)
|
#define equal(s1, s2) (!strcmp(s1, s2))
|
||||||
/* #define getenv(p) bltinlookup((p), 0) */
|
#define isodigit(c) ((c) >= '0' && (c) <= '7')
|
||||||
#define isodigit(c) ((c) >= '0' && (c) <= '7')
|
#define octtobin(c) ((c) - '0')
|
||||||
#define octtobin(c) ((c) - '0')
|
#define scopy(s1, s2) ((void)strcpy(s2, s1))
|
||||||
#define scopy(s1, s2) ((void)strcpy(s2, s1))
|
|
||||||
|
|
||||||
#define TRACE(param)
|
#define TRACE(param)
|
||||||
/* #define TRACE(param) \ */
|
/* #define TRACE(param) \ */
|
||||||
|
@ -9483,13 +9469,13 @@ static void sigblockall(sigset_t *oldmask) {
|
||||||
{ \
|
{ \
|
||||||
switch ((char *)param - (char *)array) { \
|
switch ((char *)param - (char *)array) { \
|
||||||
default: \
|
default: \
|
||||||
(void)printf(f, array[0], array[1], func); \
|
(void)Printf(f, array[0], array[1], func); \
|
||||||
break; \
|
break; \
|
||||||
case sizeof(*param): \
|
case sizeof(*param): \
|
||||||
(void)printf(f, array[0], func); \
|
(void)Printf(f, array[0], func); \
|
||||||
break; \
|
break; \
|
||||||
case 0: \
|
case 0: \
|
||||||
(void)printf(f, func); \
|
(void)Printf(f, func); \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
@ -10118,7 +10104,7 @@ static int timescmd() {
|
||||||
struct tms buf;
|
struct tms buf;
|
||||||
long int clk_tck = sysconf(_SC_CLK_TCK);
|
long int clk_tck = sysconf(_SC_CLK_TCK);
|
||||||
times(&buf);
|
times(&buf);
|
||||||
printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", (int)(buf.tms_utime / clk_tck / 60),
|
Printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", (int)(buf.tms_utime / clk_tck / 60),
|
||||||
((double)buf.tms_utime) / clk_tck, (int)(buf.tms_stime / clk_tck / 60),
|
((double)buf.tms_utime) / clk_tck, (int)(buf.tms_stime / clk_tck / 60),
|
||||||
((double)buf.tms_stime) / clk_tck, (int)(buf.tms_cutime / clk_tck / 60),
|
((double)buf.tms_stime) / clk_tck, (int)(buf.tms_cutime / clk_tck / 60),
|
||||||
((double)buf.tms_cutime) / clk_tck, (int)(buf.tms_cstime / clk_tck / 60),
|
((double)buf.tms_cutime) / clk_tck, (int)(buf.tms_cstime / clk_tck / 60),
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
#include "libc/calls/struct/rlimit.h"
|
#include "libc/calls/struct/rlimit.h"
|
||||||
#include "libc/calls/struct/rusage.h"
|
#include "libc/calls/struct/rusage.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
|
#include "libc/calls/struct/sigset.h"
|
||||||
#include "libc/calls/struct/sigval.h"
|
#include "libc/calls/struct/sigval.h"
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/calls/struct/sysinfo.h"
|
#include "libc/calls/struct/sysinfo.h"
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/calls/struct/tms.h"
|
#include "libc/calls/struct/tms.h"
|
||||||
#include "libc/calls/struct/utsname.h"
|
#include "libc/calls/struct/utsname.h"
|
||||||
#include "libc/calls/typedef/sighandler_t.h"
|
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/pflink.h"
|
#include "libc/fmt/pflink.h"
|
||||||
#include "libc/sysv/consts/s.h"
|
#include "libc/sysv/consts/s.h"
|
||||||
|
@ -178,7 +178,6 @@ int setreuid(uint32_t, uint32_t);
|
||||||
int setrlimit(int, const struct rlimit *);
|
int setrlimit(int, const struct rlimit *);
|
||||||
int setsid(void);
|
int setsid(void);
|
||||||
int setuid(uint32_t);
|
int setuid(uint32_t);
|
||||||
int sigaction(int, const struct sigaction *, struct sigaction *);
|
|
||||||
int sigignore(int);
|
int sigignore(int);
|
||||||
int siginterrupt(int, int);
|
int siginterrupt(int, int);
|
||||||
int sigprocmask(int, const struct sigset *, struct sigset *);
|
int sigprocmask(int, const struct sigset *, struct sigset *);
|
||||||
|
@ -206,7 +205,6 @@ intptr_t syscall(int, ...);
|
||||||
long ptrace(int, int, void *, void *);
|
long ptrace(int, int, void *, void *);
|
||||||
long telldir(DIR *);
|
long telldir(DIR *);
|
||||||
long times(struct tms *);
|
long times(struct tms *);
|
||||||
sighandler_t signal(int, sighandler_t);
|
|
||||||
size_t GetFileSize(const char *);
|
size_t GetFileSize(const char *);
|
||||||
size_t getfiledescriptorsize(int);
|
size_t getfiledescriptorsize(int);
|
||||||
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
|
ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t);
|
||||||
|
@ -247,51 +245,6 @@ int vdprintf(int, const char *, va_list) paramsnonnull();
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
|
|
||||||
void _init_onntconsoleevent(void);
|
|
||||||
void _init_wincrash(void);
|
|
||||||
|
|
||||||
#ifndef __SIGACTION_YOINK
|
|
||||||
#define __SIGACTION_YOINK(SIG) \
|
|
||||||
do { \
|
|
||||||
if (SupportsWindows()) { \
|
|
||||||
if (__builtin_constant_p(SIG)) { \
|
|
||||||
switch (SIG) { \
|
|
||||||
case SIGINT: \
|
|
||||||
case SIGQUIT: \
|
|
||||||
case SIGHUP: \
|
|
||||||
case SIGTERM: \
|
|
||||||
YOINK(_init_onntconsoleevent); \
|
|
||||||
break; \
|
|
||||||
case SIGTRAP: \
|
|
||||||
case SIGILL: \
|
|
||||||
case SIGSEGV: \
|
|
||||||
case SIGABRT: \
|
|
||||||
case SIGFPE: \
|
|
||||||
YOINK(_init_wincrash); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} else { \
|
|
||||||
YOINK(_init_onntconsoleevent); \
|
|
||||||
YOINK(_init_wincrash); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define sigaction(SIG, ACT, OLD) \
|
|
||||||
({ \
|
|
||||||
__SIGACTION_YOINK(SIG); \
|
|
||||||
sigaction(SIG, (ACT), OLD); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define signal(SIG, HAND) \
|
|
||||||
({ \
|
|
||||||
__SIGACTION_YOINK(SIG); \
|
|
||||||
signal(SIG, HAND); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define dprintf(FD, FMT, ...) (dprintf)(FD, PFLINK(FMT), ##__VA_ARGS__)
|
#define dprintf(FD, FMT, ...) (dprintf)(FD, PFLINK(FMT), ##__VA_ARGS__)
|
||||||
#define vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA)
|
#define vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA)
|
||||||
|
|
||||||
|
|
|
@ -18,39 +18,55 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static noasan bool AccessCommand(char path[hasatleast PATH_MAX],
|
static noasan bool EndsWithIgnoreCase(const char *p, size_t n, const char *s) {
|
||||||
const char *name, size_t namelen,
|
size_t i, m;
|
||||||
size_t pathlen) {
|
m = __strlen(s);
|
||||||
if (pathlen + 1 + namelen + 1 + 4 + 1 > PATH_MAX) return -1;
|
if (n >= m) {
|
||||||
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
|
for (i = n - m; i < n; ++i) {
|
||||||
path[pathlen] = !IsWindows() ? '/'
|
if (kToLower[p[i] & 255] != (*s++ & 255)) {
|
||||||
: memchr(path, '\\', pathlen) ? '\\'
|
return false;
|
||||||
: '/';
|
}
|
||||||
pathlen++;
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
memcpy(path + pathlen, name, namelen + 1);
|
|
||||||
if (isexecutable(path)) return true;
|
|
||||||
memcpy(path + pathlen + namelen, ".com", 5);
|
|
||||||
if (isexecutable(path)) return true;
|
|
||||||
memcpy(path + pathlen + namelen, ".exe", 5);
|
|
||||||
if (isexecutable(path)) return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static noasan bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
|
static noasan bool AccessCommand(const char *name,
|
||||||
size_t namelen) {
|
char path[hasatleast PATH_MAX], size_t namelen,
|
||||||
|
const char *suffix, size_t pathlen) {
|
||||||
|
size_t suffixlen;
|
||||||
|
suffixlen = __strlen(suffix);
|
||||||
|
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return -1;
|
||||||
|
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
|
||||||
|
path[pathlen] = !IsWindows() ? '/'
|
||||||
|
: __memchr(path, '\\', pathlen) ? '\\'
|
||||||
|
: '/';
|
||||||
|
pathlen++;
|
||||||
|
}
|
||||||
|
__repmovsb(path + pathlen, name, namelen);
|
||||||
|
__repmovsb(path + pathlen + namelen, suffix, suffixlen + 1);
|
||||||
|
return isexecutable(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
|
||||||
|
size_t namelen, const char *suffix) {
|
||||||
size_t i;
|
size_t i;
|
||||||
const char *p;
|
const char *p;
|
||||||
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
|
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) {
|
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) {
|
||||||
if (i < PATH_MAX) path[i] = p[i];
|
if (i < PATH_MAX) {
|
||||||
|
path[i] = p[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (AccessCommand(path, name, namelen, i)) {
|
if (AccessCommand(name, path, namelen, suffix, i)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (p[i] == ':' || p[i] == ';') {
|
if (p[i] == ':' || p[i] == ';') {
|
||||||
|
@ -62,6 +78,23 @@ static noasan bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
|
||||||
return false;
|
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);
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves full pathname of executable.
|
* Resolves full pathname of executable.
|
||||||
*
|
*
|
||||||
|
@ -72,40 +105,28 @@ static noasan bool SearchPath(char path[hasatleast PATH_MAX], const char *name,
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
|
||||||
char *p;
|
int olderr;
|
||||||
size_t namelen;
|
size_t namelen;
|
||||||
int rc, olderr;
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
efault();
|
efault();
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!(namelen = strlen(name))) {
|
if (!(namelen = __strlen(name))) {
|
||||||
enoent();
|
enoent();
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
if (namelen + 1 > PATH_MAX) {
|
if (namelen + 1 > PATH_MAX) {
|
||||||
enametoolong();
|
enametoolong();
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
if (strchr(name, '/') || strchr(name, '\\')) {
|
if (FindCommand(name, pathbuf, namelen, "") ||
|
||||||
if (AccessCommand(strcpy(pathbuf, ""), name, namelen, 0)) {
|
(!EndsWithIgnoreCase(name, namelen, ".exe") &&
|
||||||
return pathbuf;
|
!EndsWithIgnoreCase(name, namelen, ".com") &&
|
||||||
} else {
|
!EndsWithIgnoreCase(name, namelen, ".com.dbg") &&
|
||||||
return NULL;
|
(FindCommand(name, pathbuf, namelen, ".com") ||
|
||||||
}
|
FindCommand(name, pathbuf, namelen, ".exe")))) {
|
||||||
}
|
|
||||||
olderr = errno;
|
|
||||||
if ((IsWindows() &&
|
|
||||||
(AccessCommand(pathbuf, name, namelen,
|
|
||||||
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
|
|
||||||
AccessCommand(pathbuf, name, namelen,
|
|
||||||
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf) ||
|
|
||||||
AccessCommand(pathbuf, name, namelen,
|
|
||||||
stpcpy(pathbuf, ".") - pathbuf))) ||
|
|
||||||
SearchPath(pathbuf, name, namelen)) {
|
|
||||||
errno = olderr;
|
|
||||||
return pathbuf;
|
return pathbuf;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
static void __ensurefds_destroy(void) {
|
||||||
|
weaken(free)(g_fds.p);
|
||||||
|
}
|
||||||
|
|
||||||
int __ensurefds(int fd) {
|
int __ensurefds(int fd) {
|
||||||
size_t n1, n2;
|
size_t n1, n2;
|
||||||
struct Fd *p1, *p2;
|
struct Fd *p1, *p2;
|
||||||
|
@ -36,9 +40,15 @@ int __ensurefds(int fd) {
|
||||||
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
||||||
memcpy(p2, p1, n1 * sizeof(*p1));
|
memcpy(p2, p1, n1 * sizeof(*p1));
|
||||||
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
|
bzero(p2 + n1, (n2 - n1) * sizeof(*p1));
|
||||||
if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1);
|
|
||||||
if (cmpxchg(&g_fds.p, p1, p2)) {
|
if (cmpxchg(&g_fds.p, p1, p2)) {
|
||||||
g_fds.n = n2;
|
g_fds.n = n2;
|
||||||
|
if (weaken(free)) {
|
||||||
|
if (p1 == g_fds.__init_p) {
|
||||||
|
atexit(__ensurefds_destroy);
|
||||||
|
} else {
|
||||||
|
weaken(free)(p1);
|
||||||
|
}
|
||||||
|
}
|
||||||
return fd;
|
return fd;
|
||||||
} else if (weaken(free)) {
|
} else if (weaken(free)) {
|
||||||
weaken(free)(p2);
|
weaken(free)(p2);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
@ -42,15 +43,18 @@ char *getcwd(char *buf, size_t size) {
|
||||||
if (buf) {
|
if (buf) {
|
||||||
p = buf;
|
p = buf;
|
||||||
if (!size) {
|
if (!size) {
|
||||||
|
SYSDEBUG("getcwd(%p, %x) EINVAL", buf, size);
|
||||||
einval();
|
einval();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (weaken(malloc)) {
|
} else if (weaken(malloc)) {
|
||||||
if (!size) size = PATH_MAX + 1;
|
if (!size) size = PATH_MAX + 1;
|
||||||
if (!(p = weaken(malloc)(size))) {
|
if (!(p = weaken(malloc)(size))) {
|
||||||
|
SYSDEBUG("getcwd(%p, %x) ENOMEM", buf, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
SYSDEBUG("getcwd() EINVAL needs buf≠0 or STATIC_YOINK(\"malloc\")");
|
||||||
einval();
|
einval();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -81,5 +85,6 @@ char *getcwd(char *buf, size_t size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SYSDEBUG("getcwd(%p, %x) -> %s", buf, size, r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/calls/struct/timeval.h"
|
#include "libc/calls/struct/timeval.h"
|
||||||
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
@ -115,6 +116,7 @@ i32 __sys_fcntl(i32, i32, ...) hidden;
|
||||||
i32 __sys_fstat(i32, void *) hidden;
|
i32 __sys_fstat(i32, void *) hidden;
|
||||||
i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
|
i32 __sys_fstatat(i32, const char *, void *, i32) hidden;
|
||||||
i32 __sys_getrusage(i32, struct rusage *) hidden;
|
i32 __sys_getrusage(i32, struct rusage *) hidden;
|
||||||
|
i32 __sys_munmap(void *, u64) hidden;
|
||||||
i32 __sys_openat(i32, const char *, i32, u32) hidden;
|
i32 __sys_openat(i32, const char *, i32, u32) hidden;
|
||||||
i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
|
i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
|
||||||
i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden;
|
i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden;
|
||||||
|
@ -177,6 +179,7 @@ i32 sys_setresuid(uint32_t, uint32_t, uint32_t) hidden;
|
||||||
i32 sys_setrlimit(i32, const struct rlimit *) hidden;
|
i32 sys_setrlimit(i32, const struct rlimit *) hidden;
|
||||||
i32 sys_setsid(void) hidden;
|
i32 sys_setsid(void) hidden;
|
||||||
i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden;
|
i32 sys_sigaction(i32, const void *, void *, i64, i64) hidden;
|
||||||
|
i32 sys_sigaltstack(const void *, void *) hidden;
|
||||||
i32 sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden;
|
i32 sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden;
|
||||||
i32 sys_sigqueue(i32, i32, const union sigval) hidden;
|
i32 sys_sigqueue(i32, i32, const union sigval) hidden;
|
||||||
i32 sys_sigqueueinfo(i32, const siginfo_t *) hidden;
|
i32 sys_sigqueueinfo(i32, const siginfo_t *) hidden;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/nt/struct/ipadapteraddresses.h"
|
#include "libc/nt/struct/ipadapteraddresses.h"
|
||||||
#include "libc/nt/winsock.h"
|
#include "libc/nt/winsock.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
@ -239,6 +241,7 @@ struct HostAdapterInfoNode *appendHostInfo(
|
||||||
|
|
||||||
/* Returns -1 in case of failure */
|
/* Returns -1 in case of failure */
|
||||||
static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
|
static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
|
||||||
|
static bool once;
|
||||||
struct NtIpAdapterAddresses *aa;
|
struct NtIpAdapterAddresses *aa;
|
||||||
struct NtIpAdapterUnicastAddress *ua;
|
struct NtIpAdapterUnicastAddress *ua;
|
||||||
struct NtIpAdapterPrefix *ap;
|
struct NtIpAdapterPrefix *ap;
|
||||||
|
@ -270,7 +273,12 @@ static int createHostInfo(struct NtIpAdapterAddresses *firstAdapter) {
|
||||||
(ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) {
|
(ua != NULL) && (count < MAX_UNICAST_ADDR); ++count) {
|
||||||
node = appendHostInfo(node, baseName, aa, &ua, &ap, count);
|
node = appendHostInfo(node, baseName, aa, &ua, &ap, count);
|
||||||
if (!node) goto err;
|
if (!node) goto err;
|
||||||
if (!__hostInfo) __hostInfo = node;
|
if (!__hostInfo) {
|
||||||
|
__hostInfo = node;
|
||||||
|
if (cmpxchg(&once, false, true)) {
|
||||||
|
atexit(freeHostInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: do we need to process the remaining adapter prefix?
|
/* Note: do we need to process the remaining adapter prefix?
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/ntmagicpaths.internal.h"
|
#include "libc/calls/ntmagicpaths.internal.h"
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/nt/systeminfo.h"
|
#include "libc/nt/systeminfo.h"
|
||||||
#include "libc/str/oldutf16.internal.h"
|
#include "libc/str/oldutf16.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
@ -94,7 +95,10 @@ textwindows int __mkntpath2(const char *path,
|
||||||
m = 0;
|
m = 0;
|
||||||
}
|
}
|
||||||
n = tprecode8to16(p, z, q).ax;
|
n = tprecode8to16(p, z, q).ax;
|
||||||
if (n == z - 1) return enametoolong();
|
if (n == z - 1) {
|
||||||
|
SYSDEBUG("path too long for windows: %s", path);
|
||||||
|
return enametoolong();
|
||||||
|
}
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
if (p[i] == '/') {
|
if (p[i] == '/') {
|
||||||
p[i] = '\\';
|
p[i] = '\\';
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
@ -33,7 +34,10 @@ int __mkntpathat(int dirfd, const char *path, int flags,
|
||||||
dirlen = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
dirlen = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||||
kNtFileNameNormalized | kNtVolumeNameDos);
|
kNtFileNameNormalized | kNtVolumeNameDos);
|
||||||
if (!dirlen) return __winerr();
|
if (!dirlen) return __winerr();
|
||||||
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) return enametoolong();
|
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) {
|
||||||
|
SYSDEBUG("path too long: %.*hs\\%.*hs", dirlen, dir, filelen, file);
|
||||||
|
return enametoolong();
|
||||||
|
}
|
||||||
dir[dirlen] = u'\\';
|
dir[dirlen] = u'\\';
|
||||||
memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t));
|
memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t));
|
||||||
memcpy(file, dir, (dirlen + 1 + filelen + 1) * sizeof(char16_t));
|
memcpy(file, dir, (dirlen + 1 + filelen + 1) * sizeof(char16_t));
|
||||||
|
|
|
@ -34,7 +34,7 @@ extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||||
* @return 0 on success, or -1 w/ errno
|
* @return 0 on success, or -1 w/ errno
|
||||||
* @see mmap()
|
* @see mmap()
|
||||||
*/
|
*/
|
||||||
privileged int mprotect(void *addr, uint64_t len, int prot) {
|
noasan noubsan privileged int mprotect(void *addr, uint64_t len, int prot) {
|
||||||
bool cf;
|
bool cf;
|
||||||
int64_t rc;
|
int64_t rc;
|
||||||
uint32_t oldprot;
|
uint32_t oldprot;
|
||||||
|
|
|
@ -95,7 +95,7 @@ textwindows int ntspawn(
|
||||||
} else {
|
} else {
|
||||||
__winerr();
|
__winerr();
|
||||||
}
|
}
|
||||||
SYSDEBUG("CreateProcess(`%S`, `%S`) -> %d", prog16, block->cmdline, rc);
|
SYSDEBUG("CreateProcess(`%hs`, `%hs`) -> %d", prog16, block->cmdline, rc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
__winerr();
|
__winerr();
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/calls/sysdebug.internal.h"
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/fd.h"
|
#include "libc/sysv/consts/fd.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
@ -59,9 +60,11 @@ int sys_openat(int dirfd, const char *file, int flags, unsigned mode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (d != -1) {
|
if (d != -1) {
|
||||||
SYSDEBUG("sys_openat(0x%x, %s, %d, %d) -> %d", dirfd, file, flags, mode, d);
|
SYSDEBUG("sys_openat(%d, %s, %d, %d) -> %d", (long)dirfd, file, flags,
|
||||||
|
(flags & (O_CREAT | O_TMPFILE)) ? mode : 0, d);
|
||||||
} else {
|
} else {
|
||||||
SYSDEBUG("sys_openat(0x%x, %s, %d, %d) -> %m", dirfd, file, flags, mode);
|
SYSDEBUG("sys_openat(%d, %s, %d, %d) -> %s", (long)dirfd, file, flags,
|
||||||
|
(flags & (O_CREAT | O_TMPFILE)) ? mode : 0, strerror(errno));
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,8 +153,17 @@ ssize_t readansi(int fd, char *p, size_t n) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kEsc:
|
case kEsc:
|
||||||
if (0x20 <= c && c <= 0x2f) {
|
if (0x20 <= c && c <= 0x2f) { /* Nf */
|
||||||
t = kNf;
|
/*
|
||||||
|
* Almost no one uses ANSI Nf sequences
|
||||||
|
* They overlaps with alt+graphic keystrokes
|
||||||
|
* We care more about being able to type alt-/
|
||||||
|
*/
|
||||||
|
if (c == ' ' || c == '#') {
|
||||||
|
t = kNf;
|
||||||
|
} else {
|
||||||
|
t = kDone;
|
||||||
|
}
|
||||||
} else if (0x30 <= c && c <= 0x3f) { /* Fp */
|
} else if (0x30 <= c && c <= 0x3f) { /* Fp */
|
||||||
t = kDone;
|
t = kDone;
|
||||||
} else if (0x20 <= c && c <= 0x5F) { /* Fe */
|
} else if (0x20 <= c && c <= 0x5F) { /* Fe */
|
||||||
|
@ -173,8 +182,6 @@ ssize_t readansi(int fd, char *p, size_t n) {
|
||||||
case '_': /* DCS (Application Program Command) */
|
case '_': /* DCS (Application Program Command) */
|
||||||
t = kStr;
|
t = kStr;
|
||||||
break;
|
break;
|
||||||
case '\\':
|
|
||||||
goto Whoopsie;
|
|
||||||
default:
|
default:
|
||||||
t = kDone;
|
t = kDone;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/nexgen32e/bsr.h"
|
#include "libc/nexgen32e/bsr.h"
|
||||||
#include "libc/nt/createfile.h"
|
#include "libc/nt/createfile.h"
|
||||||
|
@ -37,7 +38,9 @@
|
||||||
|
|
||||||
static textwindows ssize_t sys_readlinkat_nt_error(void) {
|
static textwindows ssize_t sys_readlinkat_nt_error(void) {
|
||||||
uint32_t e;
|
uint32_t e;
|
||||||
switch ((e = GetLastError())) {
|
e = GetLastError();
|
||||||
|
SYSDEBUG("sys_readlinkat_nt() error %d", e);
|
||||||
|
switch (e) {
|
||||||
case kNtErrorNotAReparsePoint:
|
case kNtErrorNotAReparsePoint:
|
||||||
return einval();
|
return einval();
|
||||||
default:
|
default:
|
||||||
|
@ -56,7 +59,10 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
||||||
uint32_t e, i, j, n, mem;
|
uint32_t e, i, j, n, mem;
|
||||||
char16_t path16[PATH_MAX], *p;
|
char16_t path16[PATH_MAX], *p;
|
||||||
struct NtReparseDataBuffer *rdb;
|
struct NtReparseDataBuffer *rdb;
|
||||||
if (!buf) return efault();
|
if (__mkntpathat(dirfd, path, 0, path16) == -1) {
|
||||||
|
SYSDEBUG("sys_readlinkat_nt() failed b/c __mkntpathat() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (weaken(malloc)) {
|
if (weaken(malloc)) {
|
||||||
mem = 16384;
|
mem = 16384;
|
||||||
rdb = weaken(malloc)(mem);
|
rdb = weaken(malloc)(mem);
|
||||||
|
@ -66,9 +72,9 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
||||||
rdb = (struct NtReparseDataBuffer *)buf;
|
rdb = (struct NtReparseDataBuffer *)buf;
|
||||||
freeme = 0;
|
freeme = 0;
|
||||||
} else {
|
} else {
|
||||||
|
SYSDEBUG("sys_readlinkat_nt() needs bigger buffer malloc() to be yoinked");
|
||||||
return enomem();
|
return enomem();
|
||||||
}
|
}
|
||||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
|
||||||
if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting,
|
if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting,
|
||||||
kNtFileFlagOpenReparsePoint | kNtFileFlagBackupSemantics,
|
kNtFileFlagOpenReparsePoint | kNtFileFlagBackupSemantics,
|
||||||
0)) != -1) {
|
0)) != -1) {
|
||||||
|
@ -107,16 +113,20 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
||||||
if (freeme || (intptr_t)(buf + j) <= (intptr_t)(p + i)) {
|
if (freeme || (intptr_t)(buf + j) <= (intptr_t)(p + i)) {
|
||||||
rc = j;
|
rc = j;
|
||||||
} else {
|
} else {
|
||||||
|
SYSDEBUG("sys_readlinkat_nt() too many astral codepoints");
|
||||||
rc = enametoolong();
|
rc = enametoolong();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
SYSDEBUG("sys_readlinkat_nt() should have kNtIoReparseTagSymlink");
|
||||||
rc = einval();
|
rc = einval();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
SYSDEBUG("DeviceIoControl(kNtFsctlGetReparsePoint) failed");
|
||||||
rc = sys_readlinkat_nt_error();
|
rc = sys_readlinkat_nt_error();
|
||||||
}
|
}
|
||||||
CloseHandle(h);
|
CloseHandle(h);
|
||||||
} else {
|
} else {
|
||||||
|
SYSDEBUG("CreateFile(kNtFileFlagOpenReparsePoint) failed");
|
||||||
rc = sys_readlinkat_nt_error();
|
rc = sys_readlinkat_nt_error();
|
||||||
}
|
}
|
||||||
if (freeme && weaken(free)) {
|
if (freeme && weaken(free)) {
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/asan.internal.h"
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/at.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/zipos/zipos.internal.h"
|
#include "libc/zipos/zipos.internal.h"
|
||||||
|
@ -46,14 +49,19 @@
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
|
ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
|
||||||
|
ssize_t bytes;
|
||||||
struct ZiposUri zipname;
|
struct ZiposUri zipname;
|
||||||
if (IsAsan() && !__asan_is_valid(buf, bufsiz)) return efault();
|
if ((IsAsan() && !__asan_is_valid(buf, bufsiz)) || (bufsiz && !buf)) {
|
||||||
if (weaken(__zipos_notat) && __zipos_notat(dirfd, path) == -1) {
|
bytes = efault();
|
||||||
return -1; /* TODO(jart): code me */
|
} else if (weaken(__zipos_notat) && __zipos_notat(dirfd, path) == -1) {
|
||||||
}
|
SYSDEBUG("TOOD: zipos support for readlinkat");
|
||||||
if (!IsWindows()) {
|
bytes = enosys(); /* TODO(jart): code me */
|
||||||
return sys_readlinkat(dirfd, path, buf, bufsiz);
|
} else if (!IsWindows()) {
|
||||||
|
bytes = sys_readlinkat(dirfd, path, buf, bufsiz);
|
||||||
} else {
|
} else {
|
||||||
return sys_readlinkat_nt(dirfd, path, buf, bufsiz);
|
bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz);
|
||||||
}
|
}
|
||||||
|
SYSDEBUG("readlinkat(%d, %s, 0x%p, 0x%x) -> %d %s", (long)dirfd, path, buf,
|
||||||
|
bufsiz, bytes, bytes != -1 ? "" : strerror(errno));
|
||||||
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
@ -160,6 +161,7 @@ restart:
|
||||||
if (!check_dir) goto skip_readlink;
|
if (!check_dir) goto skip_readlink;
|
||||||
}
|
}
|
||||||
k = readlink(output, stack, p);
|
k = readlink(output, stack, p);
|
||||||
|
if (k<0) SYSDEBUG("realpath readlink failed %d", (long)errno);
|
||||||
if (k==p) goto toolong;
|
if (k==p) goto toolong;
|
||||||
if (!k) {
|
if (!k) {
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
|
|
106
libc/calls/sigaltstack.c
Normal file
106
libc/calls/sigaltstack.c
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/struct/metasigaltstack.h"
|
||||||
|
#include "libc/calls/struct/sigaltstack.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/asan.internal.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
|
||||||
|
const struct sigaltstack *linux) {
|
||||||
|
void *sp;
|
||||||
|
int flags;
|
||||||
|
size_t size;
|
||||||
|
sp = linux->ss_sp;
|
||||||
|
flags = linux->ss_flags;
|
||||||
|
size = linux->ss_size;
|
||||||
|
bsd->ss_sp = sp;
|
||||||
|
bsd->ss_flags = flags;
|
||||||
|
bsd->ss_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noasan void sigaltstack2linux(struct sigaltstack *linux,
|
||||||
|
const struct sigaltstack_bsd *bsd) {
|
||||||
|
void *sp;
|
||||||
|
int flags;
|
||||||
|
size_t size;
|
||||||
|
sp = bsd->ss_sp;
|
||||||
|
flags = bsd->ss_flags;
|
||||||
|
size = bsd->ss_size;
|
||||||
|
linux->ss_sp = sp;
|
||||||
|
linux->ss_flags = flags;
|
||||||
|
linux->ss_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets and/or gets alternate signal stack, e.g.
|
||||||
|
*
|
||||||
|
* struct sigaction sa;
|
||||||
|
* struct sigaltstack ss;
|
||||||
|
* ss.ss_flags = 0;
|
||||||
|
* ss.ss_size = SIGSTKSZ;
|
||||||
|
* ss.ss_sp = malloc(ss.ss_size);
|
||||||
|
* sa.sa_flags = SA_ONSTACK;
|
||||||
|
* sa.sa_handler = OnStackOverflow;
|
||||||
|
* __cxa_atexit(free, ss[0].ss_sp, 0);
|
||||||
|
* sigemptyset(&sa.ss_mask);
|
||||||
|
* sigaltstack(&ss, 0);
|
||||||
|
* sigaction(SIGSEGV, &sa, 0);
|
||||||
|
*
|
||||||
|
* @param neu if non-null will install new signal alt stack
|
||||||
|
* @param old if non-null will receive current signal alt stack
|
||||||
|
* @return 0 on success, or -1 w/ errno
|
||||||
|
*/
|
||||||
|
noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
|
||||||
|
int rc;
|
||||||
|
void *a, *b;
|
||||||
|
struct sigaltstack_bsd bsd;
|
||||||
|
if (IsAsan() && ((old && __asan_check(old, sizeof(*old)).kind) ||
|
||||||
|
(neu && (__asan_check(neu, sizeof(*neu)).kind ||
|
||||||
|
__asan_check(neu->ss_sp, neu->ss_size).kind)))) {
|
||||||
|
return efault();
|
||||||
|
}
|
||||||
|
if (IsLinux()) {
|
||||||
|
a = neu;
|
||||||
|
b = old;
|
||||||
|
} else if (IsBsd()) {
|
||||||
|
if (neu) {
|
||||||
|
sigaltstack2bsd(&bsd, neu);
|
||||||
|
a = &bsd;
|
||||||
|
} else {
|
||||||
|
a = 0;
|
||||||
|
}
|
||||||
|
if (old) {
|
||||||
|
b = &bsd;
|
||||||
|
} else {
|
||||||
|
b = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return enosys();
|
||||||
|
}
|
||||||
|
if ((rc = sys_sigaltstack(a, b)) != -1) {
|
||||||
|
if (old) {
|
||||||
|
sigaltstack2linux(old, &bsd);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,10 +18,13 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/struct/metasigaltstack.h"
|
||||||
#include "libc/calls/struct/siginfo.h"
|
#include "libc/calls/struct/siginfo.h"
|
||||||
|
#include "libc/calls/typedef/sigaction_f.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/intrin/repstosb.h"
|
#include "libc/intrin/repstosb.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/sa.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview XNU kernel callback normalization.
|
* @fileoverview XNU kernel callback normalization.
|
||||||
|
@ -45,12 +48,6 @@ struct __darwin_siginfo {
|
||||||
uint64_t __pad[7];
|
uint64_t __pad[7];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __darwin_sigaltstack {
|
|
||||||
void *ss_sp;
|
|
||||||
uint64_t ss_size;
|
|
||||||
int32_t ss_flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct __darwin_mmst_reg {
|
struct __darwin_mmst_reg {
|
||||||
char __mmst_reg[10];
|
char __mmst_reg[10];
|
||||||
char __mmst_rsrv[6];
|
char __mmst_rsrv[6];
|
||||||
|
@ -368,7 +365,7 @@ struct __darwin_mcontext64 {
|
||||||
struct __darwin_ucontext {
|
struct __darwin_ucontext {
|
||||||
int32_t uc_onstack;
|
int32_t uc_onstack;
|
||||||
uint32_t uc_sigmask;
|
uint32_t uc_sigmask;
|
||||||
struct __darwin_sigaltstack uc_stack;
|
struct sigaltstack_bsd uc_stack;
|
||||||
struct __darwin_ucontext *uc_link;
|
struct __darwin_ucontext *uc_link;
|
||||||
uint64_t uc_mcsize;
|
uint64_t uc_mcsize;
|
||||||
struct __darwin_mcontext64 *uc_mcontext;
|
struct __darwin_mcontext64 *uc_mcontext;
|
||||||
|
@ -387,7 +384,7 @@ noasan static void linuxexceptionstate2xnu(
|
||||||
}
|
}
|
||||||
|
|
||||||
noasan static void xnuthreadstate2linux(
|
noasan static void xnuthreadstate2linux(
|
||||||
ucontext_t *uc, mcontext_t *mc, struct __darwin_x86_thread_state64 *xnuss) {
|
mcontext_t *mc, struct __darwin_x86_thread_state64 *xnuss) {
|
||||||
mc->rdi = xnuss->__rdi;
|
mc->rdi = xnuss->__rdi;
|
||||||
mc->rsi = xnuss->__rsi;
|
mc->rsi = xnuss->__rsi;
|
||||||
mc->rbp = xnuss->__rbp;
|
mc->rbp = xnuss->__rbp;
|
||||||
|
@ -401,7 +398,6 @@ noasan static void xnuthreadstate2linux(
|
||||||
mc->gs = xnuss->__gs;
|
mc->gs = xnuss->__gs;
|
||||||
mc->fs = xnuss->__fs;
|
mc->fs = xnuss->__fs;
|
||||||
mc->eflags = xnuss->__rflags;
|
mc->eflags = xnuss->__rflags;
|
||||||
uc->uc_flags = xnuss->__rflags;
|
|
||||||
mc->r8 = xnuss->__r8;
|
mc->r8 = xnuss->__r8;
|
||||||
mc->r9 = xnuss->__r9;
|
mc->r9 = xnuss->__r9;
|
||||||
mc->r10 = xnuss->__r10;
|
mc->r10 = xnuss->__r10;
|
||||||
|
@ -427,7 +423,6 @@ noasan static void linuxthreadstate2xnu(
|
||||||
xnuss->__gs = mc->gs;
|
xnuss->__gs = mc->gs;
|
||||||
xnuss->__fs = mc->fs;
|
xnuss->__fs = mc->fs;
|
||||||
xnuss->__rflags = mc->eflags;
|
xnuss->__rflags = mc->eflags;
|
||||||
xnuss->__rflags = uc->uc_flags;
|
|
||||||
xnuss->__r8 = mc->r8;
|
xnuss->__r8 = mc->r8;
|
||||||
xnuss->__r9 = mc->r9;
|
xnuss->__r9 = mc->r9;
|
||||||
xnuss->__r10 = mc->r10;
|
xnuss->__r10 = mc->r10;
|
||||||
|
@ -484,6 +479,7 @@ noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
|
||||||
if (rva >= kSigactionMinRva) {
|
if (rva >= kSigactionMinRva) {
|
||||||
repstosb(&g, 0, sizeof(g));
|
repstosb(&g, 0, sizeof(g));
|
||||||
if (xnuctx) {
|
if (xnuctx) {
|
||||||
|
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
|
||||||
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;
|
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;
|
||||||
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
|
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
|
||||||
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
|
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
|
||||||
|
@ -498,8 +494,7 @@ noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
|
||||||
if (xnuctx->uc_mcsize >=
|
if (xnuctx->uc_mcsize >=
|
||||||
(sizeof(struct __darwin_x86_exception_state64) +
|
(sizeof(struct __darwin_x86_exception_state64) +
|
||||||
sizeof(struct __darwin_x86_thread_state64))) {
|
sizeof(struct __darwin_x86_thread_state64))) {
|
||||||
xnuthreadstate2linux(&g.uc, &g.uc.uc_mcontext,
|
xnuthreadstate2linux(&g.uc.uc_mcontext, &xnuctx->uc_mcontext->__ss);
|
||||||
&xnuctx->uc_mcontext->__ss);
|
|
||||||
}
|
}
|
||||||
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
|
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
|
||||||
xnussefpustate2linux(&g.uc.__fpustate, &xnuctx->uc_mcontext->__fs);
|
xnussefpustate2linux(&g.uc.__fpustate, &xnuctx->uc_mcontext->__fs);
|
||||||
|
|
15
libc/calls/struct/metasigaltstack.h
Normal file
15
libc/calls/struct/metasigaltstack.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_METASIGALTSTACK_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_METASIGALTSTACK_H_
|
||||||
|
#include "libc/calls/struct/sigaltstack.h"
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
struct sigaltstack_bsd {
|
||||||
|
void *ss_sp;
|
||||||
|
uint64_t ss_size;
|
||||||
|
int32_t ss_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_METASIGALTSTACK_H_ */
|
|
@ -14,7 +14,60 @@ struct sigaction { /* cosmo abi */
|
||||||
void (*sa_restorer)(void);
|
void (*sa_restorer)(void);
|
||||||
struct sigset sa_mask;
|
struct sigset sa_mask;
|
||||||
int64_t __pad;
|
int64_t __pad;
|
||||||
} forcealign(8);
|
};
|
||||||
|
|
||||||
|
sighandler_t signal(int, sighandler_t);
|
||||||
|
int sigaction(int, const struct sigaction *, struct sigaction *);
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
void _init_onntconsoleevent(void);
|
||||||
|
void _init_wincrash(void);
|
||||||
|
|
||||||
|
#ifndef __SIGACTION_YOINK
|
||||||
|
#define __SIGACTION_YOINK(SIG) \
|
||||||
|
do { \
|
||||||
|
if (SupportsWindows()) { \
|
||||||
|
if (__builtin_constant_p(SIG)) { \
|
||||||
|
switch (SIG) { \
|
||||||
|
case SIGINT: \
|
||||||
|
case SIGQUIT: \
|
||||||
|
case SIGHUP: \
|
||||||
|
case SIGTERM: \
|
||||||
|
YOINK(_init_onntconsoleevent); \
|
||||||
|
break; \
|
||||||
|
case SIGTRAP: \
|
||||||
|
case SIGILL: \
|
||||||
|
case SIGSEGV: \
|
||||||
|
case SIGABRT: \
|
||||||
|
case SIGFPE: \
|
||||||
|
YOINK(_init_wincrash); \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
YOINK(_init_onntconsoleevent); \
|
||||||
|
YOINK(_init_wincrash); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define sigaction(SIG, ACT, OLD) \
|
||||||
|
({ \
|
||||||
|
__SIGACTION_YOINK(SIG); \
|
||||||
|
sigaction(SIG, (ACT), OLD); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define signal(SIG, HAND) \
|
||||||
|
({ \
|
||||||
|
__SIGACTION_YOINK(SIG); \
|
||||||
|
signal(SIG, HAND); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif /* GNU && !ANSI */
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_H_ */
|
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_H_ */
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_
|
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_
|
||||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_
|
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
struct sigaltstack {
|
struct sigaltstack {
|
||||||
void *ss_sp;
|
void *ss_sp;
|
||||||
|
@ -10,5 +11,8 @@ struct sigaltstack {
|
||||||
|
|
||||||
typedef struct sigaltstack stack_t;
|
typedef struct sigaltstack stack_t;
|
||||||
|
|
||||||
|
int sigaltstack(const struct sigaltstack *, struct sigaltstack *);
|
||||||
|
|
||||||
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_ */
|
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_ */
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/weaken.h"
|
||||||
|
#include "libc/mem/internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +31,9 @@ int unsetenv(const char *s) {
|
||||||
for (j = 0;; ++j) {
|
for (j = 0;; ++j) {
|
||||||
if (!s[j]) {
|
if (!s[j]) {
|
||||||
if (p[i][j] == '=') {
|
if (p[i][j] == '=') {
|
||||||
|
if (weaken(__freeenv)) {
|
||||||
|
weaken(__freeenv)(p[i]);
|
||||||
|
}
|
||||||
k = i + 1;
|
k = i + 1;
|
||||||
do {
|
do {
|
||||||
p[k - 1] = p[k];
|
p[k - 1] = p[k];
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/struct/siginfo.h"
|
#include "libc/calls/struct/siginfo.h"
|
||||||
|
#include "libc/calls/typedef/sigaction_f.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sysdebug.internal.h"
|
#include "libc/calls/sysdebug.internal.h"
|
||||||
|
#include "libc/calls/typedef/sigaction_f.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
#include "libc/nt/enum/exceptionhandleractions.h"
|
#include "libc/nt/enum/exceptionhandleractions.h"
|
||||||
#include "libc/nt/enum/signal.h"
|
#include "libc/nt/enum/signal.h"
|
||||||
|
|
|
@ -16,10 +16,12 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/nt/errors.h"
|
#include "libc/nt/errors.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,8 +31,13 @@
|
||||||
* @note this is a code-size saving device
|
* @note this is a code-size saving device
|
||||||
*/
|
*/
|
||||||
privileged noasan int64_t __winerr(void) {
|
privileged noasan int64_t __winerr(void) {
|
||||||
|
errno_t e;
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
errno = GetLastError();
|
e = GetLastError();
|
||||||
|
if (weaken(__dos2errno)) {
|
||||||
|
e = weaken(__dos2errno)(e);
|
||||||
|
}
|
||||||
|
errno = e;
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return enosys();
|
return enosys();
|
||||||
|
|
|
@ -85,6 +85,7 @@ int LookupProtoByNumber(const int protonum, char *buf, size_t bufsize,
|
||||||
free(line);
|
free(line);
|
||||||
if (ferror(f)) {
|
if (ferror(f)) {
|
||||||
errno = ferror(f);
|
errno = ferror(f);
|
||||||
|
fclose(f);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
|
@ -17,7 +17,6 @@ COSMOPOLITAN_C_START_
|
||||||
int abs(int) libcesque pureconst;
|
int abs(int) libcesque pureconst;
|
||||||
long labs(long) libcesque pureconst;
|
long labs(long) libcesque pureconst;
|
||||||
long long llabs(long long) libcesque pureconst;
|
long long llabs(long long) libcesque pureconst;
|
||||||
int llog10(unsigned long) libcesque pureconst;
|
|
||||||
int atoi(const char *) paramsnonnull() libcesque;
|
int atoi(const char *) paramsnonnull() libcesque;
|
||||||
long atol(const char *) paramsnonnull() libcesque;
|
long atol(const char *) paramsnonnull() libcesque;
|
||||||
long long atoll(const char *) paramsnonnull() libcesque;
|
long long atoll(const char *) paramsnonnull() libcesque;
|
||||||
|
|
|
@ -42,6 +42,15 @@
|
||||||
|
|
||||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||||
|
|
||||||
|
static void __fmt_free_dtoa(char **mem) {
|
||||||
|
if (*mem) {
|
||||||
|
if (weaken(freedtoa)) {
|
||||||
|
weaken(freedtoa)(*mem);
|
||||||
|
}
|
||||||
|
*mem = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int __fmt_atoi(const char **str) {
|
static int __fmt_atoi(const char **str) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
|
for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
|
||||||
|
@ -135,11 +144,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
int (*out)(const char *, void *, size_t);
|
int (*out)(const char *, void *, size_t);
|
||||||
unsigned char signbit, log2base;
|
unsigned char signbit, log2base;
|
||||||
int c, d, k, w, n, i1, ui, bw, bex;
|
int c, d, k, w, n, i1, ui, bw, bex;
|
||||||
char *s, *q, *se, qchar, special[8];
|
char *s, *q, *se, *mem, qchar, special[8];
|
||||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
||||||
|
|
||||||
lasterr = errno;
|
lasterr = errno;
|
||||||
out = fn ? fn : (void *)missingno;
|
out = fn ? fn : (void *)missingno;
|
||||||
|
mem = 0;
|
||||||
|
|
||||||
while (*format) {
|
while (*format) {
|
||||||
if (*format != '%') {
|
if (*format != '%') {
|
||||||
|
@ -388,7 +398,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
p = "?";
|
p = "?";
|
||||||
goto FormatThatThing;
|
goto FormatThatThing;
|
||||||
}
|
}
|
||||||
s = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
|
assert(!mem);
|
||||||
|
s = mem = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
|
||||||
if (decpt == 9999) {
|
if (decpt == 9999) {
|
||||||
Format9999:
|
Format9999:
|
||||||
bzero(special, sizeof(special));
|
bzero(special, sizeof(special));
|
||||||
|
@ -402,6 +413,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
}
|
}
|
||||||
memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4);
|
memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4);
|
||||||
FormatThatThing:
|
FormatThatThing:
|
||||||
|
__fmt_free_dtoa(&mem);
|
||||||
|
mem = 0;
|
||||||
prec = alt = 0;
|
prec = alt = 0;
|
||||||
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
|
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
|
||||||
goto FormatString;
|
goto FormatString;
|
||||||
|
@ -462,6 +475,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
while (--width >= 0) {
|
while (--width >= 0) {
|
||||||
PUT(' ');
|
PUT(' ');
|
||||||
}
|
}
|
||||||
|
__fmt_free_dtoa(&mem);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'G':
|
case 'G':
|
||||||
|
@ -477,7 +491,9 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
p = "?";
|
p = "?";
|
||||||
goto FormatThatThing;
|
goto FormatThatThing;
|
||||||
}
|
}
|
||||||
s = weaken(__fmt_dtoa)(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se);
|
assert(!mem);
|
||||||
|
s = mem =
|
||||||
|
weaken(__fmt_dtoa)(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se);
|
||||||
if (decpt == 9999) goto Format9999;
|
if (decpt == 9999) goto Format9999;
|
||||||
c = se - s;
|
c = se - s;
|
||||||
prec1 = prec;
|
prec1 = prec;
|
||||||
|
@ -512,7 +528,8 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
p = "?";
|
p = "?";
|
||||||
goto FormatThatThing;
|
goto FormatThatThing;
|
||||||
}
|
}
|
||||||
s = weaken(__fmt_dtoa)(pun.d, 2, prec + 1, &decpt, &sgn, &se);
|
assert(!mem);
|
||||||
|
s = mem = weaken(__fmt_dtoa)(pun.d, 2, prec + 1, &decpt, &sgn, &se);
|
||||||
if (decpt == 9999) goto Format9999;
|
if (decpt == 9999) goto Format9999;
|
||||||
FormatExpo:
|
FormatExpo:
|
||||||
if (sgn) sign = '-';
|
if (sgn) sign = '-';
|
||||||
|
@ -547,6 +564,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
}
|
}
|
||||||
PUT(c);
|
PUT(c);
|
||||||
}
|
}
|
||||||
|
__fmt_free_dtoa(&mem);
|
||||||
PUT(d);
|
PUT(d);
|
||||||
if (decpt < 0) {
|
if (decpt < 0) {
|
||||||
PUT('-');
|
PUT('-');
|
||||||
|
@ -721,5 +739,7 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(!mem);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,10 @@ COSMOPOLITAN_C_START_
|
||||||
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
|
- uint128toarray_radix10(0x31337, a) l: 93 (27ns) m: 141 (41ns)
|
||||||
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */
|
- int128toarray_radix10(0x31337, a) l: 96 (28ns) m: 173 (51ns) */
|
||||||
|
|
||||||
|
unsigned LengthInt64(int64_t) pureconst;
|
||||||
|
unsigned LengthUint64(uint64_t) pureconst;
|
||||||
|
unsigned LengthInt64Thousands(int64_t) pureconst;
|
||||||
|
unsigned LengthUint64Thousands(uint64_t) pureconst;
|
||||||
char *FormatInt32(char[hasatleast 12], int32_t);
|
char *FormatInt32(char[hasatleast 12], int32_t);
|
||||||
char *FormatUint32(char[hasatleast 12], uint32_t);
|
char *FormatUint32(char[hasatleast 12], uint32_t);
|
||||||
char *FormatInt64(char[hasatleast 21], int64_t);
|
char *FormatInt64(char[hasatleast 21], int64_t);
|
||||||
|
|
102
libc/fmt/kdos2errno.S
Normal file
102
libc/fmt/kdos2errno.S
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||||
|
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/nt/errors.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
|
// @fileoverview data structure for __dos2errno()
|
||||||
|
|
||||||
|
.macro .e doscode systemv
|
||||||
|
.short \doscode
|
||||||
|
.long \systemv - kDos2Errno
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
kDos2Errno:
|
||||||
|
.e kNtErrorModNotFound,ENOSYS
|
||||||
|
.e kNtErrorBadCommand,EACCES
|
||||||
|
.e kNtErrorBadLength,EACCES
|
||||||
|
.e kNtErrorBadNetpath,ENOENT
|
||||||
|
.e kNtErrorBadNetName,ENOENT
|
||||||
|
.e kNtErrorBadNetResp,ENETDOWN
|
||||||
|
.e kNtErrorBadPathname,ENOENT
|
||||||
|
.e kNtErrorCannotMake,EACCES
|
||||||
|
.e kNtErrorCommitmentLimit,ENOMEM
|
||||||
|
.e kNtErrorConnectionAborted,ECONNABORTED
|
||||||
|
.e kNtErrorConnectionActive,EISCONN
|
||||||
|
.e kNtErrorConnectionRefused,ECONNREFUSED
|
||||||
|
.e kNtErrorCrc,EACCES
|
||||||
|
.e kNtErrorDirNotEmpty,ENOTEMPTY
|
||||||
|
.e kNtErrorDupName,EADDRINUSE
|
||||||
|
.e kNtErrorFilenameExcedRange,ENOENT
|
||||||
|
.e kNtErrorGenFailure,EACCES
|
||||||
|
.e kNtErrorGracefulDisconnect,EPIPE
|
||||||
|
.e kNtErrorHostDown,EHOSTUNREACH
|
||||||
|
.e kNtErrorHostUnreachable,EHOSTUNREACH
|
||||||
|
.e kNtErrorInsufficientBuffer,EFAULT
|
||||||
|
.e kNtErrorInvalidAddress,EADDRNOTAVAIL
|
||||||
|
.e kNtErrorInvalidFunction,EINVAL
|
||||||
|
.e kNtErrorInvalidNetname,EADDRNOTAVAIL
|
||||||
|
.e kNtErrorInvalidUserBuffer,EMSGSIZE
|
||||||
|
.e kNtErrorIoPending,EINPROGRESS
|
||||||
|
.e kNtErrorLockViolation,EACCES
|
||||||
|
.e kNtErrorMoreData,EMSGSIZE
|
||||||
|
.e kNtErrorNetnameDeleted,ECONNABORTED
|
||||||
|
.e kNtErrorNetworkAccessDenied,EACCES
|
||||||
|
.e kNtErrorNetworkBusy,ENETDOWN
|
||||||
|
.e kNtErrorNetworkUnreachable,ENETUNREACH
|
||||||
|
.e kNtErrorNoaccess,EFAULT
|
||||||
|
.e kNtErrorNonpagedSystemResources,ENOMEM
|
||||||
|
.e kNtErrorNotEnoughMemory,ENOMEM
|
||||||
|
.e kNtErrorNotEnoughQuota,ENOMEM
|
||||||
|
.e kNtErrorNotFound,ENOENT
|
||||||
|
.e kNtErrorNotLocked,EACCES
|
||||||
|
.e kNtErrorNotReady,EACCES
|
||||||
|
.e kNtErrorNotSupported,ENOTSUP
|
||||||
|
.e kNtErrorNoMoreFiles,ENOENT
|
||||||
|
.e kNtErrorNoSystemResources,ENOMEM
|
||||||
|
.e kNtErrorOperationAborted,EINTR
|
||||||
|
.e kNtErrorOutOfPaper,EACCES
|
||||||
|
.e kNtErrorPagedSystemResources,ENOMEM
|
||||||
|
.e kNtErrorPagefileQuota,ENOMEM
|
||||||
|
.e kNtErrorPipeNotConnected,EPIPE
|
||||||
|
.e kNtErrorPortUnreachable,ECONNRESET
|
||||||
|
.e kNtErrorProtocolUnreachable,ENETUNREACH
|
||||||
|
.e kNtErrorRemNotList,ECONNREFUSED
|
||||||
|
.e kNtErrorRequestAborted,EINTR
|
||||||
|
.e kNtErrorReqNotAccep,EWOULDBLOCK
|
||||||
|
.e kNtErrorSectorNotFound,EACCES
|
||||||
|
.e kNtErrorSemTimeout,ETIMEDOUT
|
||||||
|
.e kNtErrorSharingViolation,EACCES
|
||||||
|
.e kNtErrorTooManyNames,ENOMEM
|
||||||
|
.e kNtErrorUnexpNetErr,ECONNABORTED
|
||||||
|
.e kNtErrorWorkingSetQuota,ENOMEM
|
||||||
|
.e kNtErrorWriteProtect,EACCES
|
||||||
|
.e kNtErrorWrongDisk,EACCES
|
||||||
|
.e WSAEACCES,EACCES
|
||||||
|
.e WSAEDISCON,EPIPE
|
||||||
|
.e WSAEFAULT,EFAULT
|
||||||
|
.e WSAEINPROGRESS,EBUSY
|
||||||
|
.e WSAEINVAL,EINVAL
|
||||||
|
.e WSAEPROCLIM,ENOMEM
|
||||||
|
.e WSAESHUTDOWN,EPIPE
|
||||||
|
.e WSANOTINITIALISED,ENETDOWN
|
||||||
|
.e WSASYSNOTREADY,ENETDOWN
|
||||||
|
.e WSAVERNOTSUPPORTED,ENOSYS
|
||||||
|
.short 0
|
||||||
|
.endobj kDos2Errno,globl,hidden
|
98
libc/fmt/lengthuint64.c
Normal file
98
libc/fmt/lengthuint64.c
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/fmt/itoa.h"
|
||||||
|
|
||||||
|
static const uint64_t kTens[] = {
|
||||||
|
1ull,
|
||||||
|
10ull,
|
||||||
|
100ull,
|
||||||
|
1000ull,
|
||||||
|
10000ull,
|
||||||
|
100000ull,
|
||||||
|
1000000ull,
|
||||||
|
10000000ull,
|
||||||
|
100000000ull,
|
||||||
|
1000000000ull,
|
||||||
|
10000000000ull,
|
||||||
|
100000000000ull,
|
||||||
|
1000000000000ull,
|
||||||
|
10000000000000ull,
|
||||||
|
100000000000000ull,
|
||||||
|
1000000000000000ull,
|
||||||
|
10000000000000000ull,
|
||||||
|
100000000000000000ull,
|
||||||
|
1000000000000000000ull,
|
||||||
|
10000000000000000000ull,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char kTensIndex[] = {
|
||||||
|
0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, //
|
||||||
|
5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, //
|
||||||
|
10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, //
|
||||||
|
15, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19, 19, //
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `len(str(x))` where x is an unsigned 64-bit integer.
|
||||||
|
*/
|
||||||
|
unsigned LengthUint64(uint64_t x) {
|
||||||
|
unsigned w;
|
||||||
|
if (x) {
|
||||||
|
w = kTensIndex[63 ^ __builtin_clzll(x)];
|
||||||
|
w += x >= kTens[w];
|
||||||
|
return w;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `len(str(x))` where x is a signed 64-bit integer.
|
||||||
|
*/
|
||||||
|
unsigned LengthInt64(int64_t x) {
|
||||||
|
if (x >= 0) {
|
||||||
|
return LengthUint64(x);
|
||||||
|
} else {
|
||||||
|
return 1 + LengthUint64(-(uint64_t)x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns decimal string length of uint64 w/ thousands separators.
|
||||||
|
*/
|
||||||
|
unsigned LengthUint64Thousands(uint64_t x) {
|
||||||
|
unsigned w;
|
||||||
|
w = LengthUint64(x);
|
||||||
|
w += (w - 1) / 3;
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns decimal string length of int64 w/ thousands separators.
|
||||||
|
*/
|
||||||
|
unsigned LengthInt64Thousands(int64_t x) {
|
||||||
|
unsigned w;
|
||||||
|
if (x >= 0) {
|
||||||
|
w = LengthUint64(x);
|
||||||
|
return w + (w - 1) / 3;
|
||||||
|
} else {
|
||||||
|
w = LengthUint64(-(uint64_t)x);
|
||||||
|
return 1 + w + (w - 1) / 3;
|
||||||
|
}
|
||||||
|
}
|
41
libc/fmt/mapdoserrortoerrno.c
Normal file
41
libc/fmt/mapdoserrortoerrno.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 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/errno.h"
|
||||||
|
#include "libc/nt/errors.h"
|
||||||
|
#include "libc/sock/sock.h"
|
||||||
|
|
||||||
|
struct thatispacked Dos2Errno {
|
||||||
|
uint16_t doscode;
|
||||||
|
int32_t systemv;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct Dos2Errno kDos2Errno[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates Windows error using superset of consts.sh.
|
||||||
|
*/
|
||||||
|
textwindows errno_t __dos2errno(uint32_t error) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; kDos2Errno[i].doscode; ++i) {
|
||||||
|
if (error == kDos2Errno[i].doscode) {
|
||||||
|
return *(const int *)((intptr_t)kDos2Errno + kDos2Errno[i].systemv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
|
@ -21,6 +21,7 @@
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmts.h"
|
||||||
#include "libc/fmt/internal.h"
|
#include "libc/fmt/internal.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
|
|
||||||
#define BUFFER_SIZE 144
|
#define BUFFER_SIZE 144
|
||||||
|
|
||||||
|
@ -31,7 +32,6 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||||
unsigned log2base, unsigned prec, unsigned width,
|
unsigned log2base, unsigned prec, unsigned width,
|
||||||
unsigned char flags) {
|
unsigned char flags) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
/* pad leading zeros */
|
/* pad leading zeros */
|
||||||
if (!(flags & FLAGS_LEFT)) {
|
if (!(flags & FLAGS_LEFT)) {
|
||||||
if (width && (flags & FLAGS_ZEROPAD) &&
|
if (width && (flags & FLAGS_ZEROPAD) &&
|
||||||
|
@ -45,7 +45,6 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||||
buf[len++] = '0';
|
buf[len++] = '0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle hash */
|
/* handle hash */
|
||||||
if (flags & FLAGS_HASH) {
|
if (flags & FLAGS_HASH) {
|
||||||
if (!(flags & FLAGS_PRECISION) && len &&
|
if (!(flags & FLAGS_PRECISION) && len &&
|
||||||
|
@ -64,7 +63,6 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||||
buf[len++] = '0';
|
buf[len++] = '0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < BUFFER_SIZE) {
|
if (len < BUFFER_SIZE) {
|
||||||
if (negative) {
|
if (negative) {
|
||||||
buf[len++] = '-';
|
buf[len++] = '-';
|
||||||
|
@ -74,17 +72,14 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||||
buf[len++] = ' ';
|
buf[len++] = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pad spaces up to given width */
|
/* pad spaces up to given width */
|
||||||
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
||||||
if (len < width) {
|
if (len < width) {
|
||||||
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reverse(buf, len);
|
reverse(buf, len);
|
||||||
if (out(buf, arg, len) == -1) return -1;
|
if (out(buf, arg, len) == -1) return -1;
|
||||||
|
|
||||||
/* append pad spaces up to given width */
|
/* append pad spaces up to given width */
|
||||||
if (flags & FLAGS_LEFT) {
|
if (flags & FLAGS_LEFT) {
|
||||||
if (len < width) {
|
if (len < width) {
|
||||||
|
@ -97,6 +92,7 @@ static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||||
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||||
uintmax_t value, bool neg, unsigned log2base, unsigned prec,
|
uintmax_t value, bool neg, unsigned log2base, unsigned prec,
|
||||||
unsigned width, unsigned flags, const char *alphabet) {
|
unsigned width, unsigned flags, const char *alphabet) {
|
||||||
|
uint64_t u64;
|
||||||
uintmax_t remainder;
|
uintmax_t remainder;
|
||||||
unsigned len, count, digit;
|
unsigned len, count, digit;
|
||||||
char buf[BUFFER_SIZE];
|
char buf[BUFFER_SIZE];
|
||||||
|
@ -105,10 +101,15 @@ int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||||
if (value || !(flags & FLAGS_PRECISION)) {
|
if (value || !(flags & FLAGS_PRECISION)) {
|
||||||
count = 0;
|
count = 0;
|
||||||
do {
|
do {
|
||||||
assert(len < BUFFER_SIZE);
|
|
||||||
if (!log2base) {
|
if (!log2base) {
|
||||||
value = __udivmodti4(value, 10, &remainder);
|
if (value <= UINT64_MAX) {
|
||||||
digit = remainder;
|
u64 = value;
|
||||||
|
digit = u64 % 10;
|
||||||
|
value = u64 / 10;
|
||||||
|
} else {
|
||||||
|
value = __udivmodti4(value, 10, &remainder);
|
||||||
|
digit = remainder;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
digit = value;
|
digit = value;
|
||||||
digit &= (1u << log2base) - 1;
|
digit &= (1u << log2base) - 1;
|
||||||
|
@ -122,6 +123,7 @@ int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||||
}
|
}
|
||||||
buf[len++] = alphabet[digit];
|
buf[len++] = alphabet[digit];
|
||||||
} while (value);
|
} while (value);
|
||||||
|
assert(count <= BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width,
|
return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width,
|
||||||
flags);
|
flags);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
* Converts errno value to string non-reentrantly.
|
* Converts errno value to string non-reentrantly.
|
||||||
* @see strerror_r()
|
* @see strerror_r()
|
||||||
*/
|
*/
|
||||||
char *strerror(int err) {
|
noasan char *strerror(int err) {
|
||||||
_Alignas(1) static char buf[512];
|
_Alignas(1) static char buf[512];
|
||||||
strerror_r(err, buf, sizeof(buf));
|
strerror_r(err, buf, sizeof(buf));
|
||||||
return buf;
|
return buf;
|
||||||
|
|
|
@ -21,11 +21,20 @@
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/nexgen32e/bsr.h"
|
||||||
#include "libc/nt/enum/formatmessageflags.h"
|
#include "libc/nt/enum/formatmessageflags.h"
|
||||||
|
#include "libc/nt/enum/lang.h"
|
||||||
|
#include "libc/nt/memory.h"
|
||||||
#include "libc/nt/process.h"
|
#include "libc/nt/process.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/str/tpenc.h"
|
||||||
|
|
||||||
|
#if !IsTiny()
|
||||||
|
STATIC_YOINK("__dos2errno");
|
||||||
|
#endif
|
||||||
|
|
||||||
struct Error {
|
struct Error {
|
||||||
int x;
|
int x;
|
||||||
|
@ -35,7 +44,7 @@ struct Error {
|
||||||
extern const struct Error kErrorNames[];
|
extern const struct Error kErrorNames[];
|
||||||
extern const struct Error kErrorNamesLong[];
|
extern const struct Error kErrorNamesLong[];
|
||||||
|
|
||||||
static const char *GetErrorName(long x) {
|
noasan static inline const char *GetErrorName(long x) {
|
||||||
int i;
|
int i;
|
||||||
if (x) {
|
if (x) {
|
||||||
for (i = 0; kErrorNames[i].x; ++i) {
|
for (i = 0; kErrorNames[i].x; ++i) {
|
||||||
|
@ -47,7 +56,7 @@ static const char *GetErrorName(long x) {
|
||||||
return "EUNKNOWN";
|
return "EUNKNOWN";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *GetErrorNameLong(long x) {
|
noasan static inline const char *GetErrorNameLong(long x) {
|
||||||
int i;
|
int i;
|
||||||
if (x) {
|
if (x) {
|
||||||
for (i = 0; kErrorNamesLong[i].x; ++i) {
|
for (i = 0; kErrorNamesLong[i].x; ++i) {
|
||||||
|
@ -65,24 +74,51 @@ static const char *GetErrorNameLong(long x) {
|
||||||
* Converts errno value to string.
|
* Converts errno value to string.
|
||||||
* @return 0 on success, or error code
|
* @return 0 on success, or error code
|
||||||
*/
|
*/
|
||||||
int strerror_r(int err, char *buf, size_t size) {
|
noasan int strerror_r(int err, char *buf, size_t size) {
|
||||||
char *p;
|
uint64_t w;
|
||||||
|
int c, i, n;
|
||||||
|
char *p, *e;
|
||||||
const char *s;
|
const char *s;
|
||||||
err &= 0xFFFF;
|
char16_t *ws = 0;
|
||||||
if (IsTiny()) {
|
|
||||||
s = GetErrorName(err);
|
|
||||||
} else {
|
|
||||||
s = GetErrorNameLong(err);
|
|
||||||
}
|
|
||||||
p = buf;
|
p = buf;
|
||||||
if (strlen(s) + 1 + 5 + 1 + 1 <= size) {
|
e = p + size;
|
||||||
p = stpcpy(p, s);
|
err &= 0xFFFF;
|
||||||
*p++ = '[';
|
s = IsTiny() ? GetErrorName(err) : GetErrorNameLong(err);
|
||||||
p += uint64toarray_radix10(err, p);
|
while ((c = *s++)) {
|
||||||
*p++ = ']';
|
if (p + 1 + 1 <= e) *p++ = c;
|
||||||
}
|
}
|
||||||
if (p - buf < size) {
|
if (!IsTiny()) {
|
||||||
*p++ = '\0';
|
if (p + 1 + 5 + 1 + 1 <= e) {
|
||||||
|
*p++ = '[';
|
||||||
|
p = __intcpy(p, err);
|
||||||
|
*p++ = ']';
|
||||||
|
}
|
||||||
|
if (IsWindows()) {
|
||||||
|
err = GetLastError() & 0xffff;
|
||||||
|
if ((n = FormatMessage(
|
||||||
|
kNtFormatMessageAllocateBuffer | kNtFormatMessageFromSystem |
|
||||||
|
kNtFormatMessageIgnoreInserts,
|
||||||
|
0, err, MAKELANGID(kNtLangNeutral, kNtSublangDefault),
|
||||||
|
(char16_t *)&ws, 0, 0))) {
|
||||||
|
while (n && ws[n - 1] <= L' ' || ws[n - 1] == L'.') --n;
|
||||||
|
if (p + 1 + 1 <= e) *p++ = '[';
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
w = tpenc(ws[i] & 0xffff);
|
||||||
|
if (p + (bsrll(w) >> 3) + 1 + 1 <= e) {
|
||||||
|
do *p++ = w;
|
||||||
|
while ((w >>= 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p + 1 + 1 <= e) *p++ = ']';
|
||||||
|
LocalFree(ws);
|
||||||
|
}
|
||||||
|
if (p + 1 + 5 + 1 + 1 <= e) {
|
||||||
|
*p++ = '[';
|
||||||
|
p = __intcpy(p, err);
|
||||||
|
*p++ = ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (p + 1 <= e) *p = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,7 @@ typedef uint64_t uintmax_t;
|
||||||
#define strlenesque libcesque nosideeffect paramsnonnull()
|
#define strlenesque libcesque nosideeffect paramsnonnull()
|
||||||
#define vallocesque \
|
#define vallocesque \
|
||||||
libcesque nodiscard returnsaligned((PAGESIZE)) returnspointerwithnoaliases
|
libcesque nodiscard returnsaligned((PAGESIZE)) returnspointerwithnoaliases
|
||||||
#define reallocesque libcesque returnsaligned((__BIGGEST_ALIGNMENT__))
|
#define reallocesque libcesque returnsaligned((16))
|
||||||
#define mallocesque reallocesque returnspointerwithnoaliases
|
#define mallocesque reallocesque returnspointerwithnoaliases
|
||||||
#define interruptfn nocallersavedregisters forcealignargpointer
|
#define interruptfn nocallersavedregisters forcealignargpointer
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BIGPAGESIZE 0x200000
|
#define BIGPAGESIZE 0x200000
|
||||||
#define STACKSIZE 0x200000
|
#define STACKSIZE 0x20000
|
||||||
#define FRAMESIZE 0x10000 /* 8086 */
|
#define FRAMESIZE 0x10000 /* 8086 */
|
||||||
#define PAGESIZE 0x1000 /* i386+ */
|
#define PAGESIZE 0x1000 /* i386+ */
|
||||||
#define BUFSIZ 0x1000 /* best stdio default */
|
#define BUFSIZ 0x1000 /* best stdio default */
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,53 +1,61 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
|
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
|
||||||
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
|
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
|
||||||
#include "libc/calls/struct/iovec.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
|
||||||
#define kAsanScale 3
|
#define kAsanScale 3
|
||||||
#define kAsanMagic 0x7fff8000
|
#define kAsanMagic 0x7fff8000
|
||||||
#define kAsanHeapFree -1 /* F */
|
#define kAsanNullPage -1 /* ∅ 0xff */
|
||||||
#define kAsanStackFree -2 /* F */
|
#define kAsanProtected -2 /* P 0xfe */
|
||||||
#define kAsanRelocated -3 /* R */
|
#define kAsanHeapFree -3 /* F 0xfd */
|
||||||
#define kAsanHeapUnderrun -4 /* U */
|
#define kAsanHeapRelocated -4 /* R 0xfc */
|
||||||
#define kAsanHeapOverrun -5 /* O */
|
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
|
||||||
#define kAsanGlobalOverrun -6 /* O */
|
#define kAsanHeapUnderrun -6 /* U 0xfa */
|
||||||
#define kAsanGlobalUnregistered -7 /* G */
|
#define kAsanHeapOverrun -7 /* O 0xf9 */
|
||||||
#define kAsanStackUnderrun -8 /* U */
|
#define kAsanStackUnscoped -8 /* s 0xf8 */
|
||||||
#define kAsanStackOverrun -9 /* O */
|
#define kAsanStackOverflow -9 /* ! 0xf7 */
|
||||||
#define kAsanAllocaUnderrun -10 /* U */
|
#define kAsanGlobalOrder -10 /* I 0xf6 */
|
||||||
#define kAsanAllocaOverrun -11 /* O */
|
#define kAsanStackFree -11 /* r 0xf5 */
|
||||||
#define kAsanUnscoped -12 /* S */
|
#define kAsanStackPartial -12 /* p 0xf4 */
|
||||||
#define kAsanUnmapped -13 /* M */
|
#define kAsanStackOverrun -13 /* o 0xf3 */
|
||||||
#define kAsanProtected -14 /* P */
|
#define kAsanStackMiddle -14 /* m 0xf2 */
|
||||||
#define kAsanStackGuard -15 /* _ */
|
#define kAsanStackUnderrun -15 /* u 0xf1 */
|
||||||
#define kAsanNullPage -16
|
#define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
|
||||||
|
#define kAsanUnmapped -17 /* M 0xef */
|
||||||
|
#define kAsanGlobalRedzone -18 /* G 0xee */
|
||||||
|
#define kAsanGlobalGone -19 /* 𝐺 0xed */
|
||||||
|
|
||||||
#define SHADOW(x) ((signed char *)(((uintptr_t)(x) >> kAsanScale) + kAsanMagic))
|
#define SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic))
|
||||||
#define UNSHADOW(x) ((void *)(((uintptr_t)(x) + 0x7fff8000) << 3))
|
#define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale))
|
||||||
|
|
||||||
|
typedef void __asan_die_f(void);
|
||||||
|
|
||||||
struct AsanFault {
|
struct AsanFault {
|
||||||
char kind;
|
signed char kind;
|
||||||
signed char *shadow;
|
signed char *shadow;
|
||||||
};
|
};
|
||||||
|
|
||||||
void __asan_unpoison(uintptr_t, size_t);
|
extern bool __asan_noreentry;
|
||||||
|
|
||||||
|
void __asan_unpoison(long, long);
|
||||||
|
void __asan_poison(long, long, signed char);
|
||||||
void __asan_verify(const void *, size_t);
|
void __asan_verify(const void *, size_t);
|
||||||
void __asan_map_shadow(uintptr_t, size_t);
|
void __asan_map_shadow(uintptr_t, size_t);
|
||||||
void __asan_poison(uintptr_t, size_t, int);
|
bool __asan_is_valid(const void *, long) nosideeffect;
|
||||||
bool __asan_is_valid(const void *, size_t);
|
bool __asan_is_valid_strlist(char *const *) strlenesque;
|
||||||
bool __asan_is_valid_strlist(char *const *);
|
bool __asan_is_valid_iov(const struct iovec *, int) nosideeffect;
|
||||||
bool __asan_is_valid_iov(const struct iovec *, int);
|
wint_t __asan_symbolize_access_poison(signed char) pureconst;
|
||||||
struct AsanFault __asan_check(const void *, size_t);
|
const char *__asan_describe_access_poison(signed char) pureconst;
|
||||||
void __asan_report_memory_fault(void *, int, const char *) wontreturn;
|
struct AsanFault __asan_check(const void *, long) nosideeffect;
|
||||||
void __asan_report(void *, int, const char *, char) wontreturn;
|
|
||||||
void *__asan_memalign(size_t, size_t);
|
|
||||||
void __asan_free(void *);
|
void __asan_free(void *);
|
||||||
void *__asan_malloc(size_t);
|
void *__asan_malloc(size_t);
|
||||||
|
int __asan_malloc_trim(size_t);
|
||||||
|
int __asan_print_trace(void *);
|
||||||
void *__asan_calloc(size_t, size_t);
|
void *__asan_calloc(size_t, size_t);
|
||||||
void *__asan_realloc(void *, size_t);
|
void *__asan_realloc(void *, size_t);
|
||||||
|
void *__asan_memalign(size_t, size_t);
|
||||||
|
size_t __asan_get_heap_size(const void *);
|
||||||
void *__asan_realloc_in_place(void *, size_t);
|
void *__asan_realloc_in_place(void *, size_t);
|
||||||
void *__asan_valloc(size_t);
|
|
||||||
void *__asan_pvalloc(size_t);
|
|
||||||
int __asan_malloc_trim(size_t);
|
|
||||||
void __asan_die(const char *) wontreturn;
|
|
||||||
|
|
||||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */
|
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */
|
||||||
|
|
|
@ -28,7 +28,7 @@ typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
|
|
||||||
noasan static noinline antiquity void bzero_sse(char *p, size_t n) {
|
noasan static noinline antiquity void bzero_sse(char *p, size_t n) {
|
||||||
xmm_t v = {0};
|
xmm_t v = {0};
|
||||||
if (IsAsan()) __asan_check(p, n);
|
if (IsAsan()) __asan_verify(p, n);
|
||||||
if (n <= 32) {
|
if (n <= 32) {
|
||||||
*(xmm_t *)(p + n - 16) = v;
|
*(xmm_t *)(p + n - 16) = v;
|
||||||
*(xmm_t *)p = v;
|
*(xmm_t *)p = v;
|
||||||
|
@ -45,7 +45,7 @@ noasan static noinline antiquity void bzero_sse(char *p, size_t n) {
|
||||||
|
|
||||||
noasan microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
|
noasan microarchitecture("avx") static void bzero_avx(char *p, size_t n) {
|
||||||
xmm_t v = {0};
|
xmm_t v = {0};
|
||||||
if (IsAsan()) __asan_check(p, n);
|
if (IsAsan()) __asan_verify(p, n);
|
||||||
if (n <= 32) {
|
if (n <= 32) {
|
||||||
*(xmm_t *)(p + n - 16) = v;
|
*(xmm_t *)(p + n - 16) = v;
|
||||||
*(xmm_t *)p = v;
|
*(xmm_t *)p = v;
|
||||||
|
@ -134,11 +134,6 @@ void(bzero)(void *p, size_t n) {
|
||||||
char *b;
|
char *b;
|
||||||
uint64_t x;
|
uint64_t x;
|
||||||
b = p;
|
b = p;
|
||||||
if (IsTiny()) {
|
|
||||||
if (IsAsan()) __asan_check(p, n);
|
|
||||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
asm("xorl\t%k0,%k0" : "=r"(x));
|
asm("xorl\t%k0,%k0" : "=r"(x));
|
||||||
if (n <= 16) {
|
if (n <= 16) {
|
||||||
if (n >= 8) {
|
if (n >= 8) {
|
||||||
|
@ -153,6 +148,9 @@ void(bzero)(void *p, size_t n) {
|
||||||
b[--n] = x;
|
b[--n] = x;
|
||||||
} while (n);
|
} while (n);
|
||||||
}
|
}
|
||||||
|
} else if (IsTiny()) {
|
||||||
|
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(0));
|
||||||
|
return;
|
||||||
} else if (X86_HAVE(AVX)) {
|
} else if (X86_HAVE(AVX)) {
|
||||||
bzero_avx(b, n);
|
bzero_avx(b, n);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,22 +20,12 @@
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/nexgen32e/bsf.h"
|
|
||||||
#include "libc/nexgen32e/bsr.h"
|
#include "libc/nexgen32e/bsr.h"
|
||||||
|
#include "libc/runtime/cxaatexit.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
static struct CxaAtexitBlocks {
|
STATIC_YOINK("__cxa_finalize");
|
||||||
struct CxaAtexitBlock {
|
|
||||||
unsigned mask;
|
|
||||||
struct CxaAtexitBlock *next;
|
|
||||||
struct CxaAtexit {
|
|
||||||
void *fp;
|
|
||||||
void *arg;
|
|
||||||
void *pred;
|
|
||||||
} p[ATEXIT_MAX];
|
|
||||||
} * p, root;
|
|
||||||
} __cxa_blocks;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds global destructor.
|
* Adds global destructor.
|
||||||
|
@ -52,6 +42,7 @@ static struct CxaAtexitBlocks {
|
||||||
* @note folks have forked libc in past just to unbloat atexit()
|
* @note folks have forked libc in past just to unbloat atexit()
|
||||||
*/
|
*/
|
||||||
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
|
/* asan runtime depends on this function */
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct CxaAtexitBlock *b, *b2;
|
struct CxaAtexitBlock *b, *b2;
|
||||||
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
|
_Static_assert(ATEXIT_MAX == CHAR_BIT * sizeof(b->mask), "");
|
||||||
|
@ -74,51 +65,3 @@ noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
|
||||||
b->p[i].pred = pred;
|
b->p[i].pred = pred;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers global destructors.
|
|
||||||
*
|
|
||||||
* They're called in LIFO order. If a destructor adds more destructors,
|
|
||||||
* then those destructors will be called immediately following, before
|
|
||||||
* iteration continues.
|
|
||||||
*
|
|
||||||
* @param pred can be null to match all
|
|
||||||
*/
|
|
||||||
void __cxa_finalize(void *pred) {
|
|
||||||
unsigned i, mask;
|
|
||||||
struct CxaAtexitBlock *b, *b2;
|
|
||||||
StartOver:
|
|
||||||
if ((b = __cxa_blocks.p)) {
|
|
||||||
for (;;) {
|
|
||||||
mask = b->mask;
|
|
||||||
while (mask) {
|
|
||||||
i = bsf(mask);
|
|
||||||
mask &= ~(1u << i);
|
|
||||||
if (!pred || pred == b->p[i].pred) {
|
|
||||||
b->mask &= ~(1u << i);
|
|
||||||
if (b->p[i].fp) {
|
|
||||||
((void (*)(void *))b->p[i].fp)(b->p[i].arg);
|
|
||||||
goto StartOver;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pred) {
|
|
||||||
b2 = b->next;
|
|
||||||
if (b2) {
|
|
||||||
assert(b != &__cxa_blocks.root);
|
|
||||||
if (weaken(free)) {
|
|
||||||
weaken(free)(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__cxa_blocks.p = b2;
|
|
||||||
goto StartOver;
|
|
||||||
} else {
|
|
||||||
if (b->next) {
|
|
||||||
b = b->next;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,18 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/runtime/cxaatexit.internal.h"
|
||||||
.source __FILE__
|
|
||||||
|
|
||||||
.initbss 202,_init_pvalloc
|
struct CxaAtexitBlocks __cxa_blocks;
|
||||||
hook_pvalloc:
|
|
||||||
.quad 0
|
|
||||||
.endobj hook_pvalloc,globl,hidden
|
|
||||||
.previous
|
|
||||||
|
|
||||||
.init.start 202,_init_pvalloc
|
|
||||||
.hidden dlpvalloc
|
|
||||||
ezlea dlpvalloc,ax
|
|
||||||
stosq
|
|
||||||
yoink free
|
|
||||||
.init.end 202,_init_pvalloc
|
|
72
libc/intrin/cxafinalize.c
Normal file
72
libc/intrin/cxafinalize.c
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/assert.h"
|
||||||
|
#include "libc/bits/weaken.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/nexgen32e/bsf.h"
|
||||||
|
#include "libc/runtime/cxaatexit.internal.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers global destructors.
|
||||||
|
*
|
||||||
|
* They're called in LIFO order. If a destructor adds more destructors,
|
||||||
|
* then those destructors will be called immediately following, before
|
||||||
|
* iteration continues.
|
||||||
|
*
|
||||||
|
* @param pred can be null to match all
|
||||||
|
*/
|
||||||
|
void __cxa_finalize(void *pred) {
|
||||||
|
unsigned i, mask;
|
||||||
|
struct CxaAtexitBlock *b, *b2;
|
||||||
|
StartOver:
|
||||||
|
if ((b = __cxa_blocks.p)) {
|
||||||
|
for (;;) {
|
||||||
|
mask = b->mask;
|
||||||
|
while (mask) {
|
||||||
|
i = bsf(mask);
|
||||||
|
mask &= ~(1u << i);
|
||||||
|
if (!pred || pred == b->p[i].pred) {
|
||||||
|
b->mask &= ~(1u << i);
|
||||||
|
if (b->p[i].fp) {
|
||||||
|
((void (*)(void *))b->p[i].fp)(b->p[i].arg);
|
||||||
|
goto StartOver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pred) {
|
||||||
|
b2 = b->next;
|
||||||
|
if (b2) {
|
||||||
|
assert(b != &__cxa_blocks.root);
|
||||||
|
if (weaken(free)) {
|
||||||
|
weaken(free)(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__cxa_blocks.p = b2;
|
||||||
|
goto StartOver;
|
||||||
|
} else {
|
||||||
|
if (b->next) {
|
||||||
|
b = b->next;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ extern void(__msabi* __imp_ExitProcess)(uint32_t);
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
* @noreturn
|
* @noreturn
|
||||||
*/
|
*/
|
||||||
privileged wontreturn void _Exit(int exitcode) {
|
privileged noinstrument noasan noubsan wontreturn void _Exit(int exitcode) {
|
||||||
if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) {
|
if ((!IsWindows() && !IsMetal()) || (IsMetal() && IsGenuineCosmo())) {
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: /* no outputs */
|
: /* no outputs */
|
|
@ -41,12 +41,27 @@ $(LIBC_INTRIN_A).pkg: \
|
||||||
$(LIBC_INTRIN_A_OBJS) \
|
$(LIBC_INTRIN_A_OBJS) \
|
||||||
$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)_A).pkg)
|
$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||||
|
|
||||||
|
$(LIBC_INTRIN_A_OBJS): \
|
||||||
|
OVERRIDE_CFLAGS += \
|
||||||
|
-foptimize-sibling-calls
|
||||||
|
|
||||||
o/$(MODE)/libc/intrin/asan.o \
|
o/$(MODE)/libc/intrin/asan.o \
|
||||||
o/$(MODE)/libc/intrin/ubsan.o: \
|
o/$(MODE)/libc/intrin/ubsan.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-fno-sanitize=all \
|
-fno-sanitize=all \
|
||||||
-fno-stack-protector \
|
-fno-stack-protector
|
||||||
-O3
|
|
||||||
|
o/$(MODE)/libc/intrin/asan.o: \
|
||||||
|
OVERRIDE_CFLAGS += \
|
||||||
|
-O2 \
|
||||||
|
-finline \
|
||||||
|
-finline-functions
|
||||||
|
|
||||||
|
o/$(MODE)/libc/intrin/asan.o \
|
||||||
|
o/$(MODE)/libc/intrin/ubsan.o: \
|
||||||
|
OVERRIDE_CFLAGS += \
|
||||||
|
-fno-sanitize=all \
|
||||||
|
-fno-stack-protector
|
||||||
|
|
||||||
o/$(MODE)/libc/intrin/memcmp.o: \
|
o/$(MODE)/libc/intrin/memcmp.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
|
@ -63,12 +78,18 @@ o//libc/intrin/memmove.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-O3
|
-O3
|
||||||
|
|
||||||
o/tiny/libc/intrin/memcmp.o \
|
o/$(MODE)/libc/intrin/bzero.o \
|
||||||
o/tiny/libc/intrin/memmove.o \
|
o/$(MODE)/libc/intrin/memcmp.o \
|
||||||
o/tiny/libc/intrin/memmove-gcc.asm: \
|
o/$(MODE)/libc/intrin/memmove.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-fpie
|
-fpie
|
||||||
|
|
||||||
|
o/$(MODE)/libc/intrin/printf.o: \
|
||||||
|
OVERRIDE_CFLAGS += \
|
||||||
|
-Os \
|
||||||
|
-fpie \
|
||||||
|
-mgeneral-regs-only
|
||||||
|
|
||||||
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
|
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
|
||||||
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
|
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
|
||||||
LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS))
|
LIBC_INTRIN_SRCS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_SRCS))
|
||||||
|
|
|
@ -16,51 +16,43 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/alg/alg.h"
|
|
||||||
#include "libc/bits/safemacros.internal.h"
|
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/calls/internal.h"
|
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/nexgen32e/vendor.internal.h"
|
#include "libc/nexgen32e/vendor.internal.h"
|
||||||
#include "libc/nt/struct/teb.h"
|
#include "libc/nt/struct/teb.h"
|
||||||
#include "libc/runtime/runtime.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/at.h"
|
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
#define kBufSize 1024
|
#define kBufSize 1024
|
||||||
#define kProcStatus "/proc/self/status"
|
#define kPid "TracerPid:\t"
|
||||||
#define kPid "TracerPid:\t"
|
|
||||||
|
|
||||||
static noasan int NtBeingDebugged(void) {
|
|
||||||
return NtGetPeb()->BeingDebugged;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if gdb, strace, windbg, etc. is controlling process.
|
* Determines if gdb, strace, windbg, etc. is controlling process.
|
||||||
* @return non-zero if attached, otherwise 0
|
* @return non-zero if attached, otherwise 0
|
||||||
*/
|
*/
|
||||||
int IsDebuggerPresent(bool force) {
|
noasan noubsan int IsDebuggerPresent(bool force) {
|
||||||
|
/* asan runtime depends on this function */
|
||||||
int fd, res;
|
int fd, res;
|
||||||
ssize_t got;
|
ssize_t got;
|
||||||
char buf[1024];
|
char *p, buf[1024];
|
||||||
res = false;
|
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (getenv("HEISENDEBUG")) return false;
|
if (IsGenuineCosmo()) return 0;
|
||||||
if (IsGenuineCosmo()) return false;
|
if (__getenv(__envp, "HEISENDEBUG")) return 0;
|
||||||
}
|
}
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
res = NtBeingDebugged();
|
return NtGetPeb()->BeingDebugged; /* needs noasan */
|
||||||
} else if (IsLinux()) {
|
} else {
|
||||||
if ((fd = sys_openat(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
|
res = 0;
|
||||||
if ((got = sys_read(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) {
|
if ((fd = __sysv_open("/proc/self/status", O_RDONLY, 0)) >= 0) {
|
||||||
|
if ((got = __sysv_read(fd, buf, sizeof(buf) - 1)) > 0) {
|
||||||
buf[got] = '\0';
|
buf[got] = '\0';
|
||||||
res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid));
|
if ((p = __strstr(buf, kPid))) {
|
||||||
|
p += sizeof(kPid) - 1;
|
||||||
|
res = __atoul(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sys_close(fd);
|
__sysv_close(fd);
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
|
@ -16,6 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/log/internal.h"
|
||||||
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
|
@ -28,8 +30,9 @@ bool IsRunningUnderMake(void) {
|
||||||
return g_isrunningundermake;
|
return g_isrunningundermake;
|
||||||
}
|
}
|
||||||
|
|
||||||
textstartup void g_isrunningundermake_init(void) {
|
textstartup void g_isrunningundermake_init(int argc, char **argv, char **envp,
|
||||||
g_isrunningundermake = !!getenv("MAKEFLAGS");
|
intptr_t *auxv) {
|
||||||
|
g_isrunningundermake = !!__getenv(envp, "MAKEFLAGS");
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *const g_isrunningundermake_ctor[] initarray = {
|
const void *const g_isrunningundermake_ctor[] initarray = {
|
46
libc/intrin/isterminalinarticulate.c
Normal file
46
libc/intrin/isterminalinarticulate.c
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 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/bits/safemacros.internal.h"
|
||||||
|
#include "libc/log/internal.h"
|
||||||
|
#include "libc/log/libfatal.internal.h"
|
||||||
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/nt/enum/version.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
bool g_isterminalinarticulate;
|
||||||
|
|
||||||
|
bool IsTerminalInarticulate(void) {
|
||||||
|
return g_isterminalinarticulate;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup noasan void g_isterminalinarticulate_init(int argc, char **argv,
|
||||||
|
char **envp,
|
||||||
|
intptr_t *auxv) {
|
||||||
|
char *s;
|
||||||
|
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
|
||||||
|
g_isterminalinarticulate = true;
|
||||||
|
} else if ((s = __getenv(envp, "TERM"))) {
|
||||||
|
g_isterminalinarticulate = !__strcmp(s, "dumb");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *const g_isterminalinarticulate_ctor[] initarray = {
|
||||||
|
g_isterminalinarticulate_init,
|
||||||
|
};
|
|
@ -21,6 +21,8 @@
|
||||||
#include "libc/nexgen32e/x86feature.h"
|
#include "libc/nexgen32e/x86feature.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
#define PMOVMSKB(x) __builtin_ia32_pmovmskb128(x)
|
||||||
|
|
||||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||||
|
|
||||||
static noinline antiquity int memcmp_sse(const unsigned char *p,
|
static noinline antiquity int memcmp_sse(const unsigned char *p,
|
||||||
|
@ -29,9 +31,7 @@ static noinline antiquity int memcmp_sse(const unsigned char *p,
|
||||||
unsigned u, u0, u1, u2, u3;
|
unsigned u, u0, u1, u2, u3;
|
||||||
if (n > 32) {
|
if (n > 32) {
|
||||||
while (n > 16 + 16) {
|
while (n > 16 + 16) {
|
||||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p ==
|
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
|
||||||
*(const xmm_t *)q) -
|
|
||||||
0xffff)) {
|
|
||||||
n -= 16;
|
n -= 16;
|
||||||
p += 16;
|
p += 16;
|
||||||
q += 16;
|
q += 16;
|
||||||
|
@ -41,10 +41,8 @@ static noinline antiquity int memcmp_sse(const unsigned char *p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == *(const xmm_t *)q) -
|
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
|
||||||
0xffff)) {
|
if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
|
||||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
|
|
||||||
*(const xmm_t *)(q + n - 16)) -
|
|
||||||
0xffff)) {
|
0xffff)) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -61,19 +59,13 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
||||||
const unsigned char *q,
|
const unsigned char *q,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
uint64_t w;
|
uint64_t w;
|
||||||
unsigned u, u0, u1, u2, u3;
|
unsigned u;
|
||||||
if (n > 32) {
|
if (n > 32) {
|
||||||
while (n >= 16 + 64) {
|
while (n >= 16 + 64) {
|
||||||
u0 = __builtin_ia32_pmovmskb128(
|
w = (uint64_t)PMOVMSKB(((xmm_t *)p)[0] == ((xmm_t *)q)[0]) << 000 |
|
||||||
(((const xmm_t *)p)[0] == ((const xmm_t *)q)[0]));
|
(uint64_t)PMOVMSKB(((xmm_t *)p)[1] == ((xmm_t *)q)[1]) << 020 |
|
||||||
u1 = __builtin_ia32_pmovmskb128(
|
(uint64_t)PMOVMSKB(((xmm_t *)p)[2] == ((xmm_t *)q)[2]) << 040 |
|
||||||
(((const xmm_t *)p)[1] == ((const xmm_t *)q)[1]));
|
(uint64_t)PMOVMSKB(((xmm_t *)p)[3] == ((xmm_t *)q)[3]) << 060;
|
||||||
u2 = __builtin_ia32_pmovmskb128(
|
|
||||||
(((const xmm_t *)p)[2] == ((const xmm_t *)q)[2]));
|
|
||||||
u3 = __builtin_ia32_pmovmskb128(
|
|
||||||
(((const xmm_t *)p)[3] == ((const xmm_t *)q)[3]));
|
|
||||||
w = (uint64_t)u0 | (uint64_t)u1 << 16 | (uint64_t)u2 << 32 |
|
|
||||||
(uint64_t)u3 << 48;
|
|
||||||
if (w == -1) {
|
if (w == -1) {
|
||||||
n -= 64;
|
n -= 64;
|
||||||
p += 64;
|
p += 64;
|
||||||
|
@ -84,9 +76,7 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (n > 16 + 16) {
|
while (n > 16 + 16) {
|
||||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p ==
|
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
|
||||||
*(const xmm_t *)q) -
|
|
||||||
0xffff)) {
|
|
||||||
n -= 16;
|
n -= 16;
|
||||||
p += 16;
|
p += 16;
|
||||||
q += 16;
|
q += 16;
|
||||||
|
@ -96,10 +86,8 @@ microarchitecture("avx") static int memcmp_avx(const unsigned char *p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)p == *(const xmm_t *)q) -
|
if (!(u = PMOVMSKB(*(xmm_t *)p == *(xmm_t *)q) ^ 0xffff)) {
|
||||||
0xffff)) {
|
if (!(u = PMOVMSKB(*(xmm_t *)(p + n - 16) == *(xmm_t *)(q + n - 16)) ^
|
||||||
if (!(u = __builtin_ia32_pmovmskb128(*(const xmm_t *)(p + n - 16) ==
|
|
||||||
*(const xmm_t *)(q + n - 16)) -
|
|
||||||
0xffff)) {
|
0xffff)) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
|
||||||
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
|
|
||||||
asm("memcpy = memmove\n\t"
|
|
||||||
".globl\tmemcpy");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies memory.
|
* Copies memory.
|
||||||
*
|
*
|
||||||
|
@ -120,8 +117,6 @@ void *memmove(void *dst, const void *src, size_t n) {
|
||||||
*d = *s;
|
*d = *s;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IsAsan()) __asan_check(d, n);
|
|
||||||
if (IsAsan()) __asan_check(s, n);
|
|
||||||
if (d <= s) {
|
if (d <= s) {
|
||||||
asm("rep movsb"
|
asm("rep movsb"
|
||||||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
|
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])dst)
|
||||||
|
@ -224,8 +219,8 @@ void *memmove(void *dst, const void *src, size_t n) {
|
||||||
*(xmm_t *)(d + n + 16) = w;
|
*(xmm_t *)(d + n + 16) = w;
|
||||||
} while (n >= 32);
|
} while (n >= 32);
|
||||||
} else {
|
} else {
|
||||||
if (IsAsan()) __asan_check(d, n);
|
if (IsAsan()) __asan_verify(d, n);
|
||||||
if (IsAsan()) __asan_check(s, n);
|
if (IsAsan()) __asan_verify(s, n);
|
||||||
asm("std\n\t"
|
asm("std\n\t"
|
||||||
"rep movsb\n\t"
|
"rep movsb\n\t"
|
||||||
"cld"
|
"cld"
|
||||||
|
@ -246,8 +241,8 @@ void *memmove(void *dst, const void *src, size_t n) {
|
||||||
s += i;
|
s += i;
|
||||||
n -= i;
|
n -= i;
|
||||||
} else {
|
} else {
|
||||||
if (IsAsan()) __asan_check(d, n);
|
if (IsAsan()) __asan_verify(d, n);
|
||||||
if (IsAsan()) __asan_check(s, n);
|
if (IsAsan()) __asan_verify(s, n);
|
||||||
asm("rep movsb"
|
asm("rep movsb"
|
||||||
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
|
: "+D"(d), "+S"(s), "+c"(n), "=m"(*(char(*)[n])d)
|
||||||
: "m"(*(char(*)[n])s));
|
: "m"(*(char(*)[n])s));
|
||||||
|
@ -313,3 +308,6 @@ void *memmove(void *dst, const void *src, size_t n) {
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm("memcpy = memmove\n\t"
|
||||||
|
".globl\tmemcpy");
|
||||||
|
|
|
@ -28,7 +28,7 @@ typedef long long xmm_a __attribute__((__vector_size__(16), __aligned__(16)));
|
||||||
|
|
||||||
noasan static noinline antiquity void *memset_sse(char *p, char c, size_t n) {
|
noasan static noinline antiquity void *memset_sse(char *p, char c, size_t n) {
|
||||||
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||||
if (IsAsan()) __asan_check(p, n);
|
if (IsAsan()) __asan_verify(p, n);
|
||||||
if (n <= 32) {
|
if (n <= 32) {
|
||||||
*(xmm_t *)(p + n - 16) = v;
|
*(xmm_t *)(p + n - 16) = v;
|
||||||
*(xmm_t *)p = v;
|
*(xmm_t *)p = v;
|
||||||
|
@ -48,7 +48,7 @@ noasan microarchitecture("avx") static void *memset_avx(char *p, char c,
|
||||||
size_t n) {
|
size_t n) {
|
||||||
char *t;
|
char *t;
|
||||||
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
xmm_t v = {c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c};
|
||||||
if (IsAsan()) __asan_check(p, n);
|
if (IsAsan()) __asan_verify(p, n);
|
||||||
if (n <= 32) {
|
if (n <= 32) {
|
||||||
*(xmm_t *)(p + n - 16) = v;
|
*(xmm_t *)(p + n - 16) = v;
|
||||||
*(xmm_t *)p = v;
|
*(xmm_t *)p = v;
|
||||||
|
@ -140,11 +140,6 @@ void *memset(void *p, int c, size_t n) {
|
||||||
uint32_t u;
|
uint32_t u;
|
||||||
uint64_t x;
|
uint64_t x;
|
||||||
b = p;
|
b = p;
|
||||||
if (IsTiny()) {
|
|
||||||
if (IsAsan()) __asan_check(p, n);
|
|
||||||
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
if (n <= 16) {
|
if (n <= 16) {
|
||||||
if (n >= 8) {
|
if (n >= 8) {
|
||||||
x = 0x0101010101010101ul * (c & 255);
|
x = 0x0101010101010101ul * (c & 255);
|
||||||
|
@ -161,6 +156,9 @@ void *memset(void *p, int c, size_t n) {
|
||||||
} while (n);
|
} while (n);
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
|
} else if (IsTiny()) {
|
||||||
|
asm("rep stosb" : "+D"(b), "+c"(n), "=m"(*(char(*)[n])b) : "0"(p), "a"(c));
|
||||||
|
return p;
|
||||||
} else if (X86_HAVE(AVX)) {
|
} else if (X86_HAVE(AVX)) {
|
||||||
return memset_avx(b, c, n);
|
return memset_avx(b, c, n);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/nexgen32e/bsr.h"
|
|
||||||
#include "libc/nexgen32e/uart.internal.h"
|
#include "libc/nexgen32e/uart.internal.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -26,23 +25,25 @@
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Low-level printf.
|
* Privileged printf.
|
||||||
*
|
*
|
||||||
* This will work without any cosmopolitan runtime support once the
|
* This will work without any cosmopolitan runtime support once the
|
||||||
* executable has been loaded into memory.
|
* executable has been loaded into memory.
|
||||||
*/
|
*/
|
||||||
privileged noasan noinstrument void __printf(const char *fmt, ...) {
|
privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
|
||||||
long d, ax;
|
/* system call support runtime depends on this function */
|
||||||
|
/* function tracing runtime depends on this function */
|
||||||
|
/* asan runtime depends on this function */
|
||||||
|
short w[2];
|
||||||
va_list va;
|
va_list va;
|
||||||
uint16_t dx;
|
uint16_t dx;
|
||||||
const char *s;
|
const void *s;
|
||||||
uint32_t wrote;
|
uint32_t wrote;
|
||||||
unsigned long x;
|
unsigned long x;
|
||||||
unsigned char al;
|
unsigned char al;
|
||||||
const char16_t *S;
|
int i, j, t, cstr;
|
||||||
int i, n, t, w, plus;
|
long d, rax, rdi, rsi, rdx, dot;
|
||||||
char c, f, *p, *e, b[2048];
|
char c, *p, *e, pad, bits, base, sign, thou, z[28], b[2048];
|
||||||
w = 0;
|
|
||||||
p = b;
|
p = b;
|
||||||
e = p + sizeof(b);
|
e = p + sizeof(b);
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
|
@ -56,98 +57,132 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
|
||||||
case '\0':
|
case '\0':
|
||||||
break;
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
w = 0;
|
dot = 0;
|
||||||
f = ' ';
|
pad = ' ';
|
||||||
plus = 0;
|
sign = 0;
|
||||||
n = INT_MAX;
|
bits = 0;
|
||||||
|
thou = 0;
|
||||||
|
w[0] = 0;
|
||||||
|
w[1] = SHRT_MAX;
|
||||||
NeedMoar:
|
NeedMoar:
|
||||||
switch ((c = *fmt++)) {
|
switch ((c = *fmt++)) {
|
||||||
case '\0':
|
case '\0':
|
||||||
break;
|
break;
|
||||||
case '0':
|
case 'l':
|
||||||
f = c;
|
case 'z':
|
||||||
goto NeedMoar;
|
goto NeedMoar;
|
||||||
|
case ' ':
|
||||||
case '+':
|
case '+':
|
||||||
plus = c;
|
sign = c;
|
||||||
|
goto NeedMoar;
|
||||||
|
case 'e':
|
||||||
|
dot = 1;
|
||||||
|
goto NeedMoar;
|
||||||
|
case ',':
|
||||||
|
thou = c;
|
||||||
|
goto NeedMoar;
|
||||||
|
case 'h':
|
||||||
|
bits = 16;
|
||||||
|
goto NeedMoar;
|
||||||
|
case '0':
|
||||||
|
pad = c;
|
||||||
|
/* fallthrough */
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
w[dot] *= 10;
|
||||||
|
w[dot] += c - '0';
|
||||||
goto NeedMoar;
|
goto NeedMoar;
|
||||||
case '*':
|
case '*':
|
||||||
w = va_arg(va, int);
|
w[dot] = va_arg(va, int);
|
||||||
goto NeedMoar;
|
goto NeedMoar;
|
||||||
case 'd':
|
case 'd':
|
||||||
d = va_arg(va, long);
|
d = va_arg(va, long);
|
||||||
ApiAbuse:
|
ApiAbuse:
|
||||||
if (p + 22 <= e) {
|
x = d;
|
||||||
if (d || !plus) {
|
if (d < 0) {
|
||||||
if (d > 0 && plus) {
|
x = -x;
|
||||||
*p++ = plus;
|
sign = '-';
|
||||||
}
|
}
|
||||||
p = __intcpy(p, d);
|
for (i = j = 0;;) {
|
||||||
|
z[i++] = x % 10 + '0';
|
||||||
|
if (!(x /= 10)) break;
|
||||||
|
if (thou && !(++j % 3)) {
|
||||||
|
z[i++] = thou;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sign) {
|
||||||
|
z[i++] = sign;
|
||||||
|
}
|
||||||
|
EmitNumber:
|
||||||
|
while (w[0]-- > i) {
|
||||||
|
if (p < e) *p++ = pad;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
if (p < e) *p++ = z[--i];
|
||||||
|
} while (i);
|
||||||
break;
|
break;
|
||||||
|
case 'b':
|
||||||
|
base = 1;
|
||||||
|
BinaryNumber:
|
||||||
|
i = 0;
|
||||||
|
x = va_arg(va, unsigned long);
|
||||||
|
do z[i++] = "0123456789abcdef"[x & ((1 << base) - 1)];
|
||||||
|
while ((x >>= base) && i < w[1]);
|
||||||
|
goto EmitNumber;
|
||||||
case 'p':
|
case 'p':
|
||||||
w = 12;
|
pad = '0';
|
||||||
f = '0';
|
w[0] = 12;
|
||||||
|
w[1] = 12;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case 'x':
|
case 'x':
|
||||||
x = va_arg(va, unsigned long);
|
base = 4;
|
||||||
if (x) {
|
goto BinaryNumber;
|
||||||
n = __builtin_clzl(x) ^ (sizeof(long) * 8 - 1);
|
case 'o':
|
||||||
n >>= 2;
|
base = 3;
|
||||||
n += 1;
|
goto BinaryNumber;
|
||||||
} else {
|
case 'c':
|
||||||
n = 1;
|
cstr = va_arg(va, int);
|
||||||
}
|
s = &cstr;
|
||||||
while (w-- > n) {
|
goto EmitString;
|
||||||
if (p < e) {
|
|
||||||
*p++ = f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (n--) {
|
|
||||||
if (p < e) {
|
|
||||||
*p++ = "0123456789abcdef"[(x >> (n << 2)) & 15];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'S':
|
|
||||||
n = va_arg(va, int);
|
|
||||||
/* fallthrough */
|
|
||||||
case 's':
|
case 's':
|
||||||
s = va_arg(va, const char *);
|
s = va_arg(va, const void *);
|
||||||
|
EmitString:
|
||||||
if (!s) {
|
if (!s) {
|
||||||
EmitNullString:
|
|
||||||
s = "NULL";
|
s = "NULL";
|
||||||
}
|
bits = 0;
|
||||||
if ((uintptr_t)s < PAGESIZE) {
|
} else if ((uintptr_t)s < PAGESIZE) {
|
||||||
d = (intptr_t)s;
|
d = (intptr_t)s;
|
||||||
goto ApiAbuse;
|
goto ApiAbuse;
|
||||||
}
|
}
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < w[1]; ++i) {
|
||||||
if (!s[i]) {
|
if (!bits) {
|
||||||
n = i;
|
t = ((const char *)s)[i];
|
||||||
break;
|
EmitByte:
|
||||||
}
|
if (t) {
|
||||||
}
|
if (p < e) {
|
||||||
while (w-- > n) {
|
*p++ = t;
|
||||||
if (p < e) {
|
}
|
||||||
*p++ = f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0; i < n && p < e; ++i) {
|
|
||||||
*p++ = s[i];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
S = va_arg(va, const char16_t *);
|
|
||||||
if (!S) goto EmitNullString;
|
|
||||||
while ((t = *S++)) {
|
|
||||||
if (p + 3 <= e && (t & 0xfc00) != 0xdc00) {
|
|
||||||
if (t <= 0x7ff) {
|
|
||||||
p[0] = 0300 | t >> 6;
|
|
||||||
p[1] = 0200 | x << 8 | t & 077;
|
|
||||||
p += 2;
|
|
||||||
} else {
|
} else {
|
||||||
if (t > 0xffff) t = 0xfffd;
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t = ((const char16_t *)s)[i];
|
||||||
|
if (t <= 0x7f) {
|
||||||
|
goto EmitByte;
|
||||||
|
} else if (t <= 0x7ff) {
|
||||||
|
if (p + 1 < e) {
|
||||||
|
p[0] = 0300 | t >> 6;
|
||||||
|
p[1] = 0200 | x << 8 | t & 077;
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
} else if (p + 2 < e) {
|
||||||
p[0] = 0340 | t >> 12;
|
p[0] = 0340 | t >> 12;
|
||||||
p[1] = 0200 | x << 8 | (t >> 6) & 077;
|
p[1] = 0200 | x << 8 | (t >> 6) & 077;
|
||||||
p[2] = 0200 | x << 8 | t & 077;
|
p[2] = 0200 | x << 8 | t & 077;
|
||||||
|
@ -155,6 +190,9 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
while (w[0]-- > i) {
|
||||||
|
if (p < e) *p++ = pad;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -186,8 +224,8 @@ privileged noasan noinstrument void __printf(const char *fmt, ...) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
asm volatile("syscall"
|
asm volatile("syscall"
|
||||||
: "=a"(ax)
|
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
|
||||||
: "0"(__NR_write), "D"(2), "S"(b), "d"(p - b)
|
: "0"(__NR_write), "1"(2L), "2"(b), "3"(p - b)
|
||||||
: "rcx", "r11", "memory");
|
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
37
libc/intrin/printsystemmappings.c
Normal file
37
libc/intrin/printsystemmappings.c
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/log/libfatal.internal.h"
|
||||||
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
privileged void PrintSystemMappings(int outfd) {
|
||||||
|
int infd;
|
||||||
|
ssize_t rc;
|
||||||
|
char buf[64];
|
||||||
|
if (!IsWindows()) {
|
||||||
|
if ((infd = __sysv_open("/proc/self/maps", O_RDONLY, 0)) >= 0) {
|
||||||
|
__sysv_write(outfd, "\n", 1);
|
||||||
|
while ((rc = __sysv_read(infd, buf, sizeof(buf))) > 0) {
|
||||||
|
__sysv_write(outfd, buf, rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__sysv_close(infd);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,384 +19,165 @@
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
||||||
.macro .acall fn:req
|
|
||||||
xor %eax,%eax
|
|
||||||
mov $1,%r10b
|
|
||||||
cmpxchg %r10b,__asan_noreentry(%rip)
|
|
||||||
jnz 2f
|
|
||||||
call \fn
|
|
||||||
decb __asan_noreentry(%rip)
|
|
||||||
2: nop
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.rodata.cst4
|
.rodata.cst4
|
||||||
__asan_option_detect_stack_use_after_return:
|
__asan_option_detect_stack_use_after_return:
|
||||||
.long 0
|
.long 0
|
||||||
.endobj __asan_option_detect_stack_use_after_return,globl
|
.endobj __asan_option_detect_stack_use_after_return,globl
|
||||||
.previous
|
.previous
|
||||||
|
|
||||||
.bss
|
|
||||||
__asan_noreentry:
|
|
||||||
.byte 0
|
|
||||||
.endobj __asan_noreentry
|
|
||||||
.previous
|
|
||||||
|
|
||||||
__asan_report_load1:
|
__asan_report_load1:
|
||||||
push %rbp
|
push $1
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $1,%esi
|
|
||||||
.acall __asan_report_load
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_load1,globl
|
.endfn __asan_report_load1,globl
|
||||||
|
|
||||||
__asan_report_load2:
|
__asan_report_load2:
|
||||||
push %rbp
|
push $2
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $2,%esi
|
|
||||||
.acall __asan_report_load
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_load2,globl
|
.endfn __asan_report_load2,globl
|
||||||
|
|
||||||
__asan_report_load4:
|
__asan_report_load4:
|
||||||
push %rbp
|
push $4
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $4,%esi
|
|
||||||
.acall __asan_report_load
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_load4,globl
|
.endfn __asan_report_load4,globl
|
||||||
|
|
||||||
__asan_report_load8:
|
__asan_report_load8:
|
||||||
push %rbp
|
push $8
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $8,%esi
|
|
||||||
.acall __asan_report_load
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_load8,globl
|
.endfn __asan_report_load8,globl
|
||||||
|
|
||||||
__asan_report_load16:
|
__asan_report_load16:
|
||||||
push %rbp
|
push $16
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $16,%esi
|
|
||||||
.acall __asan_report_load
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_load16,globl
|
.endfn __asan_report_load16,globl
|
||||||
|
|
||||||
__asan_report_load32:
|
__asan_report_load32:
|
||||||
push %rbp
|
push $32
|
||||||
mov %rsp,%rbp
|
1: pop %rsi
|
||||||
.profilable
|
0: jmp __asan_report_load
|
||||||
mov $32,%esi
|
|
||||||
.acall __asan_report_load
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_load32,globl
|
.endfn __asan_report_load32,globl
|
||||||
|
|
||||||
__asan_report_load_n:
|
__asan_report_load_n:
|
||||||
push %rbp
|
jmp 0b
|
||||||
mov %rsp,%rbp
|
|
||||||
.profilable
|
|
||||||
.acall __asan_report_load
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_load_n,globl
|
.endfn __asan_report_load_n,globl
|
||||||
|
|
||||||
__asan_report_store1:
|
__asan_report_store1:
|
||||||
push %rbp
|
push $1
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $1,%esi
|
|
||||||
.acall __asan_report_store
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_store1,globl
|
.endfn __asan_report_store1,globl
|
||||||
|
|
||||||
__asan_report_store2:
|
__asan_report_store2:
|
||||||
push %rbp
|
push $2
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $2,%esi
|
|
||||||
.acall __asan_report_store
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_store2,globl
|
.endfn __asan_report_store2,globl
|
||||||
|
|
||||||
__asan_report_store4:
|
__asan_report_store4:
|
||||||
push %rbp
|
push $4
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $4,%esi
|
|
||||||
.acall __asan_report_store
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_store4,globl
|
.endfn __asan_report_store4,globl
|
||||||
|
|
||||||
__asan_report_store8:
|
__asan_report_store8:
|
||||||
push %rbp
|
push $8
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $8,%esi
|
|
||||||
.acall __asan_report_store
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_store8,globl
|
.endfn __asan_report_store8,globl
|
||||||
|
|
||||||
__asan_report_store16:
|
__asan_report_store16:
|
||||||
push %rbp
|
push $16
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $16,%esi
|
|
||||||
.acall __asan_report_store
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_store16,globl
|
.endfn __asan_report_store16,globl
|
||||||
|
|
||||||
__asan_report_store32:
|
__asan_report_store32:
|
||||||
push %rbp
|
push $32
|
||||||
mov %rsp,%rbp
|
1: pop %rsi
|
||||||
.profilable
|
0: jmp __asan_report_store
|
||||||
mov $32,%esi
|
|
||||||
.acall __asan_report_store
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_store32,globl
|
.endfn __asan_report_store32,globl
|
||||||
|
|
||||||
__asan_report_store_n:
|
__asan_report_store_n:
|
||||||
push %rbp
|
jmp 0b
|
||||||
mov %rsp,%rbp
|
|
||||||
.profilable
|
|
||||||
.acall __asan_report_store
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_report_store_n,globl
|
.endfn __asan_report_store_n,globl
|
||||||
|
|
||||||
__asan_stack_free_0:
|
__asan_stack_free_0:
|
||||||
push %rbp
|
push $0
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $0,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_0,globl
|
.endfn __asan_stack_free_0,globl
|
||||||
|
|
||||||
__asan_stack_free_1:
|
__asan_stack_free_1:
|
||||||
push %rbp
|
push $1
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $1,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_1,globl
|
.endfn __asan_stack_free_1,globl
|
||||||
|
|
||||||
__asan_stack_free_2:
|
__asan_stack_free_2:
|
||||||
push %rbp
|
push $2
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $2,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_2,globl
|
.endfn __asan_stack_free_2,globl
|
||||||
|
|
||||||
__asan_stack_free_3:
|
__asan_stack_free_3:
|
||||||
push %rbp
|
push $3
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $3,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_3,globl
|
.endfn __asan_stack_free_3,globl
|
||||||
|
|
||||||
__asan_stack_free_4:
|
__asan_stack_free_4:
|
||||||
push %rbp
|
push $4
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $4,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_4,globl
|
.endfn __asan_stack_free_4,globl
|
||||||
|
|
||||||
__asan_stack_free_5:
|
__asan_stack_free_5:
|
||||||
push %rbp
|
push $5
|
||||||
mov %rsp,%rbp
|
|
||||||
.profilable
|
|
||||||
mov $5,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_5,globl
|
.endfn __asan_stack_free_5,globl
|
||||||
|
__asan_stack_free_hop:
|
||||||
|
1: pop %rdx
|
||||||
|
jmp __asan_stack_free
|
||||||
|
.endfn __asan_report_store_n,globl
|
||||||
__asan_stack_free_6:
|
__asan_stack_free_6:
|
||||||
push %rbp
|
push $6
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $6,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_6,globl
|
.endfn __asan_stack_free_6,globl
|
||||||
|
|
||||||
__asan_stack_free_7:
|
__asan_stack_free_7:
|
||||||
push %rbp
|
push $7
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $7,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_7,globl
|
.endfn __asan_stack_free_7,globl
|
||||||
|
|
||||||
__asan_stack_free_8:
|
__asan_stack_free_8:
|
||||||
push %rbp
|
push $8
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $8,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_8,globl
|
.endfn __asan_stack_free_8,globl
|
||||||
|
|
||||||
__asan_stack_free_9:
|
__asan_stack_free_9:
|
||||||
push %rbp
|
push $9
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $9,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_9,globl
|
.endfn __asan_stack_free_9,globl
|
||||||
|
|
||||||
__asan_stack_free_10:
|
__asan_stack_free_10:
|
||||||
push %rbp
|
push $10
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $10,%edx
|
|
||||||
call __asan_stack_free
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_free_10,globl
|
.endfn __asan_stack_free_10,globl
|
||||||
|
|
||||||
__asan_stack_malloc_0:
|
__asan_stack_malloc_0:
|
||||||
push %rbp
|
push $0
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $0,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_0,globl
|
.endfn __asan_stack_malloc_0,globl
|
||||||
|
|
||||||
__asan_stack_malloc_1:
|
__asan_stack_malloc_1:
|
||||||
push %rbp
|
push $1
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $1,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_1,globl
|
.endfn __asan_stack_malloc_1,globl
|
||||||
|
|
||||||
__asan_stack_malloc_2:
|
__asan_stack_malloc_2:
|
||||||
push %rbp
|
push $2
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $2,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_2,globl
|
.endfn __asan_stack_malloc_2,globl
|
||||||
|
|
||||||
__asan_stack_malloc_3:
|
__asan_stack_malloc_3:
|
||||||
push %rbp
|
push $3
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $3,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_3,globl
|
.endfn __asan_stack_malloc_3,globl
|
||||||
|
|
||||||
__asan_stack_malloc_4:
|
__asan_stack_malloc_4:
|
||||||
push %rbp
|
push $4
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $4,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_4,globl
|
.endfn __asan_stack_malloc_4,globl
|
||||||
|
|
||||||
__asan_stack_malloc_5:
|
__asan_stack_malloc_5:
|
||||||
push %rbp
|
push $5
|
||||||
mov %rsp,%rbp
|
jmp 1f
|
||||||
.profilable
|
|
||||||
mov $5,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_5,globl
|
.endfn __asan_stack_malloc_5,globl
|
||||||
|
__asan_stack_malloc_hop:
|
||||||
|
1: pop %rsi
|
||||||
|
jmp __asan_stack_malloc
|
||||||
|
.endfn __asan_report_store_n,globl
|
||||||
__asan_stack_malloc_6:
|
__asan_stack_malloc_6:
|
||||||
push %rbp
|
push $6
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $6,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_6,globl
|
.endfn __asan_stack_malloc_6,globl
|
||||||
|
|
||||||
__asan_stack_malloc_7:
|
__asan_stack_malloc_7:
|
||||||
push %rbp
|
push $7
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $7,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_7,globl
|
.endfn __asan_stack_malloc_7,globl
|
||||||
|
|
||||||
__asan_stack_malloc_8:
|
__asan_stack_malloc_8:
|
||||||
push %rbp
|
push $8
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $8,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_8,globl
|
.endfn __asan_stack_malloc_8,globl
|
||||||
|
|
||||||
__asan_stack_malloc_9:
|
__asan_stack_malloc_9:
|
||||||
push %rbp
|
push $9
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $9,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_9,globl
|
.endfn __asan_stack_malloc_9,globl
|
||||||
|
|
||||||
__asan_stack_malloc_10:
|
__asan_stack_malloc_10:
|
||||||
push %rbp
|
push $10
|
||||||
mov %rsp,%rbp
|
jmp 1b
|
||||||
.profilable
|
|
||||||
mov $10,%esi
|
|
||||||
call __asan_stack_malloc
|
|
||||||
pop %rbp
|
|
||||||
ret
|
|
||||||
.endfn __asan_stack_malloc_10,globl
|
.endfn __asan_stack_malloc_10,globl
|
||||||
|
|
||||||
__asan_version_mismatch_check_v8:
|
__asan_version_mismatch_check_v8:
|
||||||
|
|
|
@ -17,8 +17,49 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
.privileged
|
||||||
|
|
||||||
|
// Invokes SYSCALL for libfatal forceinline asm() routines.
|
||||||
|
//
|
||||||
|
// @param rax is ordinal
|
||||||
|
// @param rdi is arg1
|
||||||
|
// @param rsi is arg2
|
||||||
|
// @param rdx is arg3
|
||||||
|
// @param rcx is arg4
|
||||||
|
// @param r8 is arg5
|
||||||
|
// @param r9 is arg6
|
||||||
|
// @param rsp may contain more args
|
||||||
|
// @return rdx:rax where rax holds -errno on error
|
||||||
|
// @clob rax,rdx,memory,cc
|
||||||
__syscall__:
|
__syscall__:
|
||||||
|
mov %rcx,.Lrcx(%rip)
|
||||||
|
mov %rdi,.Lrdi(%rip)
|
||||||
|
mov %rsi,.Lrsi(%rip)
|
||||||
|
mov %r8,.Lr8(%rip)
|
||||||
|
mov %r9,.Lr9(%rip)
|
||||||
|
mov %r10,.Lr10(%rip)
|
||||||
|
mov %r11,.Lr11(%rip)
|
||||||
|
mov %rcx,%r10
|
||||||
|
clc
|
||||||
syscall
|
syscall
|
||||||
|
jnc 1f
|
||||||
|
neg %rax
|
||||||
|
1: mov .Lrcx(%rip),%rcx
|
||||||
|
mov .Lrdi(%rip),%rdi
|
||||||
|
mov .Lrsi(%rip),%rsi
|
||||||
|
mov .Lr8(%rip),%r8
|
||||||
|
mov .Lr9(%rip),%r9
|
||||||
|
mov .Lr10(%rip),%r10
|
||||||
|
mov .Lr11(%rip),%r11
|
||||||
ret
|
ret
|
||||||
.endfn __syscall__,globl,hidden
|
.endfn __syscall__,globl,hidden
|
||||||
|
|
||||||
|
.bss
|
||||||
|
.align 8
|
||||||
|
.Lrcx: .quad 0 # clobbered by syscall
|
||||||
|
.Lrdi: .quad 0 # just in case
|
||||||
|
.Lrsi: .quad 0 # just in case
|
||||||
|
.Lr8: .quad 0 # freebsd bug?
|
||||||
|
.Lr9: .quad 0 # just in case
|
||||||
|
.Lr10: .quad 0 # just in case
|
||||||
|
.Lr11: .quad 0 # clobbered by syscall
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/runtime/internal.h"
|
#include "libc/runtime/internal.h"
|
||||||
|
@ -151,55 +152,19 @@ static bool __ubsan_negative(struct UbsanTypeDescriptor *t, uintptr_t x) {
|
||||||
return __ubsan_signed(t) && (intptr_t)x < 0;
|
return __ubsan_signed(t) && (intptr_t)x < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t __ubsan_strlen(const char *s) {
|
|
||||||
size_t n = 0;
|
|
||||||
while (*s++) ++n;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *__ubsan_stpcpy(char *d, const char *s) {
|
|
||||||
size_t i;
|
|
||||||
for (i = 0;; ++i) {
|
|
||||||
if (!(d[i] = s[i])) {
|
|
||||||
return d + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *__ubsan_poscpy(char *p, uintptr_t i) {
|
|
||||||
int j = 0;
|
|
||||||
do {
|
|
||||||
p[j++] = i % 10 + '0';
|
|
||||||
i /= 10;
|
|
||||||
} while (i > 0);
|
|
||||||
reverse(p, j);
|
|
||||||
return p + j;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *__ubsan_intcpy(char *p, intptr_t i) {
|
|
||||||
if (i >= 0) return __ubsan_poscpy(p, i);
|
|
||||||
*p++ = '-';
|
|
||||||
return __ubsan_poscpy(p, -i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *__ubsan_hexcpy(char *p, uintptr_t x, int k) {
|
|
||||||
while (k) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15];
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *__ubsan_itpcpy(char *p, struct UbsanTypeDescriptor *t,
|
static char *__ubsan_itpcpy(char *p, struct UbsanTypeDescriptor *t,
|
||||||
uintptr_t x) {
|
uintptr_t x) {
|
||||||
if (__ubsan_signed(t)) {
|
if (__ubsan_signed(t)) {
|
||||||
return __ubsan_intcpy(p, x);
|
return __intcpy(p, x);
|
||||||
} else {
|
} else {
|
||||||
return __ubsan_poscpy(p, x);
|
return __uintcpy(p, x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *__ubsan_dubnul(const char *s, unsigned i) {
|
static const char *__ubsan_dubnul(const char *s, unsigned i) {
|
||||||
size_t n;
|
size_t n;
|
||||||
while (i--) {
|
while (i--) {
|
||||||
if ((n = __ubsan_strlen(s))) {
|
if ((n = __strlen(s))) {
|
||||||
s += n + 1;
|
s += n + 1;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -222,53 +187,11 @@ static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t x) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static privileged noinline wontreturn void __ubsan_exit(int rc) {
|
|
||||||
if (!IsWindows()) {
|
|
||||||
asm volatile("syscall"
|
|
||||||
: /* no outputs */
|
|
||||||
: "a"(__NR_exit_group), "D"(rc)
|
|
||||||
: "memory");
|
|
||||||
unreachable;
|
|
||||||
} else {
|
|
||||||
ExitProcess(rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static privileged noinline ssize_t __ubsan_write(const void *data,
|
|
||||||
size_t size) {
|
|
||||||
ssize_t rc;
|
|
||||||
uint32_t wrote;
|
|
||||||
if (!IsWindows()) {
|
|
||||||
asm volatile("syscall"
|
|
||||||
: "=a"(rc)
|
|
||||||
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
|
|
||||||
: "rcx", "r11", "memory");
|
|
||||||
return rc;
|
|
||||||
} else {
|
|
||||||
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
|
|
||||||
return wrote;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t __ubsan_write_string(const char *s) {
|
|
||||||
return __ubsan_write(s, __ubsan_strlen(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
void __ubsan_abort(const struct UbsanSourceLocation *loc,
|
void __ubsan_abort(const struct UbsanSourceLocation *loc,
|
||||||
const char *description) {
|
const char *description) {
|
||||||
char buf[1024], *p = buf;
|
__printf("\r\n%s:%d: ubsan error: %s\r\n", loc->file, loc->line, description);
|
||||||
p = __ubsan_stpcpy(p, "error: ");
|
|
||||||
p = __ubsan_stpcpy(p, loc->file), *p++ = ':';
|
|
||||||
p = __ubsan_intcpy(p, loc->line);
|
|
||||||
p = __ubsan_stpcpy(p, ": ");
|
|
||||||
p = __ubsan_stpcpy(p, description);
|
|
||||||
p = __ubsan_stpcpy(p, "\r\n");
|
|
||||||
__ubsan_write_string(buf);
|
|
||||||
if (weaken(__die)) weaken(__die)();
|
if (weaken(__die)) weaken(__die)();
|
||||||
__ubsan_exit(134);
|
_Exit(134);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *__ubsan_describe_shift(
|
static const char *__ubsan_describe_shift(
|
||||||
|
@ -291,11 +214,11 @@ void __ubsan_handle_shift_out_of_bounds(struct UbsanShiftOutOfBoundsInfo *info,
|
||||||
char buf[512], *p = buf;
|
char buf[512], *p = buf;
|
||||||
lhs = __ubsan_extend(info->lhs_type, lhs);
|
lhs = __ubsan_extend(info->lhs_type, lhs);
|
||||||
rhs = __ubsan_extend(info->rhs_type, rhs);
|
rhs = __ubsan_extend(info->rhs_type, rhs);
|
||||||
p = __ubsan_stpcpy(p, __ubsan_describe_shift(info, lhs, rhs)), *p++ = ' ';
|
p = __stpcpy(p, __ubsan_describe_shift(info, lhs, rhs)), *p++ = ' ';
|
||||||
p = __ubsan_itpcpy(p, info->lhs_type, lhs), *p++ = ' ';
|
p = __ubsan_itpcpy(p, info->lhs_type, lhs), *p++ = ' ';
|
||||||
p = __ubsan_stpcpy(p, info->lhs_type->name), *p++ = ' ';
|
p = __stpcpy(p, info->lhs_type->name), *p++ = ' ';
|
||||||
p = __ubsan_itpcpy(p, info->rhs_type, rhs), *p++ = ' ';
|
p = __ubsan_itpcpy(p, info->rhs_type, rhs), *p++ = ' ';
|
||||||
p = __ubsan_stpcpy(p, info->rhs_type->name);
|
p = __stpcpy(p, info->rhs_type->name);
|
||||||
__ubsan_abort(&info->location, buf);
|
__ubsan_abort(&info->location, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,12 +230,12 @@ void __ubsan_handle_shift_out_of_bounds_abort(
|
||||||
void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info,
|
void __ubsan_handle_out_of_bounds(struct UbsanOutOfBoundsInfo *info,
|
||||||
uintptr_t index) {
|
uintptr_t index) {
|
||||||
char buf[512], *p = buf;
|
char buf[512], *p = buf;
|
||||||
p = __ubsan_stpcpy(p, info->index_type->name);
|
p = __stpcpy(p, info->index_type->name);
|
||||||
p = __ubsan_stpcpy(p, " index ");
|
p = __stpcpy(p, " index ");
|
||||||
p = __ubsan_itpcpy(p, info->index_type, index);
|
p = __ubsan_itpcpy(p, info->index_type, index);
|
||||||
p = __ubsan_stpcpy(p, " into ");
|
p = __stpcpy(p, " into ");
|
||||||
p = __ubsan_stpcpy(p, info->array_type->name);
|
p = __stpcpy(p, info->array_type->name);
|
||||||
p = __ubsan_stpcpy(p, " out of bounds");
|
p = __stpcpy(p, " out of bounds");
|
||||||
__ubsan_abort(&info->location, buf);
|
__ubsan_abort(&info->location, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,19 +251,19 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
|
||||||
if (!pointer) __ubsan_abort(&info->location, "null pointer access");
|
if (!pointer) __ubsan_abort(&info->location, "null pointer access");
|
||||||
kind = __ubsan_dubnul(kUbsanTypeCheckKinds, info->type_check_kind);
|
kind = __ubsan_dubnul(kUbsanTypeCheckKinds, info->type_check_kind);
|
||||||
if (info->alignment && (pointer & (info->alignment - 1))) {
|
if (info->alignment && (pointer & (info->alignment - 1))) {
|
||||||
p = __ubsan_stpcpy(p, "unaligned ");
|
p = __stpcpy(p, "unaligned ");
|
||||||
p = __ubsan_stpcpy(p, kind), *p++ = ' ';
|
p = __stpcpy(p, kind), *p++ = ' ';
|
||||||
p = __ubsan_stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
|
p = __stpcpy(p, info->type->name), *p++ = ' ', *p++ = '@';
|
||||||
p = __ubsan_itpcpy(p, info->type, pointer);
|
p = __ubsan_itpcpy(p, info->type, pointer);
|
||||||
p = __ubsan_stpcpy(p, " align ");
|
p = __stpcpy(p, " align ");
|
||||||
p = __ubsan_intcpy(p, info->alignment);
|
p = __intcpy(p, info->alignment);
|
||||||
} else {
|
} else {
|
||||||
p = __ubsan_stpcpy(p, "insufficient size\r\n\t");
|
p = __stpcpy(p, "insufficient size\r\n\t");
|
||||||
p = __ubsan_stpcpy(p, kind);
|
p = __stpcpy(p, kind);
|
||||||
p = __ubsan_stpcpy(p, " address 0x");
|
p = __stpcpy(p, " address 0x");
|
||||||
p = __ubsan_hexcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
|
p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT);
|
||||||
p = __ubsan_stpcpy(p, " with insufficient space for object of type ");
|
p = __stpcpy(p, " with insufficient space for object of type ");
|
||||||
p = __ubsan_stpcpy(p, info->type->name);
|
p = __stpcpy(p, info->type->name);
|
||||||
}
|
}
|
||||||
__ubsan_abort(&info->location, buf);
|
__ubsan_abort(&info->location, buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,17 @@
|
||||||
#include "libc/log/libfatal.internal.h"
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/nexgen32e/gc.internal.h"
|
#include "libc/nexgen32e/gc.internal.h"
|
||||||
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/runtime/symbols.internal.h"
|
#include "libc/runtime/symbols.internal.h"
|
||||||
|
#include "libc/stdio/append.internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/fileno.h"
|
#include "libc/sysv/consts/fileno.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
#define kBacktraceMaxFrames 128
|
#define kBacktraceMaxFrames 128
|
||||||
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
|
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
|
||||||
|
@ -168,13 +172,14 @@ static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
|
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
|
||||||
|
/* asan runtime depends on this function */
|
||||||
static bool noreentry;
|
static bool noreentry;
|
||||||
++ftrace;
|
++g_ftrace;
|
||||||
if (!bp) bp = __builtin_frame_address(0);
|
if (!bp) bp = __builtin_frame_address(0);
|
||||||
if (!noreentry) {
|
if (!noreentry) {
|
||||||
noreentry = true;
|
noreentry = true;
|
||||||
PrintBacktrace(fd, bp);
|
PrintBacktrace(fd, bp);
|
||||||
noreentry = false;
|
noreentry = false;
|
||||||
}
|
}
|
||||||
--ftrace;
|
--g_ftrace;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#include "libc/runtime/symbols.internal.h"
|
#include "libc/runtime/symbols.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
|
#define LIMIT 100
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints stack frames with symbols.
|
* Prints stack frames with symbols.
|
||||||
*
|
*
|
||||||
|
@ -46,14 +48,18 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
|
||||||
struct SymbolTable *st) {
|
struct SymbolTable *st) {
|
||||||
size_t gi;
|
size_t gi;
|
||||||
intptr_t addr;
|
intptr_t addr;
|
||||||
int symbol, addend;
|
int i, symbol, addend;
|
||||||
struct Garbages *garbage;
|
struct Garbages *garbage;
|
||||||
const struct StackFrame *frame;
|
const struct StackFrame *frame;
|
||||||
++ftrace;
|
++g_ftrace;
|
||||||
if (!bp) bp = __builtin_frame_address(0);
|
if (!bp) bp = __builtin_frame_address(0);
|
||||||
garbage = weaken(__garbage);
|
garbage = weaken(__garbage);
|
||||||
gi = garbage ? garbage->i : 0;
|
gi = garbage ? garbage->i : 0;
|
||||||
for (frame = bp; frame; frame = frame->next) {
|
for (i = 0, frame = bp; frame; frame = frame->next) {
|
||||||
|
if (++i == LIMIT) {
|
||||||
|
__printf("<truncated backtrace>\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
addr = frame->addr;
|
addr = frame->addr;
|
||||||
if (addr == weakaddr("__gc")) {
|
if (addr == weakaddr("__gc")) {
|
||||||
do {
|
do {
|
||||||
|
@ -68,15 +74,16 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
|
||||||
* __restore_rt where the kernel creates a stack frame that points
|
* __restore_rt where the kernel creates a stack frame that points
|
||||||
* to the beginning of the function.
|
* to the beginning of the function.
|
||||||
*/
|
*/
|
||||||
if ((symbol = GetSymbol(st, addr - 1)) != -1 ||
|
if ((symbol = __get_symbol(st, addr - 1)) != -1 ||
|
||||||
(symbol = GetSymbol(st, addr - 0)) != -1) {
|
(symbol = __get_symbol(st, addr - 0)) != -1) {
|
||||||
addend = addr - st->addr_base;
|
addend = addr - st->addr_base;
|
||||||
addend -= st->symbols[symbol].x;
|
addend -= st->symbols[symbol].x;
|
||||||
} else {
|
} else {
|
||||||
addend = 0;
|
addend = 0;
|
||||||
}
|
}
|
||||||
__printf("%p %p %s%+d\r\n", frame, addr, GetSymbolName(st, symbol), addend);
|
__printf("%p %p %s%+d\r\n", frame, addr, __get_symbol_name(st, symbol),
|
||||||
|
addend);
|
||||||
}
|
}
|
||||||
--ftrace;
|
--g_ftrace;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
60
libc/log/cxaprintexits.c
Normal file
60
libc/log/cxaprintexits.c
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/nexgen32e/bsf.h"
|
||||||
|
#include "libc/runtime/cxaatexit.internal.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints global destructors.
|
||||||
|
*
|
||||||
|
* @param pred can be null to match all
|
||||||
|
*/
|
||||||
|
void __cxa_printexits(FILE *f, void *pred) {
|
||||||
|
char name[23];
|
||||||
|
unsigned i, mask;
|
||||||
|
const char *symbol;
|
||||||
|
struct CxaAtexitBlock *b;
|
||||||
|
fprintf(f, "\n");
|
||||||
|
fprintf(f, " GLOBAL DESTRUCTORS \n");
|
||||||
|
fprintf(f, " callback arg pred \n");
|
||||||
|
fprintf(f, "---------------------- ------------------ ------------------\n");
|
||||||
|
if ((b = __cxa_blocks.p)) {
|
||||||
|
do {
|
||||||
|
mask = b->mask;
|
||||||
|
while (mask) {
|
||||||
|
i = bsf(mask);
|
||||||
|
mask &= ~(1u << i);
|
||||||
|
if (!pred || pred == b->p[i].pred) {
|
||||||
|
symbol = __get_symbol_by_addr((intptr_t)b->p[i].fp);
|
||||||
|
if (symbol) {
|
||||||
|
snprintf(name, sizeof(name), "%s", symbol);
|
||||||
|
} else {
|
||||||
|
snprintf(name, sizeof(name), "0x%016lx", b->p[i].fp);
|
||||||
|
}
|
||||||
|
fprintf(f, "%-22s 0x%016lx 0x%016lx\n", name, b->p[i].arg,
|
||||||
|
b->p[i].pred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ((b = b->next));
|
||||||
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
|
}
|
|
@ -29,6 +29,7 @@
|
||||||
* If a debugger is present then this will trigger a breakpoint.
|
* If a debugger is present then this will trigger a breakpoint.
|
||||||
*/
|
*/
|
||||||
relegated wontreturn void __die(void) {
|
relegated wontreturn void __die(void) {
|
||||||
|
/* asan runtime depends on this function */
|
||||||
static bool once;
|
static bool once;
|
||||||
if (cmpxchg(&once, false, true)) {
|
if (cmpxchg(&once, false, true)) {
|
||||||
__restore_tty(1);
|
__restore_tty(1);
|
||||||
|
|
|
@ -26,6 +26,6 @@
|
||||||
const char *GetCallerName(const struct StackFrame *bp) {
|
const char *GetCallerName(const struct StackFrame *bp) {
|
||||||
struct SymbolTable *st;
|
struct SymbolTable *st;
|
||||||
if (!bp && (bp = __builtin_frame_address(0))) bp = bp->next;
|
if (!bp && (bp = __builtin_frame_address(0))) bp = bp->next;
|
||||||
if (bp) return GetSymbolByAddr(bp->addr - 1);
|
if (bp) return __get_symbol_by_addr(bp->addr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
34
libc/log/getsymbolbyaddr.c
Normal file
34
libc/log/getsymbolbyaddr.c
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/runtime/symbols.internal.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns name of symbol at address.
|
||||||
|
*/
|
||||||
|
noasan char *__get_symbol_by_addr(int64_t addr) {
|
||||||
|
/* asan runtime depends on this function */
|
||||||
|
int i;
|
||||||
|
struct SymbolTable *st;
|
||||||
|
st = GetSymbolTable();
|
||||||
|
i = __get_symbol(st, addr);
|
||||||
|
if (i == -1) i = __get_symbol(st, addr - 1);
|
||||||
|
return __get_symbol_name(st, i);
|
||||||
|
}
|
|
@ -24,18 +24,16 @@
|
||||||
* Returns debug binary symbol table, as global singleton.
|
* Returns debug binary symbol table, as global singleton.
|
||||||
* @return symbol table, or NULL w/ errno on first call
|
* @return symbol table, or NULL w/ errno on first call
|
||||||
*/
|
*/
|
||||||
struct SymbolTable *GetSymbolTable(void) {
|
noasan struct SymbolTable *GetSymbolTable(void) {
|
||||||
|
/* asan runtime depends on this function */
|
||||||
static bool once;
|
static bool once;
|
||||||
static struct SymbolTable *singleton;
|
static struct SymbolTable *singleton;
|
||||||
const char *debugbin;
|
const char *debugbin;
|
||||||
if (!once) {
|
if (!once) {
|
||||||
once = true;
|
once = true;
|
||||||
++ftrace;
|
++g_ftrace;
|
||||||
if ((debugbin = FindDebugBinary()) &&
|
singleton = OpenSymbolTable(FindDebugBinary());
|
||||||
(singleton = OpenSymbolTable(debugbin))) {
|
--g_ftrace;
|
||||||
__cxa_atexit(CloseSymbolTable, &singleton, NULL);
|
|
||||||
}
|
|
||||||
--ftrace;
|
|
||||||
}
|
}
|
||||||
return singleton;
|
return singleton;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,11 @@
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
extern int kCrashSigs[8] hidden;
|
extern hidden int kCrashSigs[8];
|
||||||
extern struct termios g_oldtermios hidden;
|
extern hidden bool g_isrunningundermake;
|
||||||
extern struct sigaction g_oldcrashacts[8] hidden;
|
extern hidden bool g_isterminalinarticulate;
|
||||||
|
extern hidden struct termios g_oldtermios;
|
||||||
|
extern hidden struct sigaction g_oldcrashacts[8];
|
||||||
|
|
||||||
void __start_fatal(const char *, int) hidden;
|
void __start_fatal(const char *, int) hidden;
|
||||||
void __start_fatal_ndebug(void) hidden;
|
void __start_fatal_ndebug(void) hidden;
|
||||||
|
|
|
@ -5,42 +5,94 @@
|
||||||
#include "libc/nexgen32e/bsr.h"
|
#include "libc/nexgen32e/bsr.h"
|
||||||
#include "libc/nt/process.h"
|
#include "libc/nt/process.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
extern char __fatalbuf[];
|
extern char __fatalbuf[];
|
||||||
|
|
||||||
|
void __printf(const char *, ...);
|
||||||
|
|
||||||
|
forceinline void __sysv_exit(long rc) {
|
||||||
|
asm volatile("call\t__syscall__"
|
||||||
|
: /* no outputs */
|
||||||
|
: "a"(__NR_exit_group), "D"(rc)
|
||||||
|
: "memory", "cc");
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline int __sysv_close(long fd) {
|
||||||
|
long ax;
|
||||||
|
asm volatile("call\t__syscall__"
|
||||||
|
: "=a"(ax)
|
||||||
|
: "0"(__NR_close), "D"(fd)
|
||||||
|
: "rdx", "memory", "cc");
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline int __sysv_open(const char *path, long flags, long mode) {
|
||||||
|
long ax, dx;
|
||||||
|
asm volatile("call\t__syscall__"
|
||||||
|
: "=a"(ax), "=d"(dx)
|
||||||
|
: "0"(__NR_open), "D"(path), "S"(flags), "1"(mode)
|
||||||
|
: "memory", "cc");
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline long __sysv_read(long fd, void *data, unsigned long size) {
|
||||||
|
long ax, dx;
|
||||||
|
asm volatile("call\t__syscall__"
|
||||||
|
: "=a"(ax), "=d"(dx)
|
||||||
|
: "0"(__NR_read), "D"(fd), "S"(data), "1"(size)
|
||||||
|
: "memory", "cc");
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline long __sysv_write(long fd, const void *data, unsigned long size) {
|
||||||
|
long ax, dx;
|
||||||
|
asm volatile("call\t__syscall__"
|
||||||
|
: "=a"(ax), "=d"(dx)
|
||||||
|
: "0"(__NR_write), "D"(fd), "S"(data), "1"(size)
|
||||||
|
: "memory", "cc");
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline long __sysv_mprotect(void *addr, size_t size, long prot) {
|
||||||
|
long ax, dx;
|
||||||
|
asm volatile("call\t__syscall__"
|
||||||
|
: "=a"(ax), "=d"(dx)
|
||||||
|
: "0"(__NR_mprotect), "D"(addr), "S"(size), "1"(prot)
|
||||||
|
: "memory", "cc");
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline int __sysv_getpid(void) {
|
||||||
|
long ax;
|
||||||
|
asm volatile("call\t__syscall__"
|
||||||
|
: "=a"(ax)
|
||||||
|
: "0"(__NR_getpid)
|
||||||
|
: "rdx", "memory", "cc");
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
forceinline int __getpid(void) {
|
forceinline int __getpid(void) {
|
||||||
int rc;
|
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
asm volatile("call\t__syscall__"
|
return __sysv_getpid();
|
||||||
: "=a"(rc)
|
|
||||||
: "0"(__NR_getpid)
|
|
||||||
: "rcx", "r11", "memory");
|
|
||||||
return rc;
|
|
||||||
} else {
|
} else {
|
||||||
return GetCurrentProcessId();
|
return GetCurrentProcessId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline ssize_t __write(const void *data, size_t size) {
|
forceinline ssize_t __write(const void *p, size_t n) {
|
||||||
char cf;
|
char cf;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t wrote;
|
uint32_t wrote;
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
asm volatile("call\t__syscall__"
|
return __sysv_write(2, p, n);
|
||||||
: "=@ccc"(cf), "=a"(rc)
|
} else if (WriteFile(GetStdHandle(kNtStdErrorHandle), p, n, &wrote, 0)) {
|
||||||
: "1"(__NR_write), "D"(2), "S"(data), "d"(size)
|
return wrote;
|
||||||
: "rcx", "r11", "memory");
|
|
||||||
if (cf && IsBsd()) rc = -rc;
|
|
||||||
return rc;
|
|
||||||
} else {
|
} else {
|
||||||
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
|
return -GetLastError();
|
||||||
return wrote;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +106,12 @@ forceinline ssize_t __write_str(const char *s) {
|
||||||
return __write(s, __strlen(s));
|
return __write(s, __strlen(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceinline int __strcmp(const char *l, const char *r) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (l[i] == r[i] && r[i]) ++i;
|
||||||
|
return (l[i] & 255) - (r[i] & 255);
|
||||||
|
}
|
||||||
|
|
||||||
forceinline char *__stpcpy(char *d, const char *s) {
|
forceinline char *__stpcpy(char *d, const char *s) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0;; ++i) {
|
for (i = 0;; ++i) {
|
||||||
|
@ -63,6 +121,13 @@ forceinline char *__stpcpy(char *d, const char *s) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceinline void *__repstosb(void *di, char al, size_t cx) {
|
||||||
|
asm("rep stosb"
|
||||||
|
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||||
|
: "0"(di), "1"(cx), "a"(al));
|
||||||
|
return di;
|
||||||
|
}
|
||||||
|
|
||||||
forceinline void *__repmovsb(void *di, void *si, size_t cx) {
|
forceinline void *__repmovsb(void *di, void *si, size_t cx) {
|
||||||
asm("rep movsb"
|
asm("rep movsb"
|
||||||
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
|
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||||
|
@ -112,7 +177,64 @@ forceinline char *__hexcpy(char p[hasatleast 17], uint64_t x) {
|
||||||
return __fixcpy(p, x, ROUNDUP(x ? bsrl(x) + 1 : 1, 4));
|
return __fixcpy(p, x, ROUNDUP(x ? bsrl(x) + 1 : 1, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void __printf(const char *, ...);
|
forceinline const void *__memchr(const void *s, unsigned char c, size_t n) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
if (((const unsigned char *)s)[i] == c) {
|
||||||
|
return (const unsigned char *)s + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline char *__strstr(const char *haystack, const char *needle) {
|
||||||
|
size_t i;
|
||||||
|
for (;;) {
|
||||||
|
for (i = 0;; ++i) {
|
||||||
|
if (!needle[i]) return (/*unconst*/ char *)haystack;
|
||||||
|
if (!haystack[i]) break;
|
||||||
|
if (needle[i] != haystack[i]) break;
|
||||||
|
}
|
||||||
|
if (!*haystack++) break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline char *__getenv(char **p, const char *s) {
|
||||||
|
size_t i, j;
|
||||||
|
if (p) {
|
||||||
|
for (i = 0; p[i]; ++i) {
|
||||||
|
for (j = 0;; ++j) {
|
||||||
|
if (!s[j]) {
|
||||||
|
if (p[i][j] == '=') {
|
||||||
|
return p[i] + j + 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (s[j] != p[i][j]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline unsigned long __atoul(const char *p) {
|
||||||
|
int c;
|
||||||
|
unsigned long x = 0;
|
||||||
|
while ('0' <= (c = *p++) && c <= '9') x *= 10, x += c - '0';
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline long __atol(const char *p) {
|
||||||
|
int s = *p;
|
||||||
|
unsigned long x;
|
||||||
|
if (s == '-' || s == '+') ++p;
|
||||||
|
x = __atoul(p);
|
||||||
|
if (s == '-') x = -x;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -55,8 +55,8 @@ bool32 IsDebuggerPresent(bool);
|
||||||
bool IsRunningUnderMake(void);
|
bool IsRunningUnderMake(void);
|
||||||
const char *GetSiCodeName(int, int);
|
const char *GetSiCodeName(int, int);
|
||||||
void AppendResourceReport(char **, struct rusage *, const char *);
|
void AppendResourceReport(char **, struct rusage *, const char *);
|
||||||
char *GetSymbolByAddr(int64_t);
|
char *__get_symbol_by_addr(int64_t);
|
||||||
void PrintGarbage(FILE *);
|
void PrintGarbage(void);
|
||||||
void PrintGarbageNumeric(FILE *);
|
void PrintGarbageNumeric(FILE *);
|
||||||
|
|
||||||
#define showcrashreports() ShowCrashReports()
|
#define showcrashreports() ShowCrashReports()
|
||||||
|
@ -75,15 +75,15 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
// log a message with the specified log level (not checking if LOGGABLE)
|
// log a message with the specified log level (not checking if LOGGABLE)
|
||||||
#define LOGF(LEVEL, FMT, ...) \
|
#define LOGF(LEVEL, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// die with an error message without backtrace and debugger invocation
|
// die with an error message without backtrace and debugger invocation
|
||||||
#define DIEF(FMT, ...) \
|
#define DIEF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
unreachable; \
|
unreachable; \
|
||||||
|
@ -91,7 +91,7 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
|
|
||||||
#define FATALF(FMT, ...) \
|
#define FATALF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
unreachable; \
|
unreachable; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -99,78 +99,78 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
#define ERRORF(FMT, ...) \
|
#define ERRORF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogError)) { \
|
if (LOGGABLE(kLogError)) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define WARNF(FMT, ...) \
|
#define WARNF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogWarn)) { \
|
if (LOGGABLE(kLogWarn)) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define INFOF(FMT, ...) \
|
#define INFOF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogInfo)) { \
|
if (LOGGABLE(kLogInfo)) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define VERBOSEF(FMT, ...) \
|
#define VERBOSEF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogVerbose)) { \
|
if (LOGGABLE(kLogVerbose)) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define DEBUGF(FMT, ...) \
|
#define DEBUGF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define NOISEF(FMT, ...) \
|
#define NOISEF(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define FLOGF(F, FMT, ...) \
|
#define FLOGF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogInfo)) { \
|
if (LOGGABLE(kLogInfo)) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define FWARNF(F, FMT, ...) \
|
#define FWARNF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (LOGGABLE(kLogWarn)) { \
|
if (LOGGABLE(kLogWarn)) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define FFATALF(F, FMT, ...) \
|
#define FFATALF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
unreachable; \
|
unreachable; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -178,18 +178,18 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
#define FDEBUGF(F, FMT, ...) \
|
#define FDEBUGF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define FNOISEF(F, FMT, ...) \
|
#define FNOISEF(F, FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -201,9 +201,9 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
({ \
|
({ \
|
||||||
autotype(FORM) Ax = (FORM); \
|
autotype(FORM) Ax = (FORM); \
|
||||||
if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \
|
if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
__logerrno(__FILE__, __LINE__, #FORM); \
|
__logerrno(__FILE__, __LINE__, #FORM); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
Ax; \
|
Ax; \
|
||||||
})
|
})
|
||||||
|
@ -212,9 +212,9 @@ extern unsigned __log_level; /* log level for runtime check */
|
||||||
({ \
|
({ \
|
||||||
autotype(FORM) Ax = (FORM); \
|
autotype(FORM) Ax = (FORM); \
|
||||||
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
|
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
|
||||||
++ftrace; \
|
++g_ftrace; \
|
||||||
__logerrno(__FILE__, __LINE__, #FORM); \
|
__logerrno(__FILE__, __LINE__, #FORM); \
|
||||||
--ftrace; \
|
--g_ftrace; \
|
||||||
} \
|
} \
|
||||||
Ax; \
|
Ax; \
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
|
@ -44,6 +45,7 @@
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
#include "libc/runtime/pc.internal.h"
|
#include "libc/runtime/pc.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/auxv.h"
|
#include "libc/sysv/consts/auxv.h"
|
||||||
#include "libc/sysv/consts/fileno.h"
|
#include "libc/sysv/consts/fileno.h"
|
||||||
|
@ -94,20 +96,23 @@ relegated static const char *TinyStrSignal(int sig) {
|
||||||
return "???";
|
return "???";
|
||||||
}
|
}
|
||||||
|
|
||||||
relegated static void ShowFunctionCalls(int fd, ucontext_t *ctx) {
|
relegated static void ShowFunctionCalls(ucontext_t *ctx) {
|
||||||
struct StackFrame *bp;
|
struct StackFrame *bp;
|
||||||
struct StackFrame goodframe;
|
struct StackFrame goodframe;
|
||||||
write(fd, "\n", 1);
|
if (ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
|
||||||
if (ctx && ctx->uc_mcontext.rip && ctx->uc_mcontext.rbp) {
|
|
||||||
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
|
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
|
||||||
goodframe.addr = ctx->uc_mcontext.rip;
|
goodframe.addr = ctx->uc_mcontext.rip;
|
||||||
bp = &goodframe;
|
bp = &goodframe;
|
||||||
ShowBacktrace(fd, bp);
|
ShowBacktrace(2, bp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relegated static char *AddFlag(char *p, int b, const char *s) {
|
relegated static char *AddFlag(char *p, int b, const char *s) {
|
||||||
if (b) p = stpcpy(p, s);
|
if (b) {
|
||||||
|
p = __stpcpy(p, s);
|
||||||
|
} else {
|
||||||
|
*p = 0;
|
||||||
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,11 +142,13 @@ relegated static char *DescribeCpuFlags(char *p, int flags, int x87sw,
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
relegated static char *ShowGeneralRegisters(char *p, ucontext_t *ctx) {
|
relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
|
||||||
int64_t x;
|
int64_t x;
|
||||||
const char *s;
|
const char *s;
|
||||||
size_t i, j, k;
|
size_t i, j, k;
|
||||||
long double st;
|
long double st;
|
||||||
|
char *p, buf[128];
|
||||||
|
p = buf;
|
||||||
*p++ = '\n';
|
*p++ = '\n';
|
||||||
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
|
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
|
||||||
if (j > 0) *p++ = ' ';
|
if (j > 0) *p++ = ' ';
|
||||||
|
@ -162,20 +169,25 @@ relegated static char *ShowGeneralRegisters(char *p, ucontext_t *ctx) {
|
||||||
if (x < 0) x = -x, *p++ = '-';
|
if (x < 0) x = -x, *p++ = '-';
|
||||||
p = __uintcpy(p, x / 1000), *p++ = '.';
|
p = __uintcpy(p, x / 1000), *p++ = '.';
|
||||||
p = __uintcpy(p, x % 1000), *p++ = '\n';
|
p = __uintcpy(p, x % 1000), *p++ = '\n';
|
||||||
|
*p = 0;
|
||||||
|
__printf("%s", buf);
|
||||||
|
p = buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return DescribeCpuFlags(
|
DescribeCpuFlags(
|
||||||
p, ctx->uc_mcontext.gregs[REG_EFL],
|
p, ctx->uc_mcontext.gregs[REG_EFL],
|
||||||
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0,
|
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0,
|
||||||
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0);
|
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0);
|
||||||
|
__printf("%s\n", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
relegated static char *ShowSseRegisters(char *p, ucontext_t *ctx) {
|
relegated static void ShowSseRegisters(ucontext_t *ctx) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
char *p, buf[128];
|
||||||
if (ctx->uc_mcontext.fpregs) {
|
if (ctx->uc_mcontext.fpregs) {
|
||||||
p = __stpcpy(p, "\n\n");
|
__printf("\n");
|
||||||
for (i = 0; i < 8; ++i) {
|
for (i = 0; i < 8; ++i) {
|
||||||
p = __stpcpy(p, "XMM");
|
p = buf;
|
||||||
if (i >= 10) {
|
if (i >= 10) {
|
||||||
*p++ = i / 10 + '0';
|
*p++ = i / 10 + '0';
|
||||||
*p++ = i % 10 + '0';
|
*p++ = i % 10 + '0';
|
||||||
|
@ -197,93 +209,61 @@ relegated static char *ShowSseRegisters(char *p, ucontext_t *ctx) {
|
||||||
*p++ = ' ';
|
*p++ = ' ';
|
||||||
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64);
|
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64);
|
||||||
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64);
|
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64);
|
||||||
*p++ = '\n';
|
*p = 0;
|
||||||
|
__printf("XMM%s\n", buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
relegated static void ShowMemoryMappings(int outfd) {
|
|
||||||
ssize_t rc;
|
|
||||||
int c, infd;
|
|
||||||
char buf[64];
|
|
||||||
if (!IsTiny()) {
|
|
||||||
PrintMemoryIntervals(outfd, &_mmi);
|
|
||||||
if ((infd = open("/proc/self/maps", O_RDONLY)) != -1) {
|
|
||||||
while ((rc = read(infd, buf, sizeof(buf))) > 0) {
|
|
||||||
__write(buf, rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(infd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowCrashReportHook(int, int, int, struct siginfo *, ucontext_t *);
|
void ShowCrashReportHook(int, int, int, struct siginfo *, ucontext_t *);
|
||||||
|
|
||||||
relegated void ShowCrashReport(int err, int fd, int sig, struct siginfo *si,
|
relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
||||||
ucontext_t *ctx) {
|
ucontext_t *ctx) {
|
||||||
int i;
|
int i;
|
||||||
char *p;
|
char *p;
|
||||||
bool colorful;
|
char host[64];
|
||||||
char hostname[64];
|
intptr_t stackaddr;
|
||||||
struct utsname names;
|
struct utsname names;
|
||||||
static char buf[4096];
|
static char buf[4096];
|
||||||
if (weaken(ShowCrashReportHook)) {
|
if (weaken(ShowCrashReportHook)) {
|
||||||
ShowCrashReportHook(err, fd, sig, si, ctx);
|
ShowCrashReportHook(2, err, sig, si, ctx);
|
||||||
}
|
}
|
||||||
colorful = cancolor();
|
__stpcpy(host, "unknown");
|
||||||
__stpcpy(hostname, "unknown");
|
gethostname(host, sizeof(host));
|
||||||
gethostname(hostname, sizeof(hostname));
|
|
||||||
p = buf;
|
p = buf;
|
||||||
p = __stpcpy(p, "\n");
|
__printf("\n%serror%s: Uncaught SIG%s",
|
||||||
if (colorful) p = __stpcpy(p, "\e[30;101m");
|
!g_isterminalinarticulate ? "\e[30;101m" : "",
|
||||||
p = __stpcpy(p, "error");
|
!g_isterminalinarticulate ? "\e[0m" : "", TinyStrSignal(sig));
|
||||||
if (colorful) p = __stpcpy(p, "\e[0m");
|
stackaddr = GetStackAddr(0);
|
||||||
p = __stpcpy(p, ": Uncaught SIG");
|
if (ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
||||||
p = __stpcpy(p, TinyStrSignal(sig));
|
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE)) {
|
||||||
if (si) {
|
__printf(" (Stack Overflow)");
|
||||||
p = __stpcpy(p, " (");
|
} else if (si) {
|
||||||
p = __stpcpy(p, GetSiCodeName(sig, si->si_code));
|
__printf(" (%s)", GetSiCodeName(sig, si->si_code));
|
||||||
p = __stpcpy(p, ")");
|
|
||||||
}
|
}
|
||||||
p = __stpcpy(p, " on ");
|
__printf(" on %s pid %d\n %s\n %s\n", host, __getpid(),
|
||||||
p = __stpcpy(p, hostname);
|
program_invocation_name, strerror(err));
|
||||||
p = __stpcpy(p, " pid ");
|
|
||||||
p = __intcpy(p, __getpid());
|
|
||||||
p = __stpcpy(p, "\n ");
|
|
||||||
p = __stpcpy(p, program_invocation_name);
|
|
||||||
p = __stpcpy(p, "\n ");
|
|
||||||
p = __stpcpy(p, strerror(err));
|
|
||||||
*p++ = '\n';
|
|
||||||
if (uname(&names) != -1) {
|
if (uname(&names) != -1) {
|
||||||
p = __stpcpy(p, " ");
|
__printf(" %s %s %s %s\n", names.sysname, names.nodename, names.release,
|
||||||
p = __stpcpy(p, names.sysname), *p++ = ' ';
|
names.version);
|
||||||
p = __stpcpy(p, names.nodename), *p++ = ' ';
|
|
||||||
p = __stpcpy(p, names.release), *p++ = ' ';
|
|
||||||
p = __stpcpy(p, names.version), *p++ = '\n';
|
|
||||||
}
|
}
|
||||||
__write(buf, p - buf);
|
|
||||||
ShowFunctionCalls(fd, ctx);
|
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
p = buf;
|
__printf("\n");
|
||||||
p = ShowGeneralRegisters(p, ctx);
|
ShowFunctionCalls(ctx);
|
||||||
p = ShowSseRegisters(p, ctx);
|
ShowGeneralRegisters(ctx);
|
||||||
*p++ = '\n';
|
ShowSseRegisters(ctx);
|
||||||
__write(buf, p - buf);
|
|
||||||
}
|
}
|
||||||
p = buf;
|
__printf("\n");
|
||||||
*p++ = '\n';
|
PrintMemoryIntervals(2, &_mmi);
|
||||||
ShowMemoryMappings(fd);
|
/* PrintSystemMappings(2); */
|
||||||
__write(buf, p - buf);
|
|
||||||
if (__argv) {
|
if (__argv) {
|
||||||
for (i = 0; i < __argc; ++i) {
|
for (i = 0; i < __argc; ++i) {
|
||||||
if (!__argv[i]) continue;
|
if (!__argv[i]) continue;
|
||||||
if (IsAsan() && !__asan_is_valid(__argv[i], 1)) continue;
|
if (IsAsan() && !__asan_is_valid(__argv[i], 1)) continue;
|
||||||
__write(__argv[i], strlen(__argv[i]));
|
__printf("%s ", __argv[i]);
|
||||||
__write(" ", 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__write("\n", 1);
|
__printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
relegated static void RestoreDefaultCrashSignalHandlers(void) {
|
relegated static void RestoreDefaultCrashSignalHandlers(void) {
|
||||||
|
@ -309,29 +289,48 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) {
|
||||||
*
|
*
|
||||||
* This function never returns, except for traps w/ human supervision.
|
* This function never returns, except for traps w/ human supervision.
|
||||||
*/
|
*/
|
||||||
relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
|
noasan relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
|
||||||
intptr_t rip;
|
intptr_t rip;
|
||||||
int gdbpid, err;
|
int gdbpid, err;
|
||||||
static bool once;
|
static bool noreentry, notpossible;
|
||||||
err = errno;
|
++g_ftrace;
|
||||||
if (once) _exit(119);
|
|
||||||
once = true;
|
|
||||||
rip = ctx ? ctx->uc_mcontext.rip : 0;
|
rip = ctx ? ctx->uc_mcontext.rip : 0;
|
||||||
if ((gdbpid = IsDebuggerPresent(true))) {
|
if (cmpxchg(&noreentry, false, true)) {
|
||||||
DebugBreak();
|
err = errno;
|
||||||
} else if (IsTerminalInarticulate() || IsRunningUnderMake()) {
|
if ((gdbpid = IsDebuggerPresent(true))) {
|
||||||
gdbpid = -1;
|
DebugBreak();
|
||||||
} else if (FindDebugBinary()) {
|
} else if (g_isterminalinarticulate || g_isrunningundermake) {
|
||||||
RestoreDefaultCrashSignalHandlers();
|
gdbpid = -1;
|
||||||
gdbpid =
|
} else if (FindDebugBinary()) {
|
||||||
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
|
RestoreDefaultCrashSignalHandlers();
|
||||||
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
|
gdbpid =
|
||||||
? rip
|
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
|
||||||
: 0);
|
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
|
||||||
|
? rip
|
||||||
|
: 0);
|
||||||
|
}
|
||||||
|
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
|
||||||
|
__restore_tty(1);
|
||||||
|
ShowCrashReport(err, sig, si, ctx);
|
||||||
|
_Exit(128 + sig);
|
||||||
|
}
|
||||||
|
} else if (cmpxchg(¬possible, false, true)) {
|
||||||
|
__printf("\n"
|
||||||
|
"\n"
|
||||||
|
"CRASHED WHILE CRASHING WITH SIG%s\n"
|
||||||
|
"%s\n"
|
||||||
|
"RIP %x\n"
|
||||||
|
"RSP %x\n"
|
||||||
|
"RBP %x\n"
|
||||||
|
"\n",
|
||||||
|
TinyStrSignal(sig), __argv[0], rip, ctx ? ctx->uc_mcontext.rsp : 0,
|
||||||
|
ctx ? ctx->uc_mcontext.rbp : 0);
|
||||||
|
_Exit(119);
|
||||||
|
} else {
|
||||||
|
for (;;) {
|
||||||
|
asm("ud2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT)) return;
|
noreentry = false;
|
||||||
__restore_tty(1);
|
--g_ftrace;
|
||||||
ShowCrashReport(err, STDERR_FILENO, sig, si, ctx);
|
|
||||||
exit(128 + sig);
|
|
||||||
unreachable;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/nexgen32e/gc.internal.h"
|
#include "libc/nexgen32e/gc.internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
@ -24,19 +26,31 @@
|
||||||
/**
|
/**
|
||||||
* Prints list of deferred operations on shadow stack.
|
* Prints list of deferred operations on shadow stack.
|
||||||
*/
|
*/
|
||||||
void PrintGarbage(FILE *f) {
|
void PrintGarbage(void) {
|
||||||
size_t i;
|
size_t i;
|
||||||
f = stderr;
|
char name[19];
|
||||||
fprintf(f, "\n");
|
const char *symbol;
|
||||||
fprintf(f, " SHADOW STACK @ 0x%016lx\n", __builtin_frame_address(0));
|
__printf("\n");
|
||||||
fprintf(f, " garbage entry parent frame original ret callback arg \n");
|
__printf(" SHADOW STACK @ 0x%p\n", __builtin_frame_address(0));
|
||||||
fprintf(f, "-------------- -------------- ------------------ ------------------ ------------------\n");
|
__printf("garbage entry parent frame original ret callback arg \n");
|
||||||
for (i = __garbage.i; i--;) {
|
__printf("-------------- -------------- ------------------ ------------------ ------------------\n");
|
||||||
fprintf(f, "0x%012lx 0x%012lx %-18s %-18s 0x%016lx\n",
|
if (__garbage.i) {
|
||||||
__garbage.p + i,
|
for (i = __garbage.i; i--;) {
|
||||||
__garbage.p[i].frame,
|
symbol = __get_symbol_by_addr(__garbage.p[i].ret);
|
||||||
GetSymbolByAddr(__garbage.p[i].ret-1),
|
if (symbol) {
|
||||||
GetSymbolByAddr(__garbage.p[i].fn),
|
snprintf(name, sizeof(name), "%s", symbol);
|
||||||
__garbage.p[i].arg);
|
} else {
|
||||||
|
snprintf(name, sizeof(name), "0x%012lx", __garbage.p[i].ret);
|
||||||
|
}
|
||||||
|
__printf("0x%p 0x%p %18s %18s 0x%016lx\n",
|
||||||
|
__garbage.p + i,
|
||||||
|
__garbage.p[i].frame,
|
||||||
|
name,
|
||||||
|
__get_symbol_by_addr(__garbage.p[i].fn),
|
||||||
|
__garbage.p[i].arg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
__printf("%14s %14s %18s %18s %18s\n","empty","-","-","-","-");
|
||||||
}
|
}
|
||||||
|
__printf("\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,22 +16,15 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/bits/bits.h"
|
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/termios.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/typedef/sigaction_f.h"
|
#include "libc/calls/struct/sigaltstack.h"
|
||||||
#include "libc/dce.h"
|
|
||||||
#include "libc/log/check.h"
|
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/nt/signals.h"
|
|
||||||
#include "libc/runtime/symbols.internal.h"
|
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
#include "libc/sysv/consts/ss.h"
|
||||||
|
|
||||||
STATIC_YOINK("__die");
|
STATIC_YOINK("__die");
|
||||||
|
|
||||||
|
@ -57,6 +50,7 @@ extern const unsigned char __oncrash_thunks[8][11];
|
||||||
void ShowCrashReports(void) {
|
void ShowCrashReports(void) {
|
||||||
size_t i;
|
size_t i;
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
struct sigaltstack ss;
|
||||||
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||||
kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */
|
kCrashSigs[0] = SIGQUIT; /* ctrl+\ aka ctrl+break */
|
||||||
kCrashSigs[1] = SIGFPE; /* 1 / 0 */
|
kCrashSigs[1] = SIGFPE; /* 1 / 0 */
|
||||||
|
@ -68,11 +62,16 @@ void ShowCrashReports(void) {
|
||||||
kCrashSigs[7] = SIGPIPE; /* write to closed thing */
|
kCrashSigs[7] = SIGPIPE; /* write to closed thing */
|
||||||
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||||
bzero(&sa, sizeof(sa));
|
bzero(&sa, sizeof(sa));
|
||||||
sa.sa_flags = SA_RESETHAND | SA_SIGINFO;
|
ss.ss_flags = 0;
|
||||||
|
ss.ss_size = SIGSTKSZ;
|
||||||
|
ss.ss_sp = malloc(SIGSTKSZ);
|
||||||
|
__cxa_atexit(free, ss.ss_sp, 0);
|
||||||
|
sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
|
||||||
sigfillset(&sa.sa_mask);
|
sigfillset(&sa.sa_mask);
|
||||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||||
sigdelset(&sa.sa_mask, kCrashSigs[i]);
|
sigdelset(&sa.sa_mask, kCrashSigs[i]);
|
||||||
}
|
}
|
||||||
|
sigaltstack(&ss, 0);
|
||||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||||
if (kCrashSigs[i]) {
|
if (kCrashSigs[i]) {
|
||||||
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];
|
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,18 +16,23 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
.source __FILE__
|
#include "libc/mem/mem.h"
|
||||||
|
|
||||||
.initbss 202,_init_posix_memalign
|
/**
|
||||||
hook_posix_memalign:
|
* Same as memalign(a, n) but requires IS2POW(a).
|
||||||
.quad 0
|
*
|
||||||
.endobj hook_posix_memalign,globl,hidden
|
* @param n number of bytes needed
|
||||||
.previous
|
* @return memory address, or NULL w/ errno
|
||||||
|
* @throw EINVAL if !IS2POW(a)
|
||||||
.init.start 202,_init_posix_memalign
|
* @see pvalloc()
|
||||||
.hidden dlposix_memalign
|
*/
|
||||||
ezlea dlposix_memalign,ax
|
void *aligned_alloc(size_t a, size_t n) {
|
||||||
stosq
|
if (IS2POW(a)) {
|
||||||
yoink free
|
return memalign(a, n);
|
||||||
.init.end 202,_init_posix_memalign
|
} else {
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
312
libc/mem/arena.c
312
libc/mem/arena.c
|
@ -22,37 +22,39 @@
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
#include "libc/log/libfatal.internal.h"
|
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/arena.h"
|
#include "libc/mem/arena.h"
|
||||||
#include "libc/mem/hook/hook.internal.h"
|
#include "libc/mem/hook/hook.internal.h"
|
||||||
|
#include "libc/nexgen32e/bsf.h"
|
||||||
|
#include "libc/nexgen32e/bsr.h"
|
||||||
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/sysv/consts/map.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
#define BASE ((char *)0x30000000)
|
#define BASE 0x50000000
|
||||||
#define LIMIT ((char *)0x50000000)
|
#define SIZE 0x2ffe0000
|
||||||
|
#define P(i) ((void *)(intptr_t)(i))
|
||||||
#define EXCHANGE(HOOK, SLOT) \
|
#define EXCHANGE(HOOK, SLOT) \
|
||||||
__arena_hook((intptr_t *)weaken(HOOK), (intptr_t *)(&(SLOT)))
|
__arena_hook((intptr_t *)weaken(HOOK), (intptr_t *)(&(SLOT)))
|
||||||
|
|
||||||
static struct Arena {
|
static struct Arena {
|
||||||
bool once;
|
bool once;
|
||||||
uint8_t depth;
|
size_t size;
|
||||||
unsigned size;
|
size_t depth;
|
||||||
unsigned offset[16];
|
size_t offset[16];
|
||||||
void (*free)(void *);
|
void (*free)(void *);
|
||||||
void *(*malloc)(size_t);
|
void *(*malloc)(size_t);
|
||||||
void *(*calloc)(size_t, size_t);
|
void *(*calloc)(size_t, size_t);
|
||||||
void *(*memalign)(size_t, size_t);
|
void *(*memalign)(size_t, size_t);
|
||||||
void *(*realloc)(void *, size_t);
|
void *(*realloc)(void *, size_t);
|
||||||
void *(*realloc_in_place)(void *, size_t);
|
void *(*realloc_in_place)(void *, size_t);
|
||||||
void *(*valloc)(size_t);
|
|
||||||
void *(*pvalloc)(size_t);
|
|
||||||
int (*malloc_trim)(size_t);
|
|
||||||
size_t (*malloc_usable_size)(const void *);
|
size_t (*malloc_usable_size)(const void *);
|
||||||
size_t (*bulk_free)(void *[], size_t);
|
size_t (*bulk_free)(void *[], size_t);
|
||||||
|
int (*malloc_trim)(size_t);
|
||||||
} __arena;
|
} __arena;
|
||||||
|
|
||||||
static wontreturn void __arena_die(void) {
|
static wontreturn void __arena_die(void) {
|
||||||
|
@ -61,103 +63,202 @@ static wontreturn void __arena_die(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static wontreturn void __arena_not_implemented(void) {
|
static wontreturn void __arena_not_implemented(void) {
|
||||||
__printf("not implemented");
|
assert(!"not implemented");
|
||||||
__arena_die();
|
__arena_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __arena_free(void *p) {
|
forceinline void __arena_check(void) {
|
||||||
if (!p) return;
|
|
||||||
assert(__arena.depth);
|
assert(__arena.depth);
|
||||||
assert((intptr_t)BASE + __arena.offset[__arena.depth - 1] <= (intptr_t)p &&
|
}
|
||||||
(intptr_t)p < (intptr_t)BASE + __arena.offset[__arena.depth]);
|
|
||||||
|
forceinline void __arena_check_pointer(void *p) {
|
||||||
|
assert(BASE + __arena.offset[__arena.depth - 1] <= (uintptr_t)p &&
|
||||||
|
(uintptr_t)p < BASE + __arena.offset[__arena.depth]);
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline bool __arena_is_arena_pointer(void *p) {
|
||||||
|
return BASE <= (uintptr_t)p && (uintptr_t)p < BASE + SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline size_t __arena_get_size(void *p) {
|
||||||
|
return *(const size_t *)((const char *)p - sizeof(size_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __arena_free(void *p) {
|
||||||
|
__arena_check();
|
||||||
|
if (p) {
|
||||||
|
__arena_check_pointer(p);
|
||||||
|
if (!(BASE <= (uintptr_t)p && (uintptr_t)p < BASE + SIZE)) {
|
||||||
|
__arena.free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t __arena_bulk_free(void *p[], size_t n) {
|
static size_t __arena_bulk_free(void *p[], size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
if (p[i]) __arena_free(p[i]);
|
__arena_free(p[i]);
|
||||||
|
p[i] = 0;
|
||||||
}
|
}
|
||||||
bzero(p, n * sizeof(void *));
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline bool __arena_grow(size_t offset, size_t request) {
|
||||||
|
size_t greed;
|
||||||
|
greed = __arena.size + 1;
|
||||||
|
do {
|
||||||
|
greed += greed >> 1;
|
||||||
|
greed = ROUNDUP(greed, FRAMESIZE);
|
||||||
|
} while (greed < offset + request);
|
||||||
|
if (greed <= SIZE) {
|
||||||
|
if (mmap(P(BASE + __arena.size), greed - __arena.size,
|
||||||
|
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
|
||||||
|
-1, 0) != MAP_FAILED) {
|
||||||
|
__arena.size = greed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enomem();
|
||||||
|
}
|
||||||
|
if (weaken(__oom_hook)) {
|
||||||
|
weaken(__oom_hook)(request);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *__arena_alloc(size_t a, size_t n) {
|
||||||
|
size_t o;
|
||||||
|
if (!n) n = 1;
|
||||||
|
o = ROUNDUP(__arena.offset[__arena.depth] + sizeof(size_t), a);
|
||||||
|
if (o + n >= n) {
|
||||||
|
if (n <= sizeof(size_t)) {
|
||||||
|
n = sizeof(size_t);
|
||||||
|
} else {
|
||||||
|
n = ROUNDUP(n, sizeof(size_t));
|
||||||
|
}
|
||||||
|
if (o + n <= SIZE) {
|
||||||
|
if (UNLIKELY(o + n > __arena.size)) {
|
||||||
|
if (!__arena_grow(o, n)) return 0;
|
||||||
|
}
|
||||||
|
__arena.offset[__arena.depth] = o + n;
|
||||||
|
*(size_t *)(BASE + o - sizeof(size_t)) = n;
|
||||||
|
return (void *)(BASE + o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enomem();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *__arena_malloc(size_t n) {
|
static void *__arena_malloc(size_t n) {
|
||||||
char *ptr;
|
__arena_check();
|
||||||
size_t need, greed;
|
return __arena_alloc(16, n);
|
||||||
assert(__arena.depth);
|
}
|
||||||
if (!n) n = 1;
|
|
||||||
if (n < LIMIT - BASE) {
|
static void *__arena_calloc(size_t n, size_t z) {
|
||||||
need = __arena.offset[__arena.depth] + n;
|
__arena_check();
|
||||||
need = ROUNDUP(need, __BIGGEST_ALIGNMENT__);
|
if (__builtin_mul_overflow(n, z, &n)) n = -1;
|
||||||
if (UNLIKELY(need > __arena.size)) {
|
return __arena_alloc(16, n);
|
||||||
greed = __arena.size + 1;
|
}
|
||||||
do {
|
|
||||||
greed += greed >> 1;
|
static void *__arena_memalign(size_t a, size_t n) {
|
||||||
greed = ROUNDUP(greed, FRAMESIZE);
|
__arena_check();
|
||||||
} while (need > greed);
|
if (a <= sizeof(size_t)) {
|
||||||
if (greed < LIMIT - BASE &&
|
return __arena_alloc(8, n);
|
||||||
mmap(BASE + __arena.size, greed - __arena.size,
|
} else {
|
||||||
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
|
return __arena_alloc(2ul << bsrl(a - 1), n);
|
||||||
-1, 0) != MAP_FAILED) {
|
}
|
||||||
__arena.size = greed;
|
}
|
||||||
|
|
||||||
|
static size_t __arena_malloc_usable_size(const void *p) {
|
||||||
|
__arena_check();
|
||||||
|
__arena_check_pointer(p);
|
||||||
|
if (__arena_is_arena_pointer(p)) {
|
||||||
|
return __arena_get_size(p);
|
||||||
|
} else {
|
||||||
|
return __arena.malloc_usable_size(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *__arena_realloc(void *p, size_t n) {
|
||||||
|
char *q;
|
||||||
|
size_t m, o, z;
|
||||||
|
__arena_check();
|
||||||
|
if (p) {
|
||||||
|
__arena_check_pointer(p);
|
||||||
|
if (__arena_is_arena_pointer(p)) {
|
||||||
|
if (n) {
|
||||||
|
if ((m = __arena_get_size(p)) >= n) {
|
||||||
|
return p;
|
||||||
|
} else if (n <= SIZE) {
|
||||||
|
z = 2ul << bsrl(n - 1);
|
||||||
|
if (__arena.offset[__arena.depth] - m == (o = (intptr_t)p - BASE)) {
|
||||||
|
if (UNLIKELY(o + z > __arena.size)) {
|
||||||
|
if (o + z <= SIZE) {
|
||||||
|
if (!__arena_grow(o, z)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enomem();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__arena.offset[__arena.depth] = o + z;
|
||||||
|
*(size_t *)((char *)p - sizeof(size_t)) = z;
|
||||||
|
return p;
|
||||||
|
} else if ((q = __arena_alloc(1ul << bsfl((intptr_t)p), z))) {
|
||||||
|
memmove(q, p, m);
|
||||||
|
return q;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enomem();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return __arena.realloc(p, n);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (n <= 16) {
|
||||||
|
n = 16;
|
||||||
|
} else {
|
||||||
|
n = 2ul << bsrl(n - 1);
|
||||||
|
}
|
||||||
|
return __arena_alloc(16, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *__arena_realloc_in_place(void *p, size_t n) {
|
||||||
|
char *q;
|
||||||
|
size_t m, z;
|
||||||
|
__arena_check();
|
||||||
|
if (p) {
|
||||||
|
__arena_check_pointer(p);
|
||||||
|
if (__arena_is_arena_pointer(p)) {
|
||||||
|
if (n) {
|
||||||
|
if ((m = __arena_get_size(p)) >= n) {
|
||||||
|
return p;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return __arena.realloc_in_place(p, n);
|
||||||
}
|
}
|
||||||
ptr = BASE + __arena.offset[__arena.depth];
|
|
||||||
__arena.offset[__arena.depth] = need;
|
|
||||||
return ptr;
|
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *__arena_calloc(size_t n, size_t z) {
|
|
||||||
if (__builtin_mul_overflow(n, z, &n)) n = -1;
|
|
||||||
return __arena_malloc(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *__arena_memalign(size_t a, size_t n) {
|
|
||||||
if (a <= __BIGGEST_ALIGNMENT__) {
|
|
||||||
return __arena_malloc(n);
|
|
||||||
} else {
|
|
||||||
__arena_not_implemented();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *__arena_realloc(void *p, size_t n) {
|
|
||||||
if (p) {
|
|
||||||
if (n) {
|
|
||||||
__arena_not_implemented();
|
|
||||||
} else {
|
|
||||||
__arena_free(p);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return __arena_malloc(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __arena_malloc_trim(size_t n) {
|
static int __arena_malloc_trim(size_t n) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *__arena_realloc_in_place(void *p, size_t n) {
|
|
||||||
__arena_not_implemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *__arena_valloc(size_t n) {
|
|
||||||
__arena_not_implemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *__arena_pvalloc(size_t n) {
|
|
||||||
__arena_not_implemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t __arena_malloc_usable_size(const void *p) {
|
|
||||||
__arena_not_implemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __arena_hook(intptr_t *h, intptr_t *f) {
|
static void __arena_hook(intptr_t *h, intptr_t *f) {
|
||||||
intptr_t t;
|
intptr_t t;
|
||||||
if (h) {
|
if (h) {
|
||||||
|
@ -169,42 +270,32 @@ static void __arena_hook(intptr_t *h, intptr_t *f) {
|
||||||
|
|
||||||
static void __arena_install(void) {
|
static void __arena_install(void) {
|
||||||
EXCHANGE(hook_free, __arena.free);
|
EXCHANGE(hook_free, __arena.free);
|
||||||
EXCHANGE(hook_realloc, __arena.realloc);
|
|
||||||
EXCHANGE(hook_realloc, __arena.realloc);
|
|
||||||
EXCHANGE(hook_malloc, __arena.malloc);
|
EXCHANGE(hook_malloc, __arena.malloc);
|
||||||
EXCHANGE(hook_calloc, __arena.calloc);
|
EXCHANGE(hook_calloc, __arena.calloc);
|
||||||
|
EXCHANGE(hook_realloc, __arena.realloc);
|
||||||
EXCHANGE(hook_memalign, __arena.memalign);
|
EXCHANGE(hook_memalign, __arena.memalign);
|
||||||
EXCHANGE(hook_realloc_in_place, __arena.realloc_in_place);
|
|
||||||
EXCHANGE(hook_valloc, __arena.valloc);
|
|
||||||
EXCHANGE(hook_pvalloc, __arena.pvalloc);
|
|
||||||
EXCHANGE(hook_malloc_trim, __arena.malloc_trim);
|
|
||||||
EXCHANGE(hook_malloc_usable_size, __arena.malloc_usable_size);
|
|
||||||
EXCHANGE(hook_bulk_free, __arena.bulk_free);
|
EXCHANGE(hook_bulk_free, __arena.bulk_free);
|
||||||
|
EXCHANGE(hook_malloc_trim, __arena.malloc_trim);
|
||||||
|
EXCHANGE(hook_realloc_in_place, __arena.realloc_in_place);
|
||||||
|
EXCHANGE(hook_malloc_usable_size, __arena.malloc_usable_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __arena_destroy(void) {
|
static void __arena_destroy(void) {
|
||||||
if (__arena.depth) {
|
if (__arena.depth) __arena_install();
|
||||||
__arena_install();
|
if (__arena.size) munmap(P(BASE), __arena.size);
|
||||||
}
|
|
||||||
if (__arena.size) {
|
|
||||||
munmap(BASE, __arena.size);
|
|
||||||
}
|
|
||||||
bzero(&__arena, sizeof(__arena));
|
bzero(&__arena, sizeof(__arena));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __arena_init(void) {
|
static void __arena_init(void) {
|
||||||
__arena.free = __arena_free;
|
__arena.free = __arena_free;
|
||||||
__arena.realloc = __arena_realloc;
|
|
||||||
__arena.realloc = __arena_realloc;
|
|
||||||
__arena.malloc = __arena_malloc;
|
__arena.malloc = __arena_malloc;
|
||||||
__arena.calloc = __arena_calloc;
|
__arena.calloc = __arena_calloc;
|
||||||
|
__arena.realloc = __arena_realloc;
|
||||||
__arena.memalign = __arena_memalign;
|
__arena.memalign = __arena_memalign;
|
||||||
__arena.realloc_in_place = __arena_realloc_in_place;
|
|
||||||
__arena.valloc = __arena_valloc;
|
|
||||||
__arena.pvalloc = __arena_pvalloc;
|
|
||||||
__arena.malloc_trim = __arena_malloc_trim;
|
|
||||||
__arena.malloc_usable_size = __arena_malloc_usable_size;
|
|
||||||
__arena.bulk_free = __arena_bulk_free;
|
__arena.bulk_free = __arena_bulk_free;
|
||||||
|
__arena.malloc_trim = __arena_malloc_trim;
|
||||||
|
__arena.realloc_in_place = __arena_realloc_in_place;
|
||||||
|
__arena.malloc_usable_size = __arena_malloc_usable_size;
|
||||||
atexit(__arena_destroy);
|
atexit(__arena_destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,24 +306,27 @@ void __arena_push(void) {
|
||||||
}
|
}
|
||||||
if (!__arena.depth) {
|
if (!__arena.depth) {
|
||||||
__arena_install();
|
__arena_install();
|
||||||
} else if (__arena.depth == ARRAYLEN(__arena.offset) - 1) {
|
} else {
|
||||||
__printf("too many arenas");
|
assert(__arena.depth < ARRAYLEN(__arena.offset) - 1);
|
||||||
__arena_die();
|
|
||||||
}
|
}
|
||||||
__arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth];
|
__arena.offset[__arena.depth + 1] = __arena.offset[__arena.depth];
|
||||||
++__arena.depth;
|
++__arena.depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __arena_pop(void) {
|
void __arena_pop(void) {
|
||||||
unsigned greed;
|
size_t a, b, greed;
|
||||||
assert(__arena.depth);
|
__arena_check();
|
||||||
bzero(BASE + __arena.offset[__arena.depth - 1],
|
|
||||||
__arena.offset[__arena.depth] - __arena.offset[__arena.depth - 1]);
|
|
||||||
if (!--__arena.depth) __arena_install();
|
if (!--__arena.depth) __arena_install();
|
||||||
greed = __arena.offset[__arena.depth];
|
a = __arena.offset[__arena.depth];
|
||||||
|
b = __arena.offset[__arena.depth + 1];
|
||||||
|
greed = a;
|
||||||
greed += FRAMESIZE;
|
greed += FRAMESIZE;
|
||||||
greed <<= 1;
|
greed <<= 1;
|
||||||
if (__arena.size > greed) {
|
if (__arena.size > greed) {
|
||||||
munmap(BASE + greed, __arena.size - greed);
|
munmap(P(BASE + greed), __arena.size - greed);
|
||||||
|
__arena.size = greed;
|
||||||
|
b = MIN(b, greed);
|
||||||
|
a = MIN(b, a);
|
||||||
}
|
}
|
||||||
|
bzero(P(BASE + a), b - a);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/buffer.h"
|
#include "libc/runtime/buffer.h"
|
||||||
|
|
||||||
|
/* TODO(jart): delete */
|
||||||
|
|
||||||
#define kGuard PAGESIZE
|
#define kGuard PAGESIZE
|
||||||
#define kGrain FRAMESIZE
|
#define kGrain FRAMESIZE
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,13 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/bits/likely.h"
|
#include "libc/bits/likely.h"
|
||||||
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/nexgen32e/gc.internal.h"
|
#include "libc/nexgen32e/gc.internal.h"
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
|
forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
|
||||||
struct StackFrame *parent,
|
struct StackFrame *parent,
|
||||||
|
@ -31,14 +33,28 @@ forceinline bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
|
||||||
((intptr_t)ptr < (intptr_t)parent));
|
((intptr_t)ptr < (intptr_t)parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __garbage_destroy(void) {
|
||||||
|
if (weaken(free)) {
|
||||||
|
weaken(free)(__garbage.p);
|
||||||
|
}
|
||||||
|
bzero(&__garbage, sizeof(__garbage));
|
||||||
|
}
|
||||||
|
|
||||||
void __deferer(struct StackFrame *frame, void *fn, void *arg) {
|
void __deferer(struct StackFrame *frame, void *fn, void *arg) {
|
||||||
size_t n2;
|
size_t n2;
|
||||||
struct Garbage *p2;
|
struct Garbage *p2;
|
||||||
if (UNLIKELY(__garbage.i == __garbage.n)) {
|
if (UNLIKELY(__garbage.i == __garbage.n)) {
|
||||||
|
p2 = __garbage.p;
|
||||||
n2 = __garbage.n + (__garbage.n >> 1);
|
n2 = __garbage.n + (__garbage.n >> 1);
|
||||||
p2 = malloc(n2 * sizeof(*__garbage.p));
|
if (__garbage.p != __garbage.initmem) {
|
||||||
memcpy(p2, __garbage.p, __garbage.n * sizeof(*__garbage.p));
|
if (!weaken(realloc)) return;
|
||||||
if (__garbage.p != __garbage.initmem) free(__garbage.p);
|
if (!(p2 = weaken(realloc)(p2, n2 * sizeof(*p2)))) return;
|
||||||
|
} else {
|
||||||
|
if (!weaken(malloc)) return;
|
||||||
|
if (!(p2 = weaken(malloc)(n2 * sizeof(*p2)))) return;
|
||||||
|
memcpy(p2, __garbage.p, __garbage.n * sizeof(*p2));
|
||||||
|
atexit(__garbage_destroy);
|
||||||
|
}
|
||||||
__garbage.p = p2;
|
__garbage.p = p2;
|
||||||
__garbage.n = n2;
|
__garbage.n = n2;
|
||||||
}
|
}
|
||||||
|
@ -59,11 +75,11 @@ void __deferer(struct StackFrame *frame, void *fn, void *arg) {
|
||||||
* @return arg
|
* @return arg
|
||||||
*/
|
*/
|
||||||
void __defer(struct StackFrame *frame, void *fn, void *arg) {
|
void __defer(struct StackFrame *frame, void *fn, void *arg) {
|
||||||
struct StackFrame *f2;
|
struct StackFrame *f;
|
||||||
if (!arg) return;
|
if (!arg) return;
|
||||||
f2 = __builtin_frame_address(0);
|
f = __builtin_frame_address(0);
|
||||||
assert(__garbage.n);
|
assert(__garbage.n);
|
||||||
assert(f2->next == frame);
|
assert(f->next == frame);
|
||||||
assert(PointerNotOwnedByParentStackFrame(f2, frame, arg));
|
assert(PointerNotOwnedByParentStackFrame(f, frame, arg));
|
||||||
__deferer(frame, fn, arg);
|
__deferer(frame, fn, arg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@ extern void *(*hook_calloc)(size_t, size_t);
|
||||||
extern void *(*hook_memalign)(size_t, size_t);
|
extern void *(*hook_memalign)(size_t, size_t);
|
||||||
extern void *(*hook_realloc)(void *, size_t);
|
extern void *(*hook_realloc)(void *, size_t);
|
||||||
extern void *(*hook_realloc_in_place)(void *, size_t);
|
extern void *(*hook_realloc_in_place)(void *, size_t);
|
||||||
extern void *(*hook_valloc)(size_t);
|
|
||||||
extern void *(*hook_pvalloc)(size_t);
|
|
||||||
extern int (*hook_malloc_trim)(size_t);
|
extern int (*hook_malloc_trim)(size_t);
|
||||||
extern size_t (*hook_malloc_usable_size)(const void *);
|
extern size_t (*hook_malloc_usable_size)(const void *);
|
||||||
extern size_t (*hook_bulk_free)(void *[], size_t);
|
extern size_t (*hook_bulk_free)(void *[], size_t);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
int PutEnvImpl(char *, bool) hidden;
|
int PutEnvImpl(char *, bool) hidden;
|
||||||
|
void __freeenv(void *) hidden;
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
.source __FILE__
|
|
||||||
|
|
||||||
// Allocates uninitialized memory.
|
// Allocates uninitialized memory.
|
||||||
//
|
//
|
||||||
|
@ -32,9 +31,7 @@
|
||||||
// fail. The maximum supported value of n differs across systems, but is
|
// fail. The maximum supported value of n differs across systems, but is
|
||||||
// in all cases less than the maximum representable value of a size_t.
|
// in all cases less than the maximum representable value of a size_t.
|
||||||
//
|
//
|
||||||
// @param rdi is number of bytes needed
|
// @param rdi is number of bytes needed, coerced to 1+
|
||||||
// @return new memory, or NULL w/ errno
|
// @return new memory, or NULL w/ errno
|
||||||
// @note malloc(0) → malloc(32)
|
|
||||||
// @see dlmalloc()
|
|
||||||
malloc: jmp *hook_malloc(%rip)
|
malloc: jmp *hook_malloc(%rip)
|
||||||
.endfn malloc,globl
|
.endfn malloc,globl
|
||||||
|
|
|
@ -15,15 +15,17 @@ void free(void *) libcesque;
|
||||||
void *malloc(size_t) attributeallocsize((1)) mallocesque;
|
void *malloc(size_t) attributeallocsize((1)) mallocesque;
|
||||||
void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque;
|
void *calloc(size_t, size_t) attributeallocsize((1, 2)) mallocesque;
|
||||||
void *memalign(size_t, size_t) attributeallocalign((1))
|
void *memalign(size_t, size_t) attributeallocalign((1))
|
||||||
attributeallocsize((2)) mallocesque;
|
attributeallocsize((2)) returnspointerwithnoaliases libcesque nodiscard;
|
||||||
void *realloc(void *, size_t) reallocesque;
|
void *realloc(void *, size_t) reallocesque;
|
||||||
void *realloc_in_place(void *, size_t);
|
void *realloc_in_place(void *, size_t) reallocesque;
|
||||||
void *reallocarray(void *, size_t, size_t) nodiscard;
|
void *reallocarray(void *, size_t, size_t) nodiscard;
|
||||||
void *valloc(size_t) attributeallocsize((1)) vallocesque;
|
void *valloc(size_t) attributeallocsize((1)) vallocesque;
|
||||||
void *pvalloc(size_t) attributeallocsize((1)) mallocesque;
|
void *pvalloc(size_t) vallocesque;
|
||||||
char *strdup(const char *) paramsnonnull() mallocesque;
|
char *strdup(const char *) paramsnonnull() mallocesque;
|
||||||
char *strndup(const char *, size_t) paramsnonnull() mallocesque;
|
char *strndup(const char *, size_t) paramsnonnull() mallocesque;
|
||||||
int posix_memalign(void **, size_t, size_t); /* wut */
|
void *aligned_alloc(size_t, size_t) attributeallocsize((1))
|
||||||
|
attributeallocsize((2)) returnspointerwithnoaliases libcesque nodiscard;
|
||||||
|
int posix_memalign(void **, size_t, size_t);
|
||||||
bool __grow(void *, size_t *, size_t, size_t) paramsnonnull((1, 2)) libcesque;
|
bool __grow(void *, size_t *, size_t, size_t) paramsnonnull((1, 2)) libcesque;
|
||||||
|
|
||||||
int malloc_trim(size_t);
|
int malloc_trim(size_t);
|
||||||
|
|
|
@ -18,22 +18,18 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/notice.inc"
|
#include "libc/notice.inc"
|
||||||
.source __FILE__
|
|
||||||
|
|
||||||
// Allocates aligned memory.
|
// Allocates aligned memory.
|
||||||
//
|
//
|
||||||
// Returns a pointer to a newly allocated chunk of n bytes, aligned in
|
// Returns a pointer to a newly allocated chunk of n bytes, aligned in
|
||||||
// accord with the alignment argument. The alignment argument should be
|
// accord with the alignment argument. The alignment argument shall be
|
||||||
// a power of two. If the argument is not a power of two, the nearest
|
// rounded up to the nearest two power and higher 2 powers may be used
|
||||||
// greater power is used. 8-byte alignment is guaranteed by normal
|
// if the allocator imposes a minimum alignment requirement.
|
||||||
// malloc calls, so don't bother calling memalign with an argument of 8
|
|
||||||
// or less.
|
|
||||||
//
|
//
|
||||||
// @param rdi is alignment in bytes
|
// @param rdi is alignment in bytes, coerced to 1+ w/ 2-power roundup
|
||||||
// @param rsi (newsize) is number of bytes needed
|
// @param rsi is number of bytes needed, coerced to 1+
|
||||||
// @return rax is memory address, or NULL w/ errno
|
// @return rax is memory address, or NULL w/ errno
|
||||||
// @note overreliance on memalign is a sure way to fragment space
|
// @see valloc(), pvalloc()
|
||||||
// @see dlmemalign()
|
|
||||||
memalign:
|
memalign:
|
||||||
jmp *hook_memalign(%rip)
|
jmp *hook_memalign(%rip)
|
||||||
.endfn memalign,globl
|
.endfn memalign,globl
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 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/macros.internal.h"
|
|
||||||
.source __FILE__
|
|
||||||
|
|
||||||
// Allocates aligned memory the POSIX way.
|
|
||||||
//
|
|
||||||
// Allocates a chunk of n bytes, aligned in accord with the alignment
|
|
||||||
// argument. Differs from memalign only in that it (1) assigns the
|
|
||||||
// allocated memory to *pp rather than returning it, (2) fails and
|
|
||||||
// returns EINVAL if the alignment is not a power of two (3) fails and
|
|
||||||
// returns ENOMEM if memory cannot be allocated.
|
|
||||||
//
|
|
||||||
// @param rdi is void **pp
|
|
||||||
// @param rsi is size_t align
|
|
||||||
// @param rdx is size_t size
|
|
||||||
// @return eax
|
|
||||||
posix_memalign:
|
|
||||||
jmp *hook_posix_memalign(%rip)
|
|
||||||
.endfn posix_memalign,globl
|
|
58
libc/mem/posix_memalign.c
Normal file
58
libc/mem/posix_memalign.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates aligned memory, the POSIX way.
|
||||||
|
*
|
||||||
|
* Allocates a chunk of n bytes, aligned in accord with the alignment
|
||||||
|
* argument. Differs from memalign() only in that it:
|
||||||
|
*
|
||||||
|
* 1. Assigns the allocated memory to *pp rather than returning it
|
||||||
|
* 2. Fails and returns EINVAL if the alignment is not a power of two
|
||||||
|
* 3. Fails and returns ENOMEM if memory cannot be allocated
|
||||||
|
*
|
||||||
|
* @param pp receives pointer, only on success
|
||||||
|
* @param alignment must be 2-power multiple of sizeof(void *)
|
||||||
|
* @param bytes is number of bytes to allocate
|
||||||
|
* @return return 0 or EINVAL or ENOMEM w/o setting errno
|
||||||
|
* @see memalign()
|
||||||
|
*/
|
||||||
|
int posix_memalign(void **pp, size_t alignment, size_t bytes) {
|
||||||
|
int e;
|
||||||
|
void *m;
|
||||||
|
size_t q, r;
|
||||||
|
q = alignment / sizeof(void *);
|
||||||
|
r = alignment % sizeof(void *);
|
||||||
|
if (!r && q && IS2POW(q)) {
|
||||||
|
e = errno;
|
||||||
|
m = memalign(alignment, bytes);
|
||||||
|
errno = e;
|
||||||
|
if (m) {
|
||||||
|
*pp = m;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,12 @@ static void PutEnvInit(void) {
|
||||||
atexit(PutEnvDestroy);
|
atexit(PutEnvDestroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __freeenv(void *p) {
|
||||||
|
if (once) {
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int PutEnvImpl(char *s, bool overwrite) {
|
int PutEnvImpl(char *s, bool overwrite) {
|
||||||
char *p;
|
char *p;
|
||||||
unsigned i, namelen;
|
unsigned i, namelen;
|
||||||
|
@ -62,7 +68,10 @@ int PutEnvImpl(char *s, bool overwrite) {
|
||||||
goto replace;
|
goto replace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i + 1 >= MAX_VARS) goto fail;
|
if (i + 1 >= MAX_VARS) {
|
||||||
|
free(s);
|
||||||
|
return enomem();
|
||||||
|
}
|
||||||
environ[i + 1] = NULL;
|
environ[i + 1] = NULL;
|
||||||
replace:
|
replace:
|
||||||
free(environ[i]);
|
free(environ[i]);
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 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/macros.internal.h"
|
|
||||||
#include "libc/notice.inc"
|
|
||||||
.source __FILE__
|
|
||||||
|
|
||||||
// Equivalent to valloc(minimum-page-that-holds(n)), that is,
|
|
||||||
// round up n to nearest pagesize.
|
|
||||||
//
|
|
||||||
// @param rdi is number of bytes needed
|
|
||||||
// @return rax is memory address, or NULL w/ errno
|
|
||||||
// @see dlpvalloc()
|
|
||||||
pvalloc:jmp *hook_pvalloc(%rip)
|
|
||||||
.endfn pvalloc,globl
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -17,13 +17,15 @@
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/notice.inc"
|
#include "libc/mem/mem.h"
|
||||||
.source __FILE__
|
|
||||||
|
|
||||||
// Equivalent to memalign(4096, n).
|
/**
|
||||||
//
|
* Equivalent to memalign(PAGESIZE, ROUNDUP(n, PAGESIZE)).
|
||||||
// @param rdi is number of bytes needed
|
*
|
||||||
// @return rax is memory address, or NULL w/ errno
|
* @param n number of bytes needed
|
||||||
// @see dlvalloc()
|
* @return memory address, or NULL w/ errno
|
||||||
valloc: jmp *hook_valloc(%rip)
|
* @see valloc()
|
||||||
.endfn valloc,globl
|
*/
|
||||||
|
void *pvalloc(size_t n) {
|
||||||
|
return memalign(PAGESIZE, ROUNDUP(n, PAGESIZE));
|
||||||
|
}
|
|
@ -23,6 +23,5 @@
|
||||||
|
|
||||||
nodiscard void *unhexstr(const char *hexdigs) {
|
nodiscard void *unhexstr(const char *hexdigs) {
|
||||||
assert(strlen(hexdigs) % 2 == 0);
|
assert(strlen(hexdigs) % 2 == 0);
|
||||||
return unhexbuf(memalign(__BIGGEST_ALIGNMENT__, strlen(hexdigs) / 2),
|
return unhexbuf(malloc(strlen(hexdigs) / 2), strlen(hexdigs) / 2, hexdigs);
|
||||||
strlen(hexdigs) / 2, hexdigs);
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue