mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make some systemic improvements
- add vdso dump utility - tests now log stack usage - rename g_ftrace to __ftrace - make internal spinlocks go faster - add conformant c11 atomics library - function tracing now logs stack usage - make function call tracing thread safe - add -X unsecure (no ssl) mode to redbean - munmap() has more consistent behavior now - pacify fsync() calls on python unit tests - make --strace flag work better in redbean - start minimizing and documenting compiler flags
This commit is contained in:
parent
c6bbca55e9
commit
9208c83f7a
141 changed files with 1948 additions and 1411 deletions
|
@ -43,6 +43,10 @@
|
|||
# '(progn
|
||||
# (add-hook 'c-mode-common-hook 'jart-c-mode-common-hook)))
|
||||
|
||||
# ctags doesn't understand atomics, e.g.
|
||||
# extern char **environ;
|
||||
set -- --regex-c='/_Atomic(\([^)]*\))/\1/b' "$@"
|
||||
|
||||
# ctags doesn't understand variable prototypes, e.g.
|
||||
# extern char **environ;
|
||||
set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@"
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/sysconf.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -268,9 +269,9 @@ int main(int argc, char *argv[]) {
|
|||
workers = threads;
|
||||
for (i = 0; i < threads; ++i) {
|
||||
char *tls = __initialize_tls(malloc(64));
|
||||
void *stack = mmap(0, 65536, PROT_READ | PROT_WRITE,
|
||||
void *stack = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
|
||||
MAP_STACK | MAP_ANONYMOUS, -1, 0);
|
||||
CHECK_NE(-1, clone(Worker, stack, 65536,
|
||||
CHECK_NE(-1, clone(Worker, stack, GetStackSize(),
|
||||
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||
CLONE_SIGHAND | CLONE_SETTLS,
|
||||
(void *)(intptr_t)i, 0, tls, 64, 0));
|
||||
|
|
80
libc/atomic.h
Normal file
80
libc/atomic.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ATOMIC_H_
|
||||
#define COSMOPOLITAN_LIBC_ATOMIC_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview C11 Atomic Types
|
||||
*
|
||||
* We supoprt C++ and old C compilers. It's recommended you use macros
|
||||
* like `_Atomic(int)` rather than `_Atomic int` or `atomic_int` since
|
||||
* we only define a portability macro for the syntax `_Atomic(T)`.
|
||||
*
|
||||
* @see libc/integral/c.inc
|
||||
* @see libc/bits/atomic.h
|
||||
*/
|
||||
|
||||
#define atomic_bool _Atomic(_Bool)
|
||||
#define atomic_bool32 atomic_int32
|
||||
#define atomic_char _Atomic(char)
|
||||
#define atomic_schar _Atomic(signed char)
|
||||
#define atomic_uchar _Atomic(unsigned char)
|
||||
#define atomic_short _Atomic(short)
|
||||
#define atomic_ushort _Atomic(unsigned short)
|
||||
#define atomic_int _Atomic(int)
|
||||
#define atomic_uint _Atomic(unsigned int)
|
||||
#define atomic_long _Atomic(long)
|
||||
#define atomic_ulong _Atomic(unsigned long)
|
||||
#define atomic_llong _Atomic(long long)
|
||||
#define atomic_ullong _Atomic(unsigned long long)
|
||||
#define atomic_char16_t _Atomic(char16_t)
|
||||
#define atomic_char32_t _Atomic(char32_t)
|
||||
#define atomic_wchar_t _Atomic(wchar_t)
|
||||
#define atomic_intptr_t _Atomic(intptr_t)
|
||||
#define atomic_uintptr_t _Atomic(uintptr_t)
|
||||
#define atomic_size_t _Atomic(size_t)
|
||||
#define atomic_ptrdiff_t _Atomic(ptrdiff_t)
|
||||
#define atomic_int_fast8_t _Atomic(int_fast8_t)
|
||||
#define atomic_uint_fast8_t _Atomic(uint_fast8_t)
|
||||
#define atomic_int_fast16_t _Atomic(int_fast16_t)
|
||||
#define atomic_uint_fast16_t _Atomic(uint_fast16_t)
|
||||
#define atomic_int_fast32_t _Atomic(int_fast32_t)
|
||||
#define atomic_uint_fast32_t _Atomic(uint_fast32_t)
|
||||
#define atomic_int_fast64_t _Atomic(int_fast64_t)
|
||||
#define atomic_uint_fast64_t _Atomic(uint_fast64_t)
|
||||
#define atomic_int_least8_t _Atomic(int_least8_t)
|
||||
#define atomic_uint_least8_t _Atomic(uint_least8_t)
|
||||
#define atomic_int_least16_t _Atomic(int_least16_t)
|
||||
#define atomic_uint_least16_t _Atomic(uint_least16_t)
|
||||
#define atomic_int_least32_t _Atomic(int_least32_t)
|
||||
#define atomic_uint_least32_t _Atomic(uint_least32_t)
|
||||
#define atomic_int_least64_t _Atomic(int_least64_t)
|
||||
#define atomic_uint_least64_t _Atomic(uint_least64_t)
|
||||
|
||||
#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
|
||||
#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE
|
||||
#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE
|
||||
#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
|
||||
#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
|
||||
#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
|
||||
#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
|
||||
#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
|
||||
#else
|
||||
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
|
||||
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
|
||||
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
|
||||
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
|
||||
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
|
||||
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
|
||||
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
|
||||
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ATOMIC_H_ */
|
36
libc/bits/atomic-clang.h
Normal file
36
libc/bits/atomic-clang.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_CLANG_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_CLANG_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § atomics » clang ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define atomic_init(obj, value) __c11_atomic_init(obj, value)
|
||||
#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)
|
||||
#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)
|
||||
#define atomic_compare_exchange_strong_explicit(object, expected, desired, \
|
||||
success, failure) \
|
||||
__c11_atomic_compare_exchange_strong(object, expected, desired, success, \
|
||||
failure)
|
||||
#define atomic_compare_exchange_weak_explicit(object, expected, desired, \
|
||||
success, failure) \
|
||||
__c11_atomic_compare_exchange_weak(object, expected, desired, success, \
|
||||
failure)
|
||||
#define atomic_exchange_explicit(object, desired, order) \
|
||||
__c11_atomic_exchange(object, desired, order)
|
||||
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_add(object, operand, order)
|
||||
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_and(object, operand, order)
|
||||
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_or(object, operand, order)
|
||||
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_sub(object, operand, order)
|
||||
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||
__c11_atomic_fetch_xor(object, operand, order)
|
||||
#define atomic_load_explicit(object, order) __c11_atomic_load(object, order)
|
||||
#define atomic_store_explicit(object, desired, order) \
|
||||
__c11_atomic_store(object, desired, order)
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_CLANG_H_ */
|
58
libc/bits/atomic-gcc.h
Normal file
58
libc/bits/atomic-gcc.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § atomics » old gnu ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define atomic_init(obj, value) ((void)(*(obj) = (value)))
|
||||
#define atomic_thread_fence(order) __sync_synchronize()
|
||||
#define atomic_signal_fence(order) __asm__ volatile("" ::: "memory")
|
||||
#define __atomic_apply_stride(object, operand) \
|
||||
(((__typeof__(__atomic_val(object)))0) + (operand))
|
||||
#define atomic_compare_exchange_strong_explicit(object, expected, desired, \
|
||||
success, failure) \
|
||||
__extension__({ \
|
||||
__typeof__(expected) __ep = (expected); \
|
||||
__typeof__(*__ep) __e = *__ep; \
|
||||
(void)(success); \
|
||||
(void)(failure); \
|
||||
(_Bool)((*__ep = __sync_val_compare_and_swap(object, __e, desired)) == \
|
||||
__e); \
|
||||
})
|
||||
#define atomic_compare_exchange_weak_explicit(object, expected, desired, \
|
||||
success, failure) \
|
||||
atomic_compare_exchange_strong_explicit(object, expected, desired, success, \
|
||||
failure)
|
||||
#if __has_builtin(__sync_swap)
|
||||
#define atomic_exchange_explicit(object, desired, order) \
|
||||
((void)(order), __sync_swap(object, desired))
|
||||
#else
|
||||
#define atomic_exchange_explicit(object, desired, order) \
|
||||
__extension__({ \
|
||||
__typeof__(object) __o = (object); \
|
||||
__typeof__(desired) __d = (desired); \
|
||||
(void)(order); \
|
||||
__sync_synchronize(); \
|
||||
__sync_lock_test_and_set(&__atomic_val(__o), __d); \
|
||||
})
|
||||
#endif
|
||||
#define atomic_fetch_add_explicit(object, operand, order) \
|
||||
((void)(order), \
|
||||
__sync_fetch_and_add(object, __atomic_apply_stride(object, operand)))
|
||||
#define atomic_fetch_and_explicit(object, operand, order) \
|
||||
((void)(order), __sync_fetch_and_and(object, operand))
|
||||
#define atomic_fetch_or_explicit(object, operand, order) \
|
||||
((void)(order), __sync_fetch_and_or(object, operand))
|
||||
#define atomic_fetch_sub_explicit(object, operand, order) \
|
||||
((void)(order), \
|
||||
__sync_fetch_and_sub(object, __atomic_apply_stride(object, operand)))
|
||||
#define atomic_fetch_xor_explicit(object, operand, order) \
|
||||
((void)(order), __sync_fetch_and_xor(object, operand))
|
||||
#define atomic_load_explicit(object, order) \
|
||||
((void)(order), __sync_fetch_and_add(object, 0))
|
||||
#define atomic_store_explicit(object, desired, order) \
|
||||
((void)atomic_exchange_explicit(object, desired, order))
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC_H_ */
|
34
libc/bits/atomic-gcc47.h
Normal file
34
libc/bits/atomic-gcc47.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC47_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC47_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § atomics » gcc 4.7+ ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define atomic_init(obj, value) ((void)(*(obj) = (value)))
|
||||
#define atomic_thread_fence(order) __atomic_thread_fence(order)
|
||||
#define atomic_signal_fence(order) __atomic_signal_fence(order)
|
||||
#define atomic_compare_exchange_strong_explicit(pObject, pExpected, desired, \
|
||||
success, failure) \
|
||||
__atomic_compare_exchange_n(pObject, pExpected, desired, 0, success, failure)
|
||||
#define atomic_compare_exchange_weak_explicit(pObject, pExpected, desired, \
|
||||
success, failure) \
|
||||
__atomic_compare_exchange_n(pObject, pExpected, desired, 1, success, failure)
|
||||
#define atomic_exchange_explicit(pObject, desired, order) \
|
||||
__atomic_exchange_n(pObject, desired, order)
|
||||
#define atomic_fetch_add_explicit(pObject, operand, order) \
|
||||
__atomic_fetch_add(pObject, operand, order)
|
||||
#define atomic_fetch_and_explicit(pObject, operand, order) \
|
||||
__atomic_fetch_and(pObject, operand, order)
|
||||
#define atomic_fetch_or_explicit(pObject, operand, order) \
|
||||
__atomic_fetch_or(pObject, operand, order)
|
||||
#define atomic_fetch_sub_explicit(pObject, operand, order) \
|
||||
__atomic_fetch_sub(pObject, operand, order)
|
||||
#define atomic_fetch_xor_explicit(pObject, operand, order) \
|
||||
__atomic_fetch_xor(pObject, operand, order)
|
||||
#define atomic_load_explicit(pObject, order) __atomic_load_n(pObject, order)
|
||||
#define atomic_store_explicit(pObject, desired, order) \
|
||||
__atomic_store_n(pObject, desired, order)
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_GCC47_H_ */
|
|
@ -1,18 +1,18 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_ATOMIC_H_
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/atomic.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview C11 version of The Cosmopolitan Atomics Library.
|
||||
* @fileoverview Cosmopolitan C11 Atomics Library
|
||||
*
|
||||
* - Forty-two different ways to say MOV.
|
||||
* - Fourteen different ways to say XCHG.
|
||||
* - Twenty different ways to say LOCK CMPXCHG.
|
||||
*
|
||||
* Living proof high-level languages can be lower-level than assembly.
|
||||
* It's a lower level programming language than assembly!
|
||||
*
|
||||
* @see libc/atomic.h
|
||||
*/
|
||||
|
||||
#define memory_order int
|
||||
|
@ -23,31 +23,47 @@ COSMOPOLITAN_C_START_
|
|||
#define memory_order_acq_rel 4
|
||||
#define memory_order_seq_cst 5
|
||||
|
||||
#define atomic_flag struct AtomicFlag
|
||||
#define atomic_flag_clear(PTR) atomic_store((PTR)->__cacheline, 0)
|
||||
#define atomic_flag_test_and_set(PTR) \
|
||||
({ \
|
||||
uint32_t ax = 0; \
|
||||
lockcmpxchg((PTR)->__cacheline, &ax, 1); \
|
||||
})
|
||||
#define atomic_init(PTR, VAL) atomic_store(PTR, VAL)
|
||||
#define atomic_exchange(PTR, VAL) lockxchg(PTR, &(VAL))
|
||||
#define atomic_compare_exchange_strong(X, Y, Z) _lockcmpxchg(X, Y, Z)
|
||||
#define atomic_compare_exchange_weak(X, Y, Z) _lockcmpxchg(X, Y, Z)
|
||||
#define atomic_load_explicit(PTR, ORDER) atomic_load(PTR)
|
||||
#define atomic_store_explicit(PTR, VAL, ORDER) atomic_store(PTR, VAL)
|
||||
#define atomic_flag_clear_explicit(PTR, ORDER) atomic_store(PTR, 0)
|
||||
#define atomic_exchange_explicit(PTR, VAL, ORDER) lockxchg(PTR, &(VAL))
|
||||
#define atomic_flag_test_and_set_explicit(PTR, ORDER) lockcmpxchg(PTR, 0, 1)
|
||||
#define atomic_compare_exchange_strong_explicit(X, Y, Z, S, F) \
|
||||
lockcmpxchg(X, Y, Z)
|
||||
#define atomic_compare_exchange_weak_explicit(X, Y, Z, S, F) \
|
||||
lockcmpxchg(X, Y, Z)
|
||||
#define ATOMIC_VAR_INIT(value) (value)
|
||||
#define atomic_is_lock_free(obj) ((void)(obj), sizeof(obj) <= sizeof(void *))
|
||||
|
||||
struct AtomicFlag {
|
||||
uint32_t __cacheline[16]; /* Intel V.O §9.4.6 */
|
||||
} forcealign(64);
|
||||
#define atomic_flag atomic_bool
|
||||
#define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0)
|
||||
#define atomic_flag_test_and_set_explicit(x, order) \
|
||||
atomic_exchange_explicit(x, 1, order)
|
||||
#define atomic_flag_clear_explicit(x, order) atomic_store_explicit(x, 0, order)
|
||||
|
||||
#define atomic_compare_exchange_strong(pObject, pExpected, desired) \
|
||||
atomic_compare_exchange_strong_explicit( \
|
||||
pObject, pExpected, desired, memory_order_seq_cst, memory_order_seq_cst)
|
||||
#define atomic_compare_exchange_weak(pObject, pExpected, desired) \
|
||||
atomic_compare_exchange_weak_explicit( \
|
||||
pObject, pExpected, desired, memory_order_seq_cst, memory_order_seq_cst)
|
||||
#define atomic_exchange(pObject, desired) \
|
||||
atomic_exchange_explicit(pObject, desired, memory_order_seq_cst)
|
||||
#define atomic_fetch_add(pObject, operand) \
|
||||
atomic_fetch_add_explicit(pObject, operand, memory_order_seq_cst)
|
||||
#define atomic_fetch_and(pObject, operand) \
|
||||
atomic_fetch_and_explicit(pObject, operand, memory_order_seq_cst)
|
||||
#define atomic_fetch_or(pObject, operand) \
|
||||
atomic_fetch_or_explicit(pObject, operand, memory_order_seq_cst)
|
||||
#define atomic_fetch_sub(pObject, operand) \
|
||||
atomic_fetch_sub_explicit(pObject, operand, memory_order_seq_cst)
|
||||
#define atomic_fetch_xor(pObject, operand) \
|
||||
atomic_fetch_xor_explicit(pObject, operand, memory_order_seq_cst)
|
||||
#define atomic_load(pObject) atomic_load_explicit(pObject, memory_order_seq_cst)
|
||||
#define atomic_store(pObject, desired) \
|
||||
atomic_store_explicit(pObject, desired, memory_order_seq_cst)
|
||||
#define atomic_flag_test_and_set(x) \
|
||||
atomic_flag_test_and_set_explicit(x, memory_order_seq_cst)
|
||||
#define atomic_flag_clear(x) atomic_flag_clear_explicit(x, memory_order_seq_cst)
|
||||
|
||||
#if defined(__CLANG_ATOMIC_BOOL_LOCK_FREE)
|
||||
#include "libc/bits/atomic-clang.h"
|
||||
#elif (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407
|
||||
#include "libc/bits/atomic-gcc47.h"
|
||||
#else
|
||||
#include "libc/bits/atomic-gcc.h"
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_ATOMIC_H_ */
|
||||
|
|
|
@ -65,31 +65,39 @@ $(LIBC_CALLS_A).pkg: \
|
|||
$(LIBC_CALLS_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/libc/calls/sigenter-freebsd.o \
|
||||
o/$(MODE)/libc/calls/sigenter-netbsd.o \
|
||||
o/$(MODE)/libc/calls/sigenter-openbsd.o \
|
||||
# we can't use asan because:
|
||||
# ucontext_t memory is owned by xnu kernel
|
||||
o/$(MODE)/libc/calls/sigenter-xnu.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-mno-fentry \
|
||||
-fno-stack-protector \
|
||||
-fno-sanitize=all
|
||||
-ffreestanding \
|
||||
-fno-sanitize=address
|
||||
|
||||
o/$(MODE)/libc/calls/sys_mprotect.greg.o \
|
||||
o/$(MODE)/libc/calls/vdsofunc.greg.o \
|
||||
o/$(MODE)/libc/calls/directmap.o \
|
||||
o/$(MODE)/libc/calls/directmap-nt.o \
|
||||
o/$(MODE)/libc/calls/mapstack.greg.o \
|
||||
o/$(MODE)/libc/calls/execve-nt.greg.o \
|
||||
o/$(MODE)/libc/calls/getcwd.greg.o \
|
||||
o/$(MODE)/libc/calls/getcwd-xnu.greg.o \
|
||||
o/$(MODE)/libc/calls/getprogramexecutablename.greg.o \
|
||||
o/$(MODE)/libc/calls/raise.o: \
|
||||
# we can't use asan because:
|
||||
# vdso memory is owned by linux kernel
|
||||
o/$(MODE)/libc/calls/vdsofunc.greg.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffreestanding \
|
||||
$(NO_MAGIC)
|
||||
-fno-sanitize=address
|
||||
|
||||
o/$(MODE)/libc/calls/termios2linux.o \
|
||||
o/$(MODE)/libc/calls/termios2host.o \
|
||||
# we can't use asan because:
|
||||
# asan guard pages haven't been allocated yet
|
||||
o/$(MODE)/libc/calls/directmap.o \
|
||||
o/$(MODE)/libc/calls/directmap-nt.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=address
|
||||
|
||||
# we can't use asan because:
|
||||
# ntspawn allocates 128kb of heap memory via win32
|
||||
o/$(MODE)/libc/calls/ntspawn.o \
|
||||
o/$(MODE)/libc/calls/mkntcmdline.o \
|
||||
o/$(MODE)/libc/calls/mkntenvblock.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=address
|
||||
|
||||
# we always want -O3 because:
|
||||
# it makes the code size smaller too
|
||||
o/$(MODE)/libc/calls/sigenter-freebsd.o \
|
||||
o/$(MODE)/libc/calls/sigenter-netbsd.o \
|
||||
o/$(MODE)/libc/calls/sigenter-openbsd.o \
|
||||
|
@ -98,7 +106,36 @@ o/$(MODE)/libc/calls/ntcontext2linux.o: \
|
|||
OVERRIDE_COPTS += \
|
||||
-O3
|
||||
|
||||
# TODO(jart): make va_arg optimize well in default mode
|
||||
# we must disable static stack safety because:
|
||||
# these functions use alloca(n)
|
||||
o/$(MODE)/libc/calls/execl.o \
|
||||
o/$(MODE)/libc/calls/execle.o \
|
||||
o/$(MODE)/libc/calls/execlp.o \
|
||||
o/$(MODE)/libc/calls/execve-sysv.o \
|
||||
o/$(MODE)/libc/calls/mkntenvblock.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
# we must disable static stack safety because:
|
||||
# PATH_MAX*sizeof(char16_t)*2 exceeds 4096 byte frame limit
|
||||
o/$(MODE)/libc/calls/copyfile.o \
|
||||
o/$(MODE)/libc/calls/symlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/readlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/linkat-nt.o \
|
||||
o/$(MODE)/libc/calls/renameat-nt.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
# we must segregate codegen because:
|
||||
# file contains multiple independently linkable apis
|
||||
o/$(MODE)/libc/calls/ioctl-siocgifconf.o \
|
||||
o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffunction-sections \
|
||||
-fdata-sections
|
||||
|
||||
# we always want -Os because:
|
||||
# va_arg codegen is very bloated in default mode
|
||||
o//libc/calls/open.o \
|
||||
o//libc/calls/openat.o \
|
||||
o//libc/calls/prctl.o \
|
||||
|
@ -120,27 +157,6 @@ o//libc/calls/fcntl.o: \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-Os
|
||||
|
||||
# must use alloca() or path_max*2*2
|
||||
o/$(MODE)/libc/calls/execl.o \
|
||||
o/$(MODE)/libc/calls/execle.o \
|
||||
o/$(MODE)/libc/calls/execlp.o \
|
||||
o/$(MODE)/libc/calls/copyfile.o \
|
||||
o/$(MODE)/libc/calls/execve-nt.greg.o \
|
||||
o/$(MODE)/libc/calls/linkat-nt.o \
|
||||
o/$(MODE)/libc/calls/renameat-nt.o \
|
||||
o/$(MODE)/libc/calls/execve-sysv.o \
|
||||
o/$(MODE)/libc/calls/symlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/readlinkat-nt.o \
|
||||
o/$(MODE)/libc/calls/mkntenvblock.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
o/$(MODE)/libc/calls/ioctl-siocgifconf.o \
|
||||
o/$(MODE)/libc/calls/ioctl-siocgifconf-nt.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-ffunction-sections \
|
||||
-fdata-sections
|
||||
|
||||
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
|
||||
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sock/ntstdin.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -42,12 +41,7 @@ textwindows int sys_close_nt(struct Fd *fd) {
|
|||
// if this file descriptor is wrapped in a named pipe worker thread
|
||||
// then we need to close our copy of the worker thread handle. it's
|
||||
// also required that whatever install a worker use malloc, so free
|
||||
if (fd->worker) {
|
||||
if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false;
|
||||
fd->worker = 0;
|
||||
} else {
|
||||
if (!CloseHandle(fd->handle)) ok = false;
|
||||
}
|
||||
if (!CloseHandle(fd->handle)) ok = false;
|
||||
if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
|
||||
if (!CloseHandle(fd->extra)) ok = false;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -16,29 +16,22 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/ntstdin.internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/calls/struct/sigaltstack.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
|
||||
/* STATIC_YOINK("StdinWorker"); */
|
||||
|
||||
static textexit void StdinWorkerFree(void) {
|
||||
int i;
|
||||
NTTRACE("StdinWorkerFree()");
|
||||
for (i = g_fds.n; i--;) {
|
||||
if (g_fds.p[i].kind && g_fds.p[i].worker) {
|
||||
close(i);
|
||||
}
|
||||
const char *DescribeSigaltstk(char *buf, size_t bufsize, int rc,
|
||||
const struct sigaltstack *ss) {
|
||||
if (rc == -1) return "n/a";
|
||||
if (!ss) return "NULL";
|
||||
if ((!IsAsan() && kisdangerous(ss)) ||
|
||||
(IsAsan() && !__asan_is_valid(ss, sizeof(*ss)))) {
|
||||
ksnprintf(buf, sizeof(buf), "%p", ss);
|
||||
} else {
|
||||
ksnprintf(buf, bufsize, "{.ss_sp=%p, .ss_flags=%#lx, .ss_size=%'zu}",
|
||||
ss->ss_sp, ss->ss_flags, ss->ss_size);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static textstartup void StdinWorkerInit(void) {
|
||||
g_fds.p[0].worker = NewNtStdinWorker(0);
|
||||
atexit(StdinWorkerFree);
|
||||
}
|
||||
|
||||
const void *const StdinWorker[] initarray = {
|
||||
StdinWorkerInit,
|
||||
};
|
|
@ -25,7 +25,6 @@
|
|||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/ntstdin.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -67,16 +66,7 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
|||
g_fds.p[newfd].kind = kFdReserved;
|
||||
}
|
||||
|
||||
// if this file descriptor is wrapped in a named pipe worker thread
|
||||
// then we should clone the original authentic handle rather than the
|
||||
// stdin worker's named pipe. we won't clone the worker, since that
|
||||
// can always be recreated again on demand.
|
||||
if (g_fds.p[oldfd].worker) {
|
||||
handle = g_fds.p[oldfd].worker->reader;
|
||||
} else {
|
||||
handle = g_fds.p[oldfd].handle;
|
||||
}
|
||||
|
||||
handle = g_fds.p[oldfd].handle;
|
||||
proc = GetCurrentProcess();
|
||||
if (DuplicateHandle(proc, handle, proc, &g_fds.p[newfd].handle, 0, true,
|
||||
kNtDuplicateSameAccess)) {
|
||||
|
@ -90,9 +80,6 @@ textwindows int sys_dup_nt(int oldfd, int newfd, int flags, int start) {
|
|||
} else {
|
||||
g_fds.p[newfd].extra = g_fds.p[oldfd].extra;
|
||||
}
|
||||
if (g_fds.p[oldfd].worker) {
|
||||
g_fds.p[newfd].worker = weaken(RefNtStdinWorker)(g_fds.p[oldfd].worker);
|
||||
}
|
||||
rc = newfd;
|
||||
} else {
|
||||
__releasefd(newfd);
|
||||
|
|
|
@ -20,21 +20,28 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Blocks until kernel flushes non-metadata buffers for fd to disk.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see fsync(), sync_file_range()
|
||||
* @see sync(), fsync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fdatasync(int fd) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fdatasync(fd);
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fdatasync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
}
|
||||
STRACE("fdatasync(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
rc = 0;
|
||||
STRACE("fdatasync(%d) → disabled% m", fd);
|
||||
}
|
||||
STRACE("%s(%d) → %d% m", "fdatasync", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -20,21 +20,28 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
/**
|
||||
* Blocks until kernel flushes buffers for fd to disk.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see fdatasync(), sync_file_range()
|
||||
* @see __nosync to secretly disable
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fsync(int fd) {
|
||||
int rc;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fsync(fd);
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
if (!IsWindows()) {
|
||||
rc = sys_fsync(fd);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
}
|
||||
STRACE("fysnc(%d) → %d% m", fd, rc);
|
||||
} else {
|
||||
rc = sys_fdatasync_nt(fd);
|
||||
rc = 0;
|
||||
STRACE("fsync(%d) → disabled% m", fd);
|
||||
}
|
||||
STRACE("%s(%d) → %d% m", "fsync", fd, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,6 @@ struct Fd {
|
|||
unsigned mode;
|
||||
int64_t handle;
|
||||
int64_t extra;
|
||||
struct NtStdinWorker *worker;
|
||||
bool zombie;
|
||||
};
|
||||
|
||||
|
@ -90,9 +89,12 @@ void __releasefd(int) hidden;
|
|||
void __releasefd_unlocked(int) hidden;
|
||||
int __ensurefds(int) hidden;
|
||||
int __ensurefds_unlocked(int) hidden;
|
||||
int64_t __getfdhandleactual(int) hidden;
|
||||
void __printfds(void) hidden;
|
||||
|
||||
forceinline int64_t __getfdhandleactual(int fd) {
|
||||
return g_fds.p[fd].handle;
|
||||
}
|
||||
|
||||
forceinline bool __isfdopen(int fd) {
|
||||
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static noasan bool NeedsQuotes(const char *s) {
|
||||
static bool NeedsQuotes(const char *s) {
|
||||
if (!*s) return true;
|
||||
do {
|
||||
if (*s == ' ' || *s == '\t') {
|
||||
|
@ -54,8 +54,8 @@ static noasan bool NeedsQuotes(const char *s) {
|
|||
* @return freshly allocated lpCommandLine or NULL w/ errno
|
||||
* @see libc/runtime/dosargv.c
|
||||
*/
|
||||
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX / 2],
|
||||
const char *prog, char *const argv[]) {
|
||||
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX / 2], const char *prog,
|
||||
char *const argv[]) {
|
||||
char *arg;
|
||||
uint64_t w;
|
||||
wint_t x, y;
|
||||
|
|
|
@ -31,14 +31,14 @@
|
|||
|
||||
#define ToUpper(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
|
||||
|
||||
static noasan int CompareStrings(const char *l, const char *r) {
|
||||
static int CompareStrings(const char *l, const char *r) {
|
||||
int a, b;
|
||||
size_t i = 0;
|
||||
while ((a = ToUpper(l[i] & 255)) == (b = ToUpper(r[i] & 255)) && r[i]) ++i;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static noasan void InsertString(char **a, size_t i, char *s) {
|
||||
static void InsertString(char **a, size_t i, char *s) {
|
||||
size_t j;
|
||||
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
|
||||
a[j] = a[j - 1];
|
||||
|
@ -57,8 +57,8 @@ static noasan void InsertString(char **a, size_t i, char *s) {
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @error E2BIG if total number of shorts exceeded ARG_MAX/2 (32767)
|
||||
*/
|
||||
textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX / 2],
|
||||
char *const envp[], const char *extravar) {
|
||||
textwindows int mkntenvblock(char16_t envvars[ARG_MAX / 2], char *const envp[],
|
||||
const char *extravar) {
|
||||
bool v;
|
||||
char *t;
|
||||
axdx_t rc;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=8 sts=2 sw=2 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 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -17,17 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
/**
|
||||
* Asks kernel to deschedule thread momentarily.
|
||||
* Tunes sync system call availability.
|
||||
*
|
||||
* If this value is set to 0x5453455454534146, then the system calls
|
||||
* sync(), fsync(), and fdatasync() system calls will do nothing and
|
||||
* return success. This is intended to be used for things like making
|
||||
* things like Python unit tests go faster because fsync is extremely
|
||||
* slow and using tmpfs requires root privileges.
|
||||
*/
|
||||
int sched_yield(void) {
|
||||
/* TODO(jart): Add get_sched_yield() so we can STRACE() */
|
||||
if (!IsWindows()) {
|
||||
return sys_sched_yield();
|
||||
} else {
|
||||
return sys_sched_yield_nt();
|
||||
}
|
||||
}
|
||||
uint64_t __nosync;
|
|
@ -38,7 +38,6 @@
|
|||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/ntstdin.internal.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
|
|
@ -54,7 +54,6 @@ void __printfds(void) {
|
|||
if (g_fds.p[i].mode) kprintf(" mode=%#o", g_fds.p[i].mode);
|
||||
if (g_fds.p[i].handle) kprintf(" handle=%ld", g_fds.p[i].handle);
|
||||
if (g_fds.p[i].extra) kprintf(" extra=%ld", g_fds.p[i].extra);
|
||||
if (g_fds.p[i].worker) kprintf(" worker=%p", g_fds.p[i].worker);
|
||||
kprintf("\n");
|
||||
}
|
||||
_spunlock(&__fds_lock);
|
||||
|
|
|
@ -16,12 +16,14 @@
|
|||
│ 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/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
|
@ -50,6 +52,7 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
|
|||
(bytes = __zipos_notat(dirfd, path)) == -1) {
|
||||
STRACE("TOOD: zipos support for readlinkat");
|
||||
} else if (!IsWindows()) {
|
||||
assert(bufsiz);
|
||||
bytes = sys_readlinkat(dirfd, path, buf, bufsiz);
|
||||
} else {
|
||||
bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
|
@ -81,7 +82,9 @@ char *realpath(const char *filename, char *resolved)
|
|||
ssize_t rc;
|
||||
int e, up, check_dir=0;
|
||||
size_t k, p, q, l, l0, cnt=0, nup=0;
|
||||
char output[PATH_MAX], stack[PATH_MAX], *z;
|
||||
char output[PATH_MAX], stack[PATH_MAX+1], *z;
|
||||
|
||||
/* STRACE("realpath(%#s, %#s)", filename, resolved); */
|
||||
|
||||
if (!filename) {
|
||||
einval();
|
||||
|
|
|
@ -22,10 +22,11 @@
|
|||
#include "libc/calls/struct/sigaltstack.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
|
||||
const struct sigaltstack *linux) {
|
||||
static void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
|
||||
const struct sigaltstack *linux) {
|
||||
void *sp;
|
||||
int flags;
|
||||
size_t size;
|
||||
|
@ -37,8 +38,8 @@ static noasan void sigaltstack2bsd(struct sigaltstack_bsd *bsd,
|
|||
bsd->ss_size = size;
|
||||
}
|
||||
|
||||
static noasan void sigaltstack2linux(struct sigaltstack *linux,
|
||||
const struct sigaltstack_bsd *bsd) {
|
||||
static void sigaltstack2linux(struct sigaltstack *linux,
|
||||
const struct sigaltstack_bsd *bsd) {
|
||||
void *sp;
|
||||
int flags;
|
||||
size_t size;
|
||||
|
@ -69,10 +70,11 @@ static noasan void sigaltstack2linux(struct sigaltstack *linux,
|
|||
* @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 sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
|
||||
int rc;
|
||||
void *b;
|
||||
const void *a;
|
||||
char buf[2][128];
|
||||
struct sigaltstack_bsd bsd;
|
||||
if (IsAsan() && ((old && __asan_check(old, sizeof(*old)).kind) ||
|
||||
(neu && (__asan_check(neu, sizeof(*neu)).kind ||
|
||||
|
@ -106,6 +108,8 @@ noasan int sigaltstack(const struct sigaltstack *neu, struct sigaltstack *old) {
|
|||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
STRACE("sigaltstack() → %d% m", rc);
|
||||
STRACE("sigaltstack(%s, [%s]) → %d% m",
|
||||
DescribeSigaltstk(buf[0], sizeof(buf[0]), 0, neu),
|
||||
DescribeSigaltstk(buf[0], sizeof(buf[0]), 0, old), rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
#define _KERNTRACE 0 /* not configurable w/ flag yet */
|
||||
#define _POLLTRACE 0 /* not configurable w/ flag yet */
|
||||
|
@ -50,8 +51,6 @@ COSMOPOLITAN_C_START_
|
|||
#define NTTRACE(FMT, ...) (void)0
|
||||
#endif
|
||||
|
||||
extern int __strace;
|
||||
|
||||
void __stracef(const char *, ...);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -18,15 +18,22 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
/**
|
||||
* Flushes file system changes to disk by any means necessary.
|
||||
* @see __nosync to secretly disable
|
||||
*/
|
||||
void sync(void) {
|
||||
if (!IsWindows()) {
|
||||
sys_sync();
|
||||
if (__nosync != 0x5453455454534146) {
|
||||
if (!IsWindows()) {
|
||||
sys_sync();
|
||||
} else {
|
||||
sys_sync_nt();
|
||||
}
|
||||
STRACE("sync()% m");
|
||||
} else {
|
||||
sys_sync_nt();
|
||||
STRACE("sync() → disabled% m");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,66 +68,5 @@ typedef __UINT_FAST64_TYPE__ uint_fast64_t;
|
|||
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
|
||||
#define UINT_FAST16_MIN (-UINT_FAST16_MAX - 1)
|
||||
|
||||
#define atomic_bool _Atomic(_Bool)
|
||||
#define atomic_bool32 atomic_int_fast32_t
|
||||
#define atomic_char _Atomic(char)
|
||||
#define atomic_schar _Atomic(signed char)
|
||||
#define atomic_uchar _Atomic(unsigned char)
|
||||
#define atomic_short _Atomic(short)
|
||||
#define atomic_ushort _Atomic(unsigned short)
|
||||
#define atomic_int _Atomic(int)
|
||||
#define atomic_uint _Atomic(unsigned int)
|
||||
#define atomic_long _Atomic(long)
|
||||
#define atomic_ulong _Atomic(unsigned long)
|
||||
#define atomic_llong _Atomic(long long)
|
||||
#define atomic_ullong _Atomic(unsigned long long)
|
||||
#define atomic_char16_t _Atomic(char16_t)
|
||||
#define atomic_char32_t _Atomic(char32_t)
|
||||
#define atomic_wchar_t _Atomic(wchar_t)
|
||||
#define atomic_int_least8_t _Atomic(int_least8_t)
|
||||
#define atomic_uint_least8_t _Atomic(uint_least8_t)
|
||||
#define atomic_int_least16_t _Atomic(int_least16_t)
|
||||
#define atomic_uint_least16_t _Atomic(uint_least16_t)
|
||||
#define atomic_int_least32_t _Atomic(int_least32_t)
|
||||
#define atomic_uint_least32_t _Atomic(uint_least32_t)
|
||||
#define atomic_int_least64_t _Atomic(int_least64_t)
|
||||
#define atomic_uint_least64_t _Atomic(uint_least64_t)
|
||||
#define atomic_int_fast8_t _Atomic(int_fast8_t)
|
||||
#define atomic_uint_fast8_t _Atomic(uint_fast8_t)
|
||||
#define atomic_int_fast16_t _Atomic(int_fast16_t)
|
||||
#define atomic_uint_fast16_t _Atomic(uint_fast16_t)
|
||||
#define atomic_int_fast32_t _Atomic(int_fast32_t)
|
||||
#define atomic_uint_fast32_t _Atomic(uint_fast32_t)
|
||||
#define atomic_int_fast64_t _Atomic(int_fast64_t)
|
||||
#define atomic_uint_fast64_t _Atomic(uint_fast64_t)
|
||||
#define atomic_intptr_t _Atomic(intptr_t)
|
||||
#define atomic_uintptr_t _Atomic(uintptr_t)
|
||||
#define atomic_size_t _Atomic(size_t)
|
||||
#define atomic_ptrdiff_t _Atomic(ptrdiff_t)
|
||||
|
||||
#ifdef __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE
|
||||
#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE
|
||||
#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE
|
||||
#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE
|
||||
#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE
|
||||
#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE
|
||||
#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE
|
||||
#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE
|
||||
#else
|
||||
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
|
||||
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
|
||||
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
|
||||
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
|
||||
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
|
||||
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
|
||||
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
|
||||
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
|
||||
#endif
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_WEIRDTYPES_H_ */
|
||||
|
|
|
@ -67,8 +67,8 @@
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ + 0 < 201112 && defined(__x86__)
|
||||
#define _Atomic(TYPE) TYPE
|
||||
#if __STDC_VERSION__ + 0 < 201112
|
||||
#define _Atomic(TYPE) TYPE volatile
|
||||
#endif
|
||||
|
||||
#ifdef __llvm__
|
||||
|
@ -123,7 +123,7 @@ typedef __UINT64_TYPE__ uint64_t;
|
|||
typedef __INTMAX_TYPE__ intmax_t;
|
||||
typedef __UINTMAX_TYPE__ uintmax_t;
|
||||
|
||||
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 406 || defined(__llvm__)
|
||||
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406 || defined(__llvm__)
|
||||
typedef signed __int128 int128_t;
|
||||
typedef unsigned __int128 uint128_t;
|
||||
#endif
|
||||
|
|
|
@ -50,6 +50,9 @@
|
|||
#ifndef __has_cpp_attribute
|
||||
#define __has_cpp_attribute(x) 0
|
||||
#endif
|
||||
#ifndef __has_extension
|
||||
#define __has_extension(x) 0
|
||||
#endif
|
||||
|
||||
#ifdef unix
|
||||
#undef unix
|
||||
|
|
|
@ -128,7 +128,7 @@ struct AsanSourceLocation {
|
|||
};
|
||||
|
||||
struct AsanAccessInfo {
|
||||
const uintptr_t addr;
|
||||
const char *addr;
|
||||
const uintptr_t first_bad_addr;
|
||||
size_t size;
|
||||
bool iswrite;
|
||||
|
@ -136,7 +136,7 @@ struct AsanAccessInfo {
|
|||
};
|
||||
|
||||
struct AsanGlobal {
|
||||
const uintptr_t addr;
|
||||
const char *addr;
|
||||
size_t size;
|
||||
size_t size_with_redzone;
|
||||
const void *name;
|
||||
|
@ -339,10 +339,10 @@ dontdiscard static __asan_die_f *__asan_die(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void __asan_poison(long p, long n, signed char t) {
|
||||
void __asan_poison(void *p, long n, signed char t) {
|
||||
signed char k, *s;
|
||||
s = (signed char *)((p >> 3) + 0x7fff8000);
|
||||
if ((k = p & 7)) {
|
||||
s = (signed char *)(((intptr_t)p >> 3) + 0x7fff8000);
|
||||
if ((k = (intptr_t)p & 7)) {
|
||||
if ((!*s && n >= 8 - k) || *s > k) *s = k;
|
||||
n -= MIN(8 - k, n);
|
||||
s += 1;
|
||||
|
@ -354,10 +354,10 @@ void __asan_poison(long p, long n, signed char t) {
|
|||
}
|
||||
}
|
||||
|
||||
void __asan_unpoison(long p, long n) {
|
||||
void __asan_unpoison(void *p, long n) {
|
||||
signed char k, *s;
|
||||
k = p & 7;
|
||||
s = (signed char *)((p >> 3) + 0x7fff8000);
|
||||
k = (intptr_t)p & 7;
|
||||
s = (signed char *)(((intptr_t)p >> 3) + 0x7fff8000);
|
||||
if (UNLIKELY(k)) {
|
||||
if (k + n < 8) {
|
||||
if (n > 0) *s = MAX(*s, k + n);
|
||||
|
@ -737,9 +737,9 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
|||
uint64_t x, y, z;
|
||||
char *p, *q, *base;
|
||||
struct MemoryIntervals *m;
|
||||
++g_ftrace;
|
||||
--__ftrace;
|
||||
p = __fatalbuf;
|
||||
kprintf("\n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p\n%s\n",
|
||||
kprintf("\n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p\n",
|
||||
__asan_describe_access_poison(kind), size, message, addr,
|
||||
SHADOW(addr), __argv[0]);
|
||||
if (0 < size && size < 80) {
|
||||
|
@ -759,19 +759,19 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
|||
for (c = i = 0; i < 80; ++i) {
|
||||
if (!(t = __asan_check(base + i, 1).kind)) {
|
||||
if (c != 32) {
|
||||
p = __stpcpy(p, "\e[32m");
|
||||
*p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '2', *p++ = 'm';
|
||||
c = 32;
|
||||
}
|
||||
*p++ = '.';
|
||||
} else {
|
||||
if (c != 31) {
|
||||
p = __stpcpy(p, "\e[31m");
|
||||
*p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '1', *p++ = 'm';
|
||||
c = 31;
|
||||
}
|
||||
p = __asan_utf8cpy(p, __asan_symbolize_access_poison(t));
|
||||
}
|
||||
}
|
||||
p = __stpcpy(p, "\e[39m");
|
||||
*p++ = '\e', *p++ = '[', *p++ = '3', *p++ = '9', *p++ = 'm';
|
||||
*p++ = '\n';
|
||||
for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' ';
|
||||
for (; i + 8 <= 80; i += 8) {
|
||||
|
@ -814,7 +814,7 @@ dontdiscard static __asan_die_f *__asan_report(const void *addr, int size,
|
|||
kprintf("%s", __fatalbuf);
|
||||
__asan_report_memory_origin(addr, size, kind);
|
||||
kprintf("\nthe crash was caused by\n");
|
||||
--g_ftrace;
|
||||
++__ftrace;
|
||||
return __asan_die();
|
||||
}
|
||||
|
||||
|
@ -840,7 +840,7 @@ dontdiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size,
|
|||
void *__asan_morgue_add(void *p) {
|
||||
int i;
|
||||
void *r;
|
||||
_spinlock_optimistic(&__asan_lock);
|
||||
_spinlock_cooperative(&__asan_lock);
|
||||
i = __asan_morgue.i++ & (ARRAYLEN(__asan_morgue.p) - 1);
|
||||
r = __asan_morgue.p[i];
|
||||
__asan_morgue.p[i] = p;
|
||||
|
@ -851,7 +851,7 @@ void *__asan_morgue_add(void *p) {
|
|||
static void __asan_morgue_flush(void) {
|
||||
int i;
|
||||
void *p;
|
||||
_spinlock_optimistic(&__asan_lock);
|
||||
_spinlock_cooperative(&__asan_lock);
|
||||
for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) {
|
||||
if (weaken(dlfree)) {
|
||||
weaken(dlfree)(__asan_morgue.p[i]);
|
||||
|
@ -943,9 +943,9 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
|
|||
if ((p = weaken(dlmemalign)(a, __asan_heap_size(n)))) {
|
||||
c = weaken(dlmalloc_usable_size)(p);
|
||||
e = (struct AsanExtra *)(p + c - sizeof(*e));
|
||||
__asan_unpoison((uintptr_t)p, n);
|
||||
__asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */
|
||||
__asan_poison((uintptr_t)p + n, c - n, overrun);
|
||||
__asan_unpoison(p, n);
|
||||
__asan_poison(p - 16, 16, underrun); /* see dlmalloc design */
|
||||
__asan_poison(p + n, c - n, overrun);
|
||||
__asan_memset(p, 0xF9, n);
|
||||
__asan_write48(&e->size, n);
|
||||
__asan_memcpy(&e->bt, bt, sizeof(*bt));
|
||||
|
@ -1030,7 +1030,7 @@ static void __asan_deallocate(char *p, long kind) {
|
|||
struct AsanExtra *e;
|
||||
if ((e = __asan_get_extra(p, &c))) {
|
||||
if (__asan_read48(e->size, &n)) {
|
||||
__asan_poison((uintptr_t)p, c, kind);
|
||||
__asan_poison(p, c, kind);
|
||||
if (c <= ASAN_MORGUE_THRESHOLD) {
|
||||
p = __asan_morgue_add(p);
|
||||
}
|
||||
|
@ -1084,11 +1084,11 @@ static void *__asan_realloc_impl(void *p, size_t n,
|
|||
if ((e = __asan_get_extra(p, &c))) {
|
||||
if (__asan_read48(e->size, &m)) {
|
||||
if (n <= m) { /* shrink */
|
||||
__asan_poison((uintptr_t)p + n, m - n, kAsanHeapOverrun);
|
||||
__asan_poison((char *)p + n, m - n, kAsanHeapOverrun);
|
||||
__asan_write48(&e->size, n);
|
||||
return p;
|
||||
} else if (n <= c - sizeof(struct AsanExtra)) { /* small growth */
|
||||
__asan_unpoison((uintptr_t)p + m, n - m);
|
||||
__asan_unpoison((char *)p + m, n - m);
|
||||
__asan_write48(&e->size, n);
|
||||
return p;
|
||||
} else { /* exponential growth */
|
||||
|
@ -1175,13 +1175,12 @@ void __asan_handle_no_return(void) {
|
|||
|
||||
void __asan_register_globals(struct AsanGlobal g[], int n) {
|
||||
int i;
|
||||
__asan_poison((intptr_t)g, sizeof(*g) * n, kAsanProtected);
|
||||
__asan_poison(g, sizeof(*g) * n, kAsanProtected);
|
||||
for (i = 0; i < n; ++i) {
|
||||
__asan_poison(g[i].addr + g[i].size, g[i].size_with_redzone - g[i].size,
|
||||
kAsanGlobalRedzone);
|
||||
if (g[i].location) {
|
||||
__asan_poison((intptr_t)g[i].location, sizeof(*g[i].location),
|
||||
kAsanProtected);
|
||||
__asan_poison(g[i].location, sizeof(*g[i].location), kAsanProtected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1228,15 +1227,15 @@ void __asan_report_store(uint8_t *addr, int size) {
|
|||
}
|
||||
}
|
||||
|
||||
void __asan_poison_stack_memory(uintptr_t addr, size_t size) {
|
||||
void __asan_poison_stack_memory(char *addr, size_t size) {
|
||||
__asan_poison(addr, size, kAsanStackFree);
|
||||
}
|
||||
|
||||
void __asan_unpoison_stack_memory(uintptr_t addr, size_t size) {
|
||||
void __asan_unpoison_stack_memory(char *addr, size_t size) {
|
||||
__asan_unpoison(addr, size);
|
||||
}
|
||||
|
||||
void __asan_alloca_poison(uintptr_t addr, uintptr_t size) {
|
||||
void __asan_alloca_poison(char *addr, uintptr_t size) {
|
||||
__asan_poison(addr - 32, 32, kAsanAllocaUnderrun);
|
||||
__asan_poison(addr + size, 32, kAsanAllocaOverrun);
|
||||
}
|
||||
|
@ -1255,8 +1254,8 @@ void *__asan_get_current_fake_stack(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __sanitizer_annotate_contiguous_container(long beg, long end, long old_mid,
|
||||
long new_mid) {
|
||||
void __sanitizer_annotate_contiguous_container(char *beg, char *end,
|
||||
char *old_mid, char *new_mid) {
|
||||
// the c++ stl uses this
|
||||
// TODO(jart): make me faster
|
||||
__asan_unpoison(beg, new_mid - beg);
|
||||
|
@ -1317,11 +1316,11 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
|
|||
__repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16),
|
||||
kAsanUnmapped, size);
|
||||
}
|
||||
__asan_unpoison((uintptr_t)p, n);
|
||||
__asan_unpoison((char *)p, n);
|
||||
}
|
||||
|
||||
static textstartup void __asan_shadow_string(char *s) {
|
||||
__asan_map_shadow((uintptr_t)s, __strlen(s) + 1);
|
||||
__asan_map_shadow((intptr_t)s, __strlen(s) + 1);
|
||||
}
|
||||
|
||||
static textstartup void __asan_shadow_auxv(intptr_t *auxv) {
|
||||
|
@ -1359,7 +1358,7 @@ static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
|
|||
|
||||
static textstartup void __asan_shadow_existing_mappings(void) {
|
||||
__asan_shadow_mapping(&_mmi, 0);
|
||||
__asan_map_shadow(GetStackAddr(0), GetStackSize());
|
||||
__asan_map_shadow((intptr_t)GetStackAddr(0), GetStackSize());
|
||||
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ struct AsanFault {
|
|||
const signed char *shadow;
|
||||
};
|
||||
|
||||
void __asan_unpoison(long, long);
|
||||
void __asan_poison(long, long, signed char);
|
||||
void __asan_unpoison(void *, long);
|
||||
void __asan_poison(void *, long, signed char);
|
||||
void __asan_verify(const void *, size_t);
|
||||
void __asan_map_shadow(uintptr_t, size_t);
|
||||
bool __asan_is_valid(const void *, long) nosideeffect;
|
||||
|
|
|
@ -33,8 +33,8 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file,
|
|||
int line) {
|
||||
int rc;
|
||||
static bool noreentry;
|
||||
__strace = 0;
|
||||
g_ftrace = 0;
|
||||
--__strace;
|
||||
--__ftrace;
|
||||
kprintf("%s:%d: assert(%s) failed\n", file, line, expr);
|
||||
if (_lockcmpxchg(&noreentry, false, true)) {
|
||||
if (weaken(__die)) {
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/*-*- 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/intrin/atomic_load.h"
|
||||
|
||||
/**
|
||||
* Reads scalar from memory w/ one operation.
|
||||
*
|
||||
* This macro is intended to prevent things like compiler load tearing
|
||||
* optimizations.
|
||||
*
|
||||
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @return *(MEM)
|
||||
* @note defeats compiler load tearing optimizations
|
||||
* @note alignas(𝑘) is implied if compiler knows type
|
||||
* @note alignas(𝑘) only avoids multi-core / cross-page edge cases
|
||||
* @see Intel's Six-Thousand Page Manual V.3A §8.2.3.1
|
||||
* @see atomic_store()
|
||||
*/
|
||||
intptr_t(atomic_load)(void *p, size_t n) {
|
||||
intptr_t x = 0;
|
||||
switch (n) {
|
||||
case 1:
|
||||
__builtin_memcpy(&x, p, 1);
|
||||
return x;
|
||||
case 2:
|
||||
__builtin_memcpy(&x, p, 2);
|
||||
return x;
|
||||
case 4:
|
||||
__builtin_memcpy(&x, p, 4);
|
||||
return x;
|
||||
case 8:
|
||||
__builtin_memcpy(&x, p, 8);
|
||||
return x;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
intptr_t atomic_load(void *, size_t);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define atomic_load(MEM) \
|
||||
({ \
|
||||
autotype(MEM) Mem = (MEM); \
|
||||
typeof(*Mem) Reg; \
|
||||
asm("mov\t%1,%0" : "=r"(Reg) : "m"(*Mem)); \
|
||||
Reg; \
|
||||
})
|
||||
#else
|
||||
#define atomic_load(MEM) atomic_load(MEM, sizeof(*(MEM)))
|
||||
#endif /* GNUC && !ANSI && x86 */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ATOMIC_LOAD_H_ */
|
|
@ -1,54 +0,0 @@
|
|||
/*-*- 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/intrin/atomic_store.h"
|
||||
|
||||
/**
|
||||
* Saves scalar to memory w/ one operation.
|
||||
*
|
||||
* This is guaranteed to happen in either one or zero operations,
|
||||
* depending on whether or not it's possible for *(MEM) to be read
|
||||
* afterwards. This macro only forbids compiler from using >1 ops.
|
||||
*
|
||||
* @param MEM is alignas(𝑘) uint𝑘_t[hasatleast 1] where 𝑘 ∈ {8,16,32,64}
|
||||
* @param VAL is uint𝑘_t w/ better encoding for immediates (constexpr)
|
||||
* @return VAL
|
||||
* @note alignas(𝑘) on nexgen32e only needed for end of page gotcha
|
||||
* @note alignas(𝑘) is implied if compiler knows type
|
||||
* @note needed to defeat store tearing optimizations
|
||||
* @see Intel Six-Thousand Page Manual Manual V.3A §8.2.3.1
|
||||
* @see atomic_load()
|
||||
*/
|
||||
intptr_t(atomic_store)(void *p, intptr_t x, size_t n) {
|
||||
switch (n) {
|
||||
case 1:
|
||||
__builtin_memcpy(p, &x, 1);
|
||||
return x;
|
||||
case 2:
|
||||
__builtin_memcpy(p, &x, 2);
|
||||
return x;
|
||||
case 4:
|
||||
__builtin_memcpy(p, &x, 4);
|
||||
return x;
|
||||
case 8:
|
||||
__builtin_memcpy(p, &x, 8);
|
||||
return x;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
intptr_t atomic_store(void *, intptr_t, size_t);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define atomic_store(MEM, VAL) \
|
||||
({ \
|
||||
autotype(VAL) Val = (VAL); \
|
||||
typeof(&Val) Mem = (MEM); \
|
||||
asm("mov%z1\t%1,%0" : "=m"(*Mem) : "r"(Val)); \
|
||||
Val; \
|
||||
})
|
||||
#else
|
||||
#define atomic_store(MEM, VAL) \
|
||||
atomic_store(MEM, VAL, sizeof(*(MEM)) / (sizeof(*(MEM)) == sizeof(*(VAL))))
|
||||
#endif /* __GNUC__ && !__STRICT_ANSI__ */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_INTRIN_ATOMIC_STORE_H_ */
|
|
@ -3,6 +3,7 @@
|
|||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/rlimit.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/sigaltstack.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
|
@ -27,6 +28,7 @@ const char *DescribePollFlags(char *, size_t, int);
|
|||
const char *DescribeStat(int, const struct stat *);
|
||||
const char *DescribeDirfd(char[hasatleast 12], int);
|
||||
const char *DescribeSigaction(char *, size_t, int, const struct sigaction *);
|
||||
const char *DescribeSigaltstk(char *, size_t, int, const struct sigaltstack *);
|
||||
const char *DescribeSigset(char *, size_t, int, const sigset_t *);
|
||||
const char *DescribeRlimit(char *, size_t, int, const struct rlimit *);
|
||||
const char *DescribeTimespec(char *, size_t, int, const struct timespec *);
|
||||
|
|
|
@ -30,17 +30,17 @@ noasan const char *DescribeFrame(int x) {
|
|||
char *p;
|
||||
static char buf[32];
|
||||
if (IsShadowFrame(x)) {
|
||||
ksnprintf(buf, sizeof(buf), " /*shadow:%.12p*/", UNSHADOW(ADDR(x)));
|
||||
ksnprintf(buf, sizeof(buf), " shadow=%.8x", FRAME(UNSHADOW(ADDR(x))));
|
||||
return buf;
|
||||
return " /*shadow*/ ";
|
||||
return " shadow ";
|
||||
} else if (IsAutoFrame(x)) {
|
||||
return " /*automap*/";
|
||||
return " automap";
|
||||
} else if (IsFixedFrame(x)) {
|
||||
return " /*fixed*/ ";
|
||||
return " fixed ";
|
||||
} else if (IsArenaFrame(x)) {
|
||||
return " /*arena*/ ";
|
||||
return " arena ";
|
||||
} else if (IsStaticStackFrame(x)) {
|
||||
return " /*stack*/ ";
|
||||
return " stack ";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ const char *DescribeMapFlags(int x) {
|
|||
_Alignas(char) static char mapflags[256];
|
||||
const struct DescribeFlags kMapFlags[] = {
|
||||
{MAP_STACK, "STACK"}, // order matters
|
||||
{MAP_ANONYMOUS, "ANONYMOUS"}, //
|
||||
{MAP_PRIVATE, "PRIVATE"}, //
|
||||
{MAP_ANONYMOUS, "ANONYMOUS"}, //
|
||||
{MAP_SHARED, "SHARED"}, //
|
||||
{MAP_FIXED, "FIXED"}, //
|
||||
{MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
|
||||
|
|
|
@ -18,4 +18,25 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
int g_ftrace;
|
||||
/**
|
||||
* Function tracing enabled state.
|
||||
*
|
||||
* After ftrace_install() has been called, the logging of C function
|
||||
* calls may be controlled by changing this variable. If `__ftrace` is
|
||||
* greater than zero, functions are logged. Otherwise, they aren't.
|
||||
*
|
||||
* By convention, functions wishing to disable function tracing for a
|
||||
* short time period should say:
|
||||
*
|
||||
* void foo() {
|
||||
* --__ftrace;
|
||||
* bar();
|
||||
* ++__ftrace;
|
||||
* }
|
||||
*
|
||||
* This way you still have some flexibility to force function tracing,
|
||||
* by setting `__ftrace` to a higher number like `2` or `200`. Even
|
||||
* though under normal circumstances, `__ftrace` should only be either
|
||||
* zero or one.
|
||||
*/
|
||||
_Atomic(int) __ftrace;
|
||||
|
|
|
@ -66,50 +66,57 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
|
|||
|
||||
o/$(MODE)/libc/intrin/tls.greg.o \
|
||||
o/$(MODE)/libc/intrin/exit.greg.o \
|
||||
o/$(MODE)/libc/intrin/errno.greg.o \
|
||||
o/$(MODE)/libc/intrin/exit1.greg.o \
|
||||
o/$(MODE)/libc/intrin/gettid.greg.o \
|
||||
o/$(MODE)/libc/intrin/getenv.greg.o \
|
||||
o/$(MODE)/libc/intrin/createfile.greg.o \
|
||||
o/$(MODE)/libc/intrin/assertfail.greg.o \
|
||||
o/$(MODE)/libc/intrin/reopenfile.greg.o \
|
||||
o/$(MODE)/libc/intrin/deletefile.greg.o \
|
||||
o/$(MODE)/libc/intrin/createpipe.greg.o \
|
||||
o/$(MODE)/libc/intrin/closehandle.greg.o \
|
||||
o/$(MODE)/libc/intrin/describeiov.greg.o \
|
||||
o/$(MODE)/libc/intrin/openprocess.greg.o \
|
||||
o/$(MODE)/libc/intrin/createthread.greg.o \
|
||||
o/$(MODE)/libc/intrin/describestat.greg.o \
|
||||
o/$(MODE)/libc/intrin/findnextfile.greg.o \
|
||||
o/$(MODE)/libc/intrin/createprocess.greg.o \
|
||||
o/$(MODE)/libc/intrin/findfirstfile.greg.o \
|
||||
o/$(MODE)/libc/intrin/describeflags.greg.o \
|
||||
o/$(MODE)/libc/intrin/describerlimit.greg.o \
|
||||
o/$(MODE)/libc/intrin/removedirectory.greg.o \
|
||||
o/$(MODE)/libc/intrin/createnamedpipe.greg.o \
|
||||
o/$(MODE)/libc/intrin/unmapviewoffile.greg.o \
|
||||
o/$(MODE)/libc/intrin/flushviewoffile.greg.o \
|
||||
o/$(MODE)/libc/intrin/deviceiocontrol.greg.o \
|
||||
o/$(MODE)/libc/intrin/createdirectory.greg.o \
|
||||
o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \
|
||||
o/$(MODE)/libc/intrin/terminateprocess.greg.o \
|
||||
o/$(MODE)/libc/intrin/describemapflags.greg.o \
|
||||
o/$(MODE)/libc/intrin/describetimespec.greg.o \
|
||||
o/$(MODE)/libc/intrin/getfileattributes.greg.o \
|
||||
o/$(MODE)/libc/intrin/getexitcodeprocess.greg.o \
|
||||
o/$(MODE)/libc/intrin/waitforsingleobject.greg.o \
|
||||
o/$(MODE)/libc/intrin/setcurrentdirectory.greg.o \
|
||||
o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \
|
||||
o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \
|
||||
o/$(MODE)/libc/intrin/waitformultipleobjects.greg.o \
|
||||
o/$(MODE)/libc/intrin/generateconsolectrlevent.greg.o \
|
||||
o/$(MODE)/libc/intrin/createfile.o \
|
||||
o/$(MODE)/libc/intrin/reopenfile.o \
|
||||
o/$(MODE)/libc/intrin/deletefile.o \
|
||||
o/$(MODE)/libc/intrin/createpipe.o \
|
||||
o/$(MODE)/libc/intrin/closehandle.o \
|
||||
o/$(MODE)/libc/intrin/openprocess.o \
|
||||
o/$(MODE)/libc/intrin/createthread.o \
|
||||
o/$(MODE)/libc/intrin/findclose.o \
|
||||
o/$(MODE)/libc/intrin/findnextfile.o \
|
||||
o/$(MODE)/libc/intrin/createprocess.o \
|
||||
o/$(MODE)/libc/intrin/findfirstfile.o \
|
||||
o/$(MODE)/libc/intrin/removedirectory.o \
|
||||
o/$(MODE)/libc/intrin/createsymboliclink.o \
|
||||
o/$(MODE)/libc/intrin/createnamedpipe.o \
|
||||
o/$(MODE)/libc/intrin/unmapviewoffile.o \
|
||||
o/$(MODE)/libc/intrin/virtualprotect.o \
|
||||
o/$(MODE)/libc/intrin/flushviewoffile.o \
|
||||
o/$(MODE)/libc/intrin/createdirectory.o \
|
||||
o/$(MODE)/libc/intrin/flushfilebuffers.o \
|
||||
o/$(MODE)/libc/intrin/terminateprocess.o \
|
||||
o/$(MODE)/libc/intrin/getfileattributes.o \
|
||||
o/$(MODE)/libc/intrin/getexitcodeprocess.o \
|
||||
o/$(MODE)/libc/intrin/waitforsingleobject.o \
|
||||
o/$(MODE)/libc/intrin/setcurrentdirectory.o \
|
||||
o/$(MODE)/libc/intrin/mapviewoffileex.o \
|
||||
o/$(MODE)/libc/intrin/movefileex.o \
|
||||
o/$(MODE)/libc/intrin/mapviewoffileexnuma.o \
|
||||
o/$(MODE)/libc/intrin/createfilemapping.o \
|
||||
o/$(MODE)/libc/intrin/createfilemappingnuma.o \
|
||||
o/$(MODE)/libc/intrin/waitformultipleobjects.o \
|
||||
o/$(MODE)/libc/intrin/generateconsolectrlevent.o \
|
||||
o/$(MODE)/libc/intrin/kstarttsc.o \
|
||||
o/$(MODE)/libc/intrin/nomultics.o \
|
||||
o/$(MODE)/libc/intrin/ntconsolemode.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-Os \
|
||||
-fwrapv \
|
||||
-ffreestanding \
|
||||
$(NO_MAGIC)
|
||||
-fno-stack-protector \
|
||||
-fno-sanitize=all
|
||||
|
||||
o/$(MODE)/libc/intrin/describeopenflags.greg.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
|
|
|
@ -40,6 +40,7 @@ kOpenFlags:
|
|||
.e O_TRUNC,"TRUNC" //
|
||||
.e O_CLOEXEC,"CLOEXEC" //
|
||||
.e O_NONBLOCK,"NONBLOCK" //
|
||||
.e O_DIRECTORY,"DIRECTORY" //
|
||||
.e O_DIRECT,"DIRECT" // no-op on xnu/openbsd
|
||||
.e O_APPEND,"APPEND" // weird on nt
|
||||
.e O_TMPFILE,"TMPFILE" // linux, windows
|
||||
|
|
54
libc/intrin/sched_yield.S
Normal file
54
libc/intrin/sched_yield.S
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*-*- 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 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
// Asks kernel to let other threads be scheduled.
|
||||
//
|
||||
// @return 0 on success, or -1 w/ errno
|
||||
sched_yield:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
testb IsWindows()
|
||||
jnz 1f
|
||||
|
||||
// UNIX Support
|
||||
mov __NR_sched_yield,%eax
|
||||
syscall
|
||||
jmp 2f
|
||||
|
||||
// Windows Support
|
||||
//
|
||||
// A value of zero, together with the bAlertable parameter set to
|
||||
// FALSE, causes the thread to relinquish the remainder of its time
|
||||
// slice to any other thread that is ready to run, if there are no
|
||||
// pending user APCs on the calling thread. If there are no other
|
||||
// threads ready to run and no user APCs are queued, the function
|
||||
// returns immediately, and the thread continues execution.
|
||||
// ──Quoth MSDN
|
||||
1: xor %ecx,%ecx
|
||||
xor %edx,%edx
|
||||
ntcall __imp_SleepEx
|
||||
xor %eax,%eax
|
||||
|
||||
2: pop %rbp
|
||||
ret
|
||||
.endfn sched_yield,globl
|
||||
.previous
|
|
@ -1,13 +1,8 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
||||
#define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
||||
#if IsModeDbg() && !defined(_SPINLOCK_DEBUG)
|
||||
#define _SPINLOCK_DEBUG
|
||||
|
@ -15,13 +10,13 @@
|
|||
|
||||
#if defined(_SPINLOCK_DEBUG)
|
||||
#define _spinlock(lock) _spinlock_ndebug(lock)
|
||||
#define _spinlock_ndebug(lock) _spinlock_optimistic(lock)
|
||||
#define _spinlock_ndebug(lock) _spinlock_cooperative(lock)
|
||||
#elif defined(TINY)
|
||||
#define _spinlock(lock) _spinlock_tiny(lock)
|
||||
#define _spinlock_ndebug(lock) _spinlock_tiny(lock)
|
||||
#else
|
||||
#define _spinlock(lock) _spinlock_optimistic(lock)
|
||||
#define _spinlock_ndebug(lock) _spinlock_optimistic(lock)
|
||||
#define _spinlock(lock) _spinlock_cooperative(lock)
|
||||
#define _spinlock_ndebug(lock) _spinlock_cooperative(lock)
|
||||
#endif
|
||||
|
||||
#define _spunlock(lock) __atomic_clear(lock, __ATOMIC_RELAXED)
|
||||
|
@ -41,15 +36,18 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define _spinlock_optimistic(lock) \
|
||||
#define _spinlock_cooperative(lock) \
|
||||
do { \
|
||||
int __tries = 0; \
|
||||
for (;;) { \
|
||||
typeof(*(lock)) x; \
|
||||
__atomic_load(lock, &x, __ATOMIC_RELAXED); \
|
||||
if (!x && !_trylock(lock)) { \
|
||||
break; \
|
||||
} else { \
|
||||
} else if (++__tries & 7) { \
|
||||
__builtin_ia32_pause(); \
|
||||
} else { \
|
||||
sched_yield(); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -57,7 +55,7 @@
|
|||
#define _spinlock_debug(lock) \
|
||||
do { \
|
||||
typeof(*(lock)) me, owner; \
|
||||
unsigned long warntries = 10000000; \
|
||||
unsigned long warntries = 16777216; \
|
||||
me = gettid(); \
|
||||
if (!_lockcmpxchg(lock, 0, me)) { \
|
||||
__atomic_load(lock, &owner, __ATOMIC_RELAXED); \
|
||||
|
@ -71,7 +69,11 @@
|
|||
kprintf("%s:%d: warning: possible deadlock on %s in %s()\n", \
|
||||
__FILE__, __LINE__, #lock, __FUNCTION__); \
|
||||
} \
|
||||
__builtin_ia32_pause(); \
|
||||
if (warntries & 7) { \
|
||||
__builtin_ia32_pause(); \
|
||||
} else { \
|
||||
sched_yield(); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
privileged void __stracef(const char *fmt, ...) {
|
||||
va_list v;
|
||||
|
|
4
libc/isystem/stdatomic.h
Normal file
4
libc/isystem/stdatomic.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_
|
||||
#define COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_
|
||||
#include "libc/bits/atomic.h"
|
||||
#endif /* COSMOPOLITAN_LIBC_ISYSTEM_STDATOMIC_H_ */
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
@ -86,6 +87,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (IsLinux() && !__is_linux_2_6_23()) {
|
||||
// we need the `addr2line -a` option
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
argv[i++] = "addr2line";
|
||||
|
@ -177,12 +183,12 @@ static int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
|||
void ShowBacktrace(int fd, const struct StackFrame *bp) {
|
||||
#ifdef __FNO_OMIT_FRAME_POINTER__
|
||||
/* asan runtime depends on this function */
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED);
|
||||
--__ftrace;
|
||||
--__strace;
|
||||
if (!bp) bp = __builtin_frame_address(0);
|
||||
PrintBacktrace(fd, bp);
|
||||
__atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED);
|
||||
++__strace;
|
||||
++__ftrace;
|
||||
#else
|
||||
(fprintf)(stderr, "ShowBacktrace() needs these flags to show C backtrace:\n"
|
||||
"\t-D__FNO_OMIT_FRAME_POINTER__\n"
|
||||
|
|
|
@ -45,8 +45,8 @@ relegated void __check_fail(const char *suffix, const char *opstr,
|
|||
size_t i;
|
||||
va_list va;
|
||||
char hostname[32];
|
||||
__strace = 0;
|
||||
g_ftrace = 0;
|
||||
--__strace;
|
||||
--__ftrace;
|
||||
e = errno;
|
||||
__start_fatal(file, line);
|
||||
__stpcpy(hostname, "unknown");
|
||||
|
|
|
@ -78,15 +78,15 @@ extern unsigned __log_level; /* log level for runtime check */
|
|||
// log a message with the specified log level (not checking if LOGGABLE)
|
||||
#define LOGF(LEVEL, FMT, ...) \
|
||||
do { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
flogf(LEVEL, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} while (0)
|
||||
|
||||
// die with an error message without backtrace and debugger invocation
|
||||
#define DIEF(FMT, ...) \
|
||||
do { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
if (weaken(__die)) weaken(__die)(); \
|
||||
exit(1); \
|
||||
|
@ -95,7 +95,7 @@ extern unsigned __log_level; /* log level for runtime check */
|
|||
|
||||
#define FATALF(FMT, ...) \
|
||||
do { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
ffatalf(kLogFatal, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
unreachable; \
|
||||
} while (0)
|
||||
|
@ -103,78 +103,78 @@ extern unsigned __log_level; /* log level for runtime check */
|
|||
#define ERRORF(FMT, ...) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogError)) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
flogf(kLogError, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WARNF(FMT, ...) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogWarn)) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
flogf(kLogWarn, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define INFOF(FMT, ...) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogInfo)) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
flogf(kLogInfo, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VERBOSEF(FMT, ...) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogVerbose)) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
fverbosef(kLogVerbose, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DEBUGF(FMT, ...) \
|
||||
do { \
|
||||
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
fdebugf(kLogDebug, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define NOISEF(FMT, ...) \
|
||||
do { \
|
||||
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
fnoisef(kLogNoise, __FILE__, __LINE__, NULL, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FLOGF(F, FMT, ...) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogInfo)) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
flogf(kLogInfo, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FWARNF(F, FMT, ...) \
|
||||
do { \
|
||||
if (LOGGABLE(kLogWarn)) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
flogf(kLogWarn, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FFATALF(F, FMT, ...) \
|
||||
do { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
ffatalf(kLogFatal, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||
unreachable; \
|
||||
} while (0)
|
||||
|
@ -182,18 +182,18 @@ extern unsigned __log_level; /* log level for runtime check */
|
|||
#define FDEBUGF(F, FMT, ...) \
|
||||
do { \
|
||||
if (UNLIKELY(LOGGABLE(kLogDebug))) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
fdebugf(kLogDebug, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FNOISEF(F, FMT, ...) \
|
||||
do { \
|
||||
if (UNLIKELY(LOGGABLE(kLogNoise))) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
fnoisef(kLogNoise, __FILE__, __LINE__, F, FMT, ##__VA_ARGS__); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
@ -206,25 +206,25 @@ extern unsigned __log_level; /* log level for runtime check */
|
|||
int e = errno; \
|
||||
autotype(FORM) Ax = (FORM); \
|
||||
if (UNLIKELY(Ax == (typeof(Ax))(-1)) && LOGGABLE(kLogWarn)) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
--__ftrace; \
|
||||
__logerrno(__FILE__, __LINE__, #FORM); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
++__ftrace; \
|
||||
errno = e; \
|
||||
} \
|
||||
Ax; \
|
||||
})
|
||||
|
||||
#define LOGIFNULL(FORM) \
|
||||
({ \
|
||||
int e = errno; \
|
||||
autotype(FORM) Ax = (FORM); \
|
||||
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
__logerrno(__FILE__, __LINE__, #FORM); \
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED); \
|
||||
errno = e; \
|
||||
} \
|
||||
Ax; \
|
||||
#define LOGIFNULL(FORM) \
|
||||
({ \
|
||||
int e = errno; \
|
||||
autotype(FORM) Ax = (FORM); \
|
||||
if (Ax == NULL && LOGGABLE(kLogWarn)) { \
|
||||
--__ftrace; \
|
||||
__logerrno(__FILE__, __LINE__, #FORM); \
|
||||
++__ftrace; \
|
||||
errno = e; \
|
||||
} \
|
||||
Ax; \
|
||||
})
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
|
|
|
@ -75,7 +75,6 @@ o/$(MODE)/libc/log/backtrace3.o \
|
|||
o/$(MODE)/libc/log/checkaligned.o \
|
||||
o/$(MODE)/libc/log/checkfail.o \
|
||||
o/$(MODE)/libc/log/checkfail_ndebug.o \
|
||||
o/$(MODE)/libc/log/getsymboltable.o \
|
||||
o/$(MODE)/libc/log/restoretty.o \
|
||||
o/$(MODE)/libc/log/oncrash.o \
|
||||
o/$(MODE)/libc/log/onkill.o \
|
||||
|
|
|
@ -206,8 +206,9 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
|||
" %m\n"
|
||||
" %s %s %s %s\n",
|
||||
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "", sig,
|
||||
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
||||
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
|
||||
(ctx &&
|
||||
(ctx->uc_mcontext.rsp >= (intptr_t)GetStaticStackAddr(0) &&
|
||||
ctx->uc_mcontext.rsp <= (intptr_t)GetStaticStackAddr(0) + PAGESIZE))
|
||||
? "Stack Overflow"
|
||||
: GetSiCodeName(sig, si->si_code),
|
||||
host, getpid(), gettid(), program_invocation_name, names.sysname,
|
||||
|
@ -278,8 +279,8 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
|||
int gdbpid, err;
|
||||
static bool noreentry, notpossible;
|
||||
STRACE("__oncrash rip %x", ctx->uc_mcontext.rip);
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED);
|
||||
--__ftrace;
|
||||
--__strace;
|
||||
if (_lockcmpxchg(&noreentry, false, true)) {
|
||||
if (!__vforked) {
|
||||
rip = ctx ? ctx->uc_mcontext.rip : 0;
|
||||
|
@ -317,6 +318,6 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
|
|||
}
|
||||
noreentry = false;
|
||||
ItsATrap:
|
||||
__atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED);
|
||||
++__strace;
|
||||
++__ftrace;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,14 @@ STATIC_YOINK("__die"); /* for backtracing */
|
|||
STATIC_YOINK("malloc_inspect_all"); /* for asan memory origin */
|
||||
STATIC_YOINK("__get_symbol_by_addr"); /* for asan memory origin */
|
||||
|
||||
static struct sigaltstack oldsigaltstack;
|
||||
extern const unsigned char __oncrash_thunks[8][11];
|
||||
|
||||
static void FreeSigAltStack(void *p) {
|
||||
sigaltstack(&oldsigaltstack, 0);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs crash signal handlers.
|
||||
*
|
||||
|
@ -63,17 +69,24 @@ void ShowCrashReports(void) {
|
|||
kCrashSigs[5] = SIGABRT; /* abort() called */
|
||||
kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */
|
||||
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||
if (!IsWindows()) {
|
||||
bzero(&ss, sizeof(ss));
|
||||
ss.ss_flags = 0;
|
||||
ss.ss_size = SIGSTKSZ;
|
||||
if ((ss.ss_sp = malloc(SIGSTKSZ))) {
|
||||
if (!sigaltstack(&ss, &oldsigaltstack)) {
|
||||
__cxa_atexit(FreeSigAltStack, ss.ss_sp, 0);
|
||||
} else {
|
||||
free(ss.ss_sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
bzero(&sa, sizeof(sa));
|
||||
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);
|
||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
sigdelset(&sa.sa_mask, kCrashSigs[i]);
|
||||
}
|
||||
if (!IsWindows()) sigaltstack(&ss, 0);
|
||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
if (kCrashSigs[i]) {
|
||||
sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i];
|
||||
|
|
|
@ -105,10 +105,14 @@ Fail:
|
|||
return einval();
|
||||
}
|
||||
|
||||
static void UnsetenvFree(void *p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
/* weakly called by unsetenv() when removing a pointer */
|
||||
void __freeenv(void *p) {
|
||||
if (once) {
|
||||
__cxa_atexit(free, p, 0);
|
||||
__cxa_atexit(UnsetenvFree, p, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
||||
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
||||
|
@ -27,6 +28,12 @@ noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
|||
STRACE("AreMemoryIntervalsOk() y should be >= x!");
|
||||
return false;
|
||||
}
|
||||
if (!(mm->p[i].size <=
|
||||
(size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE + FRAMESIZE &&
|
||||
mm->p[i].size > (size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE)) {
|
||||
STRACE("AreMemoryIntervalsOk() size is wrong!");
|
||||
return false;
|
||||
}
|
||||
if (i) {
|
||||
if (mm->p[i].h != -1 || mm->p[i - 1].h != -1) {
|
||||
if (mm->p[i].x <= mm->p[i - 1].y) {
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/ntstdin.internal.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
@ -222,7 +221,6 @@ textwindows void WinMainForked(void) {
|
|||
|
||||
// rewrap the stdin named pipe hack
|
||||
// since the handles closed on fork
|
||||
if (weaken(ForkNtStdinWorker)) weaken(ForkNtStdinWorker)();
|
||||
struct Fds *fds = VEIL("r", &g_fds);
|
||||
fds->p[0].handle = fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle);
|
||||
fds->p[1].handle = fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
.privileged
|
||||
|
||||
ftrace_hook:
|
||||
cmp $0,g_ftrace(%rip)
|
||||
cmp $0,__ftrace(%rip)
|
||||
jg 1f
|
||||
ret
|
||||
1: push %rbp
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
textstartup int ftrace_init(void) {
|
||||
if (__intercept_flag(&__argc, __argv, "--ftrace")) {
|
||||
ftrace_install();
|
||||
++g_ftrace;
|
||||
++__ftrace;
|
||||
}
|
||||
return __argc;
|
||||
}
|
||||
|
|
|
@ -17,24 +17,26 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/rdtscp.h"
|
||||
#include "libc/nexgen32e/stackframe.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/time/clockstonanos.internal.h"
|
||||
|
||||
#pragma weak stderr
|
||||
|
||||
#define MAX_NESTING 512
|
||||
|
||||
/**
|
||||
|
@ -47,13 +49,16 @@
|
|||
|
||||
void ftrace_hook(void);
|
||||
|
||||
bool ftrace_enabled;
|
||||
static int g_skew;
|
||||
static int64_t g_lastaddr;
|
||||
static uint64_t g_laststamp;
|
||||
_Alignas(64) char ftrace_lock;
|
||||
|
||||
static privileged noinstrument noasan noubsan int GetNestingLevelImpl(
|
||||
struct StackFrame *frame) {
|
||||
static struct Ftrace {
|
||||
int skew;
|
||||
int stackdigs;
|
||||
int64_t lastaddr;
|
||||
uint64_t laststamp;
|
||||
} g_ftrace;
|
||||
|
||||
static privileged int GetNestingLevelImpl(struct StackFrame *frame) {
|
||||
int nesting = -2;
|
||||
while (frame) {
|
||||
++nesting;
|
||||
|
@ -62,12 +67,11 @@ static privileged noinstrument noasan noubsan int GetNestingLevelImpl(
|
|||
return MAX(0, nesting);
|
||||
}
|
||||
|
||||
static privileged noinstrument noasan noubsan int GetNestingLevel(
|
||||
struct StackFrame *frame) {
|
||||
static privileged int GetNestingLevel(struct StackFrame *frame) {
|
||||
int nesting;
|
||||
nesting = GetNestingLevelImpl(frame);
|
||||
if (nesting < g_skew) g_skew = nesting;
|
||||
nesting -= g_skew;
|
||||
if (nesting < g_ftrace.skew) g_ftrace.skew = nesting;
|
||||
nesting -= g_ftrace.skew;
|
||||
return MIN(MAX_NESTING, nesting);
|
||||
}
|
||||
|
||||
|
@ -78,32 +82,30 @@ static privileged noinstrument noasan noubsan int GetNestingLevel(
|
|||
* prologues of other functions. We assume those functions behave
|
||||
* according to the System Five NexGen32e ABI.
|
||||
*/
|
||||
privileged noinstrument noasan noubsan void ftracer(void) {
|
||||
/* asan runtime depends on this function */
|
||||
privileged void ftracer(void) {
|
||||
uint64_t stamp;
|
||||
static bool noreentry;
|
||||
size_t stackuse;
|
||||
struct StackFrame *frame;
|
||||
if (!_cmpxchg(&noreentry, 0, 1)) return;
|
||||
if (ftrace_enabled) {
|
||||
stamp = rdtsc();
|
||||
frame = __builtin_frame_address(0);
|
||||
frame = frame->next;
|
||||
if (frame->addr != g_lastaddr) {
|
||||
kprintf("%rFUN %5P %'18T %*s%t\r\n", GetNestingLevel(frame) * 2, "",
|
||||
frame->addr);
|
||||
g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
|
||||
g_lastaddr = frame->addr;
|
||||
}
|
||||
_spinlock_cooperative(&ftrace_lock);
|
||||
stamp = rdtsc();
|
||||
frame = __builtin_frame_address(0);
|
||||
frame = frame->next;
|
||||
if (frame->addr != g_ftrace.lastaddr) {
|
||||
stackuse = ROUNDUP((intptr_t)frame, GetStackSize()) - (intptr_t)frame;
|
||||
kprintf("%rFUN %5P %'13T %'*lu %*s%t\r\n", g_ftrace.stackdigs, stackuse,
|
||||
GetNestingLevel(frame) * 2, "", frame->addr);
|
||||
g_ftrace.laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
|
||||
g_ftrace.lastaddr = frame->addr;
|
||||
}
|
||||
noreentry = 0;
|
||||
_spunlock(&ftrace_lock);
|
||||
}
|
||||
|
||||
textstartup int ftrace_install(void) {
|
||||
if (GetSymbolTable()) {
|
||||
g_lastaddr = -1;
|
||||
g_laststamp = kStartTsc;
|
||||
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
|
||||
ftrace_enabled = 1;
|
||||
g_ftrace.lastaddr = -1;
|
||||
g_ftrace.laststamp = kStartTsc;
|
||||
g_ftrace.stackdigs = LengthInt64Thousands(GetStackSize());
|
||||
g_ftrace.skew = GetNestingLevelImpl(__builtin_frame_address(0));
|
||||
return __hook(ftrace_hook, GetSymbolTable());
|
||||
} else {
|
||||
kprintf("error: --ftrace failed to open symbol table\r\n");
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
|
@ -112,7 +113,9 @@ int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
|||
|
||||
static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
|
||||
if (CreateMemoryInterval(mm, i) == -1) return -1;
|
||||
mm->p[i].y = x - 1;
|
||||
mm->p[i + 0].size -= (size_t)(mm->p[i + 0].y - (x - 1)) * FRAMESIZE;
|
||||
mm->p[i + 0].y = x - 1;
|
||||
mm->p[i + 1].size -= (size_t)((y + 1) - mm->p[i + 1].x) * FRAMESIZE;
|
||||
mm->p[i + 1].x = y + 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -123,31 +126,60 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
|||
assert(y >= x);
|
||||
assert(AreMemoryIntervalsOk(mm));
|
||||
if (!mm->i) return 0;
|
||||
|
||||
// binary search for the lefthand side
|
||||
l = FindMemoryInterval(mm, x);
|
||||
if (l == mm->i) return 0;
|
||||
if (!l && y < mm->p[l].x) return 0;
|
||||
if (y < mm->p[l].x) return 0;
|
||||
|
||||
// binary search for the righthand side
|
||||
r = FindMemoryInterval(mm, y);
|
||||
if (r == mm->i || (r > l && y < mm->p[r].x)) --r;
|
||||
assert(r >= l);
|
||||
assert(x <= mm->p[r].y);
|
||||
|
||||
// remove the middle of an existing map
|
||||
//
|
||||
// ----|mmmmmmmmmmmmmmmm|--------- before
|
||||
// xxxxx
|
||||
// ----|mmmm|-----|mmmmm|--------- after
|
||||
//
|
||||
// this isn't possible on windows because we track each
|
||||
// 64kb segment on that platform using a separate entry
|
||||
if (l == r && x > mm->p[l].x && y < mm->p[l].y) {
|
||||
return PunchHole(mm, x, y, l);
|
||||
}
|
||||
|
||||
// trim the right side of the lefthand map
|
||||
//
|
||||
// ----|mmmmmmm|-------------- before
|
||||
// xxxxx
|
||||
// ----|mmmm|----------------- after
|
||||
//
|
||||
if (x > mm->p[l].x && x <= mm->p[l].y) {
|
||||
assert(y >= mm->p[l].y);
|
||||
if (IsWindows()) return einval();
|
||||
mm->p[l].size -= (size_t)(mm->p[l].y - (x - 1)) * FRAMESIZE;
|
||||
mm->p[l].y = x - 1;
|
||||
assert(mm->p[l].x <= mm->p[l].y);
|
||||
++l;
|
||||
}
|
||||
|
||||
// trim the left side of the righthand map
|
||||
//
|
||||
// ------------|mmmmm|-------- before
|
||||
// xxxxx
|
||||
// ---------------|mm|-------- after
|
||||
//
|
||||
if (y >= mm->p[r].x && y < mm->p[r].y) {
|
||||
assert(x <= mm->p[r].x);
|
||||
if (IsWindows()) return einval();
|
||||
mm->p[r].size -= (size_t)((y + 1) - mm->p[r].x) * FRAMESIZE;
|
||||
mm->p[r].x = y + 1;
|
||||
assert(mm->p[r].x <= mm->p[r].y);
|
||||
--r;
|
||||
}
|
||||
|
||||
if (l <= r) {
|
||||
if (IsWindows() && wf) {
|
||||
wf(mm, l, r);
|
||||
|
@ -164,19 +196,38 @@ int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
|||
unsigned i;
|
||||
assert(y >= x);
|
||||
assert(AreMemoryIntervalsOk(mm));
|
||||
|
||||
i = FindMemoryInterval(mm, x);
|
||||
|
||||
// try to extend the righthand side of the lefthand entry
|
||||
// we can't do that if we're tracking independent handles
|
||||
// we can't do that if it's a file map with a small size!
|
||||
if (i && x == mm->p[i - 1].y + 1 && h == mm->p[i - 1].h &&
|
||||
prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags) {
|
||||
prot == mm->p[i - 1].prot && flags == mm->p[i - 1].flags &&
|
||||
mm->p[i - 1].size ==
|
||||
(size_t)(mm->p[i - 1].y - mm->p[i - 1].x) * FRAMESIZE + FRAMESIZE) {
|
||||
mm->p[i - 1].size += (size_t)(y - mm->p[i - 1].y) * FRAMESIZE;
|
||||
mm->p[i - 1].y = y;
|
||||
// if we filled the hole then merge the two mappings
|
||||
if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h &&
|
||||
prot == mm->p[i].prot && flags == mm->p[i].flags) {
|
||||
mm->p[i - 1].y = mm->p[i].y;
|
||||
mm->p[i - 1].size += mm->p[i].size;
|
||||
RemoveMemoryIntervals(mm, i, 1);
|
||||
}
|
||||
} else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h &&
|
||||
prot == mm->p[i].prot && flags == mm->p[i].flags) {
|
||||
}
|
||||
|
||||
// try to extend the lefthand side of the righthand entry
|
||||
// we can't do that if we're creating a smaller file map!
|
||||
else if (i < mm->i && y + 1 == mm->p[i].x && h == mm->p[i].h &&
|
||||
prot == mm->p[i].prot && flags == mm->p[i].flags &&
|
||||
size == (size_t)(y - x) * FRAMESIZE + FRAMESIZE) {
|
||||
mm->p[i].size += (size_t)(mm->p[i].x - x) * FRAMESIZE;
|
||||
mm->p[i].x = x;
|
||||
} else {
|
||||
}
|
||||
|
||||
// otherwise, create a new entry and memmove the items
|
||||
else {
|
||||
if (CreateMemoryInterval(mm, i) == -1) return -1;
|
||||
mm->p[i].x = x;
|
||||
mm->p[i].y = y;
|
||||
|
|
|
@ -34,10 +34,10 @@ struct MemoryInterval {
|
|||
int x;
|
||||
int y;
|
||||
long h;
|
||||
long size;
|
||||
int prot;
|
||||
int flags;
|
||||
long offset;
|
||||
long size;
|
||||
bool iscow;
|
||||
bool readonlyfile;
|
||||
};
|
||||
|
@ -90,25 +90,27 @@ forceinline pureconst bool IsShadowFrame(int x) {
|
|||
}
|
||||
|
||||
forceinline pureconst bool IsKernelFrame(int x) {
|
||||
return (int)(GetStaticStackAddr(0) >> 16) <= x &&
|
||||
x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >>
|
||||
16);
|
||||
intptr_t stack = (intptr_t)GetStaticStackAddr(0);
|
||||
return (int)(stack >> 16) <= x &&
|
||||
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
||||
}
|
||||
|
||||
forceinline pureconst bool IsStaticStackFrame(int x) {
|
||||
return (int)(GetStaticStackAddr(0) >> 16) <= x &&
|
||||
x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >>
|
||||
16);
|
||||
intptr_t stack = (intptr_t)GetStaticStackAddr(0);
|
||||
return (int)(stack >> 16) <= x &&
|
||||
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
||||
}
|
||||
|
||||
forceinline pureconst bool IsStackFrame(int x) {
|
||||
return (int)(GetStackAddr(0) >> 16) <= x &&
|
||||
x <= (int)((GetStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16);
|
||||
intptr_t stack = (intptr_t)GetStackAddr(0);
|
||||
return (int)(stack >> 16) <= x &&
|
||||
x <= (int)((stack + (GetStackSize() - FRAMESIZE)) >> 16);
|
||||
}
|
||||
|
||||
forceinline pureconst bool IsSigAltStackFrame(int x) {
|
||||
return (int)(GetStackAddr(0) >> 16) <= x &&
|
||||
x <= (int)((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16);
|
||||
intptr_t stack = (intptr_t)GetStackAddr(0);
|
||||
return (int)(stack >> 16) <= x &&
|
||||
x <= (int)((stack + (SIGSTKSZ - FRAMESIZE)) >> 16);
|
||||
}
|
||||
|
||||
forceinline pureconst bool IsOldStackFrame(int x) {
|
||||
|
|
|
@ -16,16 +16,22 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/likely.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -36,89 +42,123 @@
|
|||
#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16)
|
||||
#define FRAME(x) ((int)((intptr_t)(x) >> 16))
|
||||
|
||||
static noasan int Munmap(void *v, size_t n) {
|
||||
char poison, *p = v;
|
||||
static noasan int Munmap(char *, size_t);
|
||||
|
||||
static noasan void MunmapShadow(char *p, size_t n) {
|
||||
intptr_t a, b, x, y;
|
||||
KERNTRACE("MunmapShadow(%p, %'zu)", p, n);
|
||||
a = ((intptr_t)p >> 3) + 0x7fff8000;
|
||||
b = a + (n >> 3);
|
||||
if (IsMemtracked(FRAME(a), FRAME(b - 1))) {
|
||||
x = ROUNDUP(a, FRAMESIZE);
|
||||
y = ROUNDDOWN(b, FRAMESIZE);
|
||||
if (0 && x < y) {
|
||||
// delete shadowspace if unmapping ≥512kb. in practice it has
|
||||
// to be >1mb since we can only unmap it if it's aligned, and
|
||||
// as such we poison the edges if there are any.
|
||||
__repstosb((void *)a, kAsanUnmapped, x - a);
|
||||
Munmap((void *)x, y - x);
|
||||
__repstosb((void *)y, kAsanUnmapped, b - y);
|
||||
} else {
|
||||
// otherwise just poison and assume reuse
|
||||
__repstosb((void *)a, kAsanUnmapped, b - a);
|
||||
}
|
||||
} else {
|
||||
STRACE("unshadow(%.12p, %p) EFAULT", a, b - a);
|
||||
}
|
||||
}
|
||||
|
||||
// our api supports doing things like munmap(0, 0x7fffffffffff) but some
|
||||
// platforms (e.g. openbsd) require that we know the specific intervals
|
||||
// or else it returns EINVAL. so we munmap a piecewise.
|
||||
static noasan void MunmapImpl(char *p, size_t n) {
|
||||
char *q;
|
||||
size_t m;
|
||||
intptr_t a, b, c;
|
||||
int i, l, r, rc, beg, end;
|
||||
KERNTRACE("MunmapImpl(%p, %'zu)", p, n);
|
||||
l = FRAME(p);
|
||||
r = FRAME(p + n - 1);
|
||||
i = FindMemoryInterval(&_mmi, l);
|
||||
for (; i < _mmi.i && r >= _mmi.p[i].x; ++i) {
|
||||
if (l >= _mmi.p[i].x && r <= _mmi.p[i].y) {
|
||||
|
||||
// it's contained within the entry
|
||||
beg = l;
|
||||
end = r;
|
||||
} else if (l <= _mmi.p[i].x && r >= _mmi.p[i].x) {
|
||||
|
||||
// it overlaps with the lefthand side of the entry
|
||||
beg = _mmi.p[i].x;
|
||||
end = MIN(r, _mmi.p[i].y);
|
||||
} else if (l <= _mmi.p[i].y && r >= _mmi.p[i].y) {
|
||||
|
||||
// it overlaps with the righthand side of the entry
|
||||
beg = MAX(_mmi.p[i].x, l);
|
||||
end = _mmi.p[i].y;
|
||||
} else {
|
||||
// shouldn't be possible
|
||||
assert(!"binary search panic");
|
||||
continue;
|
||||
}
|
||||
// openbsd even requires that if we mapped, for instance a 5 byte
|
||||
// file, that we be sure to call munmap(file, 5). let's abstract!
|
||||
a = ADDR(beg);
|
||||
b = ADDR(end) + FRAMESIZE;
|
||||
c = ADDR(_mmi.p[i].x) + _mmi.p[i].size;
|
||||
q = (char *)a;
|
||||
m = MIN(b, c) - a;
|
||||
if (!IsWindows()) {
|
||||
rc = sys_munmap(q, m);
|
||||
assert(!rc);
|
||||
} else {
|
||||
// Handled by UntrackMemoryIntervals() on Windows
|
||||
}
|
||||
if (IsAsan() && !OverlapsShadowSpace(p, n)) {
|
||||
MunmapShadow(q, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static noasan int Munmap(char *p, size_t n) {
|
||||
unsigned i;
|
||||
char poison;
|
||||
intptr_t a, b, x, y;
|
||||
assert(!__vforked);
|
||||
|
||||
if (UNLIKELY(!n)) {
|
||||
STRACE("munmap(%.12p, %'zu) %s (n=0)", p, n);
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (n=0)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (UNLIKELY(!IsLegalSize(n))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (n isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (UNLIKELY(!IsLegalPointer(p))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p+(n-1) isn't 48-bit)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("munmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, n);
|
||||
return einval();
|
||||
}
|
||||
|
||||
if (!IsMemtracked(FRAME(p), FRAME(p + (n - 1)))) {
|
||||
STRACE("munmap(%.12p, %'zu) EFAULT (interval not tracked)", p, n);
|
||||
return efault();
|
||||
}
|
||||
|
||||
if (UntrackMemoryIntervals(p, n) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (IsWindows()) {
|
||||
return 0; // UntrackMemoryIntervals does it for NT
|
||||
}
|
||||
|
||||
if (sys_munmap(p, n) == -1) {
|
||||
return -1; // ouch
|
||||
}
|
||||
|
||||
if (IsAsan() && !OverlapsShadowSpace(p, n)) {
|
||||
a = ((intptr_t)p >> 3) + 0x7fff8000;
|
||||
b = a + (n >> 3);
|
||||
if (IsMemtracked(FRAME(a), FRAME(b - 1))) {
|
||||
x = ROUNDUP(a, FRAMESIZE);
|
||||
y = ROUNDDOWN(b, FRAMESIZE);
|
||||
if (x < y) {
|
||||
// delete shadowspace if unmapping ≥512kb
|
||||
__repstosb((void *)a, kAsanUnmapped, x - a);
|
||||
Munmap((void *)x, y - x);
|
||||
__repstosb((void *)y, kAsanUnmapped, b - y);
|
||||
} else {
|
||||
// otherwise just poison and assume reuse
|
||||
__repstosb((void *)a, kAsanUnmapped, b - a);
|
||||
}
|
||||
} else {
|
||||
STRACE("unshadow(%.12p, %p) EFAULT", a, b - a);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
MunmapImpl(p, n);
|
||||
return UntrackMemoryIntervals(p, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases memory pages.
|
||||
*
|
||||
* This function may be used to punch holes in existing mappings, but
|
||||
* your mileage may vary on Windows.
|
||||
*
|
||||
* @param p is a pointer within any memory mapped region the process
|
||||
* has permission to control, such as address ranges returned by
|
||||
* mmap(), the program image itself, etc.
|
||||
* @param n is the number of bytes to be unmapped, and needs to be a
|
||||
* multiple of FRAMESIZE for anonymous mappings, because windows
|
||||
* and for files size needs to be perfect to the byte bc openbsd
|
||||
* @param p is the beginning of the memory region to unmap
|
||||
* @param n is the number of bytes to be unmapped
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raises EINVAL if `n == 0`
|
||||
* @raises EINVAL if `n` isn't 48-bit
|
||||
* @raises EINVAL if `p+(n-1)` isn't 48-bit
|
||||
* @raises EINVAL if `p` isn't 65536-byte aligned
|
||||
*/
|
||||
noasan int munmap(void *p, size_t n) {
|
||||
int rc;
|
||||
|
|
|
@ -147,8 +147,8 @@ textstartup void __printargs(const char *prologue) {
|
|||
struct pollfd pfds[128];
|
||||
} u;
|
||||
|
||||
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED);
|
||||
--__ftrace;
|
||||
--__strace;
|
||||
e = errno;
|
||||
|
||||
PRINT("");
|
||||
|
@ -547,7 +547,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
}
|
||||
|
||||
PRINT("");
|
||||
__atomic_fetch_add(&__strace, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_add(&g_ftrace, 1, __ATOMIC_RELAXED);
|
||||
++__strace;
|
||||
++__ftrace;
|
||||
errno = e;
|
||||
}
|
||||
|
|
|
@ -41,10 +41,16 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
|
|||
for (i = 0; i < mm->i; ++i) {
|
||||
frames = mm->p[i].y + 1 - mm->p[i].x;
|
||||
maptally += frames;
|
||||
kprintf("%012lx-%012lx %s %'*ldx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1),
|
||||
kprintf("%08x-%08x %s %'*ldx%s", mm->p[i].x, mm->p[i].y,
|
||||
DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
|
||||
DescribeFrame(mm->p[i].x));
|
||||
if (i + 1 < _mmi.i) {
|
||||
if (mm->p[i].iscow) kprintf(" cow");
|
||||
if (mm->p[i].readonlyfile) kprintf(" readonlyfile");
|
||||
if (mm->p[i].size !=
|
||||
(size_t)(mm->p[i].y - mm->p[i].x) * FRAMESIZE + FRAMESIZE) {
|
||||
kprintf(" size=%'zu", mm->p[i].size);
|
||||
}
|
||||
if (i + 1 < mm->i) {
|
||||
frames = mm->p[i + 1].x - mm->p[i].y - 1;
|
||||
if (frames && IsNoteworthyHole(i, mm)) {
|
||||
gaptally += frames;
|
||||
|
|
|
@ -14,10 +14,12 @@ extern char **__argv; /* CRT */
|
|||
extern char **__envp; /* CRT */
|
||||
extern unsigned long *__auxv; /* CRT */
|
||||
extern intptr_t __oldstack; /* CRT */
|
||||
extern uint64_t __nosync; /* SYS */
|
||||
extern _Atomic(int) __ftrace; /* SYS */
|
||||
extern _Atomic(int) __strace; /* SYS */
|
||||
extern char *program_invocation_name; /* RII */
|
||||
extern char *program_invocation_short_name; /* RII */
|
||||
extern int g_ftrace; /* CRT */
|
||||
extern uint64_t g_syscount; /* RII */
|
||||
extern uint64_t __syscount; /* RII */
|
||||
extern const uint64_t kStartTsc; /* RII */
|
||||
extern const char kTmpPath[]; /* RII */
|
||||
extern const char kNtSystemDirectory[]; /* RII */
|
||||
|
@ -38,7 +40,6 @@ extern unsigned char *__relo_start[]; /* αpε */
|
|||
extern unsigned char *__relo_end[]; /* αpε */
|
||||
extern uint8_t __zip_start[]; /* αpε */
|
||||
extern uint8_t __zip_end[]; /* αpε */
|
||||
extern bool ftrace_enabled;
|
||||
extern size_t __virtualmax;
|
||||
extern bool __isworker;
|
||||
|
||||
|
|
|
@ -58,24 +58,25 @@ $(LIBC_RUNTIME_A).pkg: \
|
|||
$(LIBC_RUNTIME_A_OBJS) \
|
||||
$(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
# we can't use asan and ubsan because:
|
||||
# asan and ubsan can be function traced
|
||||
# we can't use function tracing because:
|
||||
# this is the function tracing runtime
|
||||
o/$(MODE)/libc/runtime/ftracer.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-mno-fentry \
|
||||
-ffreestanding \
|
||||
-fno-sanitize=all
|
||||
|
||||
o/$(MODE)/libc/runtime/fork-nt.o \
|
||||
o/$(MODE)/libc/runtime/printmemoryintervals.o \
|
||||
o/$(MODE)/libc/runtime/arememoryintervalsok.o \
|
||||
o/$(MODE)/libc/runtime/directmap.o \
|
||||
o/$(MODE)/libc/runtime/directmapnt.o \
|
||||
o/$(MODE)/libc/runtime/findmemoryinterval.o \
|
||||
o/$(MODE)/libc/runtime/ftrace.greg.o \
|
||||
o/$(MODE)/libc/runtime/sys_mprotect.greg.o \
|
||||
o/$(MODE)/libc/runtime/ftracer.o \
|
||||
o/$(MODE)/libc/runtime/ezmap.o \
|
||||
o/$(MODE)/libc/runtime/getdosargv.o \
|
||||
o/$(MODE)/libc/runtime/getdosenviron.o \
|
||||
o/$(MODE)/libc/runtime/hook.greg.o \
|
||||
o/$(MODE)/libc/runtime/morph.greg.o \
|
||||
o/$(MODE)/libc/runtime/mprotect.greg.o \
|
||||
o/$(MODE)/libc/runtime/mprotect-nt.greg.o \
|
||||
o/$(MODE)/libc/runtime/ismemtracked.greg.o \
|
||||
o/$(MODE)/libc/runtime/isheap.o \
|
||||
o/$(MODE)/libc/runtime/memtracknt.o \
|
||||
o/$(MODE)/libc/runtime/memtrack.greg.o \
|
||||
o/$(MODE)/libc/runtime/metalprintf.greg.o \
|
||||
|
|
|
@ -61,8 +61,9 @@ extern char ape_stack_align[] __attribute__((__weak__));
|
|||
/**
|
||||
* Returns address of bottom of stack.
|
||||
*/
|
||||
#define GetStackAddr(ADDEND) \
|
||||
((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + (ADDEND))
|
||||
#define GetStackAddr(ADDEND) \
|
||||
((void *)((((intptr_t)__builtin_frame_address(0) - 1) & -GetStackSize()) + \
|
||||
(ADDEND)))
|
||||
|
||||
/**
|
||||
* Returns preferred bottom address of stack.
|
||||
|
@ -78,7 +79,7 @@ extern char ape_stack_align[] __attribute__((__weak__));
|
|||
} else { \
|
||||
vAddr = 0x10000000; \
|
||||
} \
|
||||
vAddr; \
|
||||
(void *)vAddr; \
|
||||
})
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/atomic.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/stack.h"
|
||||
#include "libc/str/str.h"
|
||||
|
@ -26,16 +29,23 @@
|
|||
|
||||
static char stacklog[1024];
|
||||
|
||||
static size_t NullLength(const char *s) {
|
||||
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(16)));
|
||||
size_t n;
|
||||
xmm_t v, z = {0};
|
||||
unsigned m, k = (uintptr_t)s & 15;
|
||||
const xmm_t *p = (const xmm_t *)((uintptr_t)s & -16);
|
||||
m = (__builtin_ia32_pmovmskb128(*p == z) ^ 0xffff) >> k << k;
|
||||
while (!m) m = __builtin_ia32_pmovmskb128(*++p == z) ^ 0xffff;
|
||||
n = (const char *)p + __builtin_ctzl(m) - s;
|
||||
return n;
|
||||
size_t GetStackUsage(char *s, size_t n) {
|
||||
// RHEL5 MAP_GROWSDOWN seems to only grow to 68kb :'(
|
||||
// So we count non-zero bytes down from the top
|
||||
// First clear 64 bytes is considered the end
|
||||
long *p;
|
||||
size_t got;
|
||||
p = (long *)(s + n);
|
||||
got = 0;
|
||||
for (;;) {
|
||||
p -= 8;
|
||||
if (p[0] | p[1] | p[2] | p[3] | p[4] | p[5] | p[6] | p[7]) {
|
||||
++got;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return got * 8 * sizeof(long);
|
||||
}
|
||||
|
||||
static textexit void LogStackUse(void) {
|
||||
|
@ -43,10 +53,8 @@ static textexit void LogStackUse(void) {
|
|||
bool quote;
|
||||
char *p, *q;
|
||||
size_t n, usage;
|
||||
const char *stack;
|
||||
usage = GetStackUsage(GetStackAddr(0), GetStackSize());
|
||||
fd = open(stacklog, O_APPEND | O_CREAT | O_WRONLY, 0644);
|
||||
stack = (char *)GetStackAddr(0);
|
||||
usage = GetStackSize() - (NullLength(stack + PAGESIZE) + PAGESIZE);
|
||||
p = FormatUint64(stacklog, usage);
|
||||
for (i = 0; i < __argc; ++i) {
|
||||
n = strlen(__argv[i]);
|
||||
|
|
|
@ -16,17 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
||||
int UntrackMemoryIntervals(void *addr, size_t size) {
|
||||
int a, b;
|
||||
assert(size > 0);
|
||||
a = ROUNDDOWN((intptr_t)addr, FRAMESIZE) >> 16;
|
||||
b = ROUNDDOWN((intptr_t)addr + size - 1, FRAMESIZE) >> 16;
|
||||
if (SupportsWindows()) {
|
||||
return ReleaseMemoryIntervals(&_mmi, a, b, ReleaseMemoryNt);
|
||||
} else {
|
||||
return ReleaseMemoryIntervals(&_mmi, a, b, 0);
|
||||
}
|
||||
return ReleaseMemoryIntervals(&_mmi, a, b,
|
||||
SupportsWindows() ? ReleaseMemoryNt : 0);
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
_mmi.p = _mmi.s;
|
||||
_mmi.n = ARRAYLEN(_mmi.s);
|
||||
argsize = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE);
|
||||
stackaddr = GetStaticStackAddr(0);
|
||||
stackaddr = (intptr_t)GetStaticStackAddr(0);
|
||||
stacksize = GetStackSize();
|
||||
allocsize = argsize + stacksize;
|
||||
allocaddr = stackaddr - argsize;
|
||||
|
|
|
@ -1,150 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/refcount.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/nt2sysv.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/events.h"
|
||||
#include "libc/nt/ipc.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/sock/ntstdin.internal.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Pollable Standard Input for the New Technology.
|
||||
*/
|
||||
|
||||
static textwindows uint32_t StdinWorkerThread(void *arg) {
|
||||
char buf[512];
|
||||
bool32 ok = true;
|
||||
uint32_t i, rc, got, err, wrote;
|
||||
struct NtStdinWorker w, *wp = arg;
|
||||
NTTRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader,
|
||||
wp->writer, wp->consumer, getpid(), gettid());
|
||||
_spunlock(&wp->sync);
|
||||
w = *wp;
|
||||
do {
|
||||
ok = ReadFile(w.reader, buf, sizeof(buf), &got, 0);
|
||||
/* When writing to a non-blocking, byte-mode pipe handle with
|
||||
insufficient buffer space, WriteFile returns TRUE with
|
||||
*lpNumberOfBytesWritten < nNumberOfBytesToWrite.
|
||||
──Quoth MSDN WriteFile() */
|
||||
for (i = 0; ok && i < got; i += wrote) {
|
||||
ok = WriteFile(w.writer, buf + i, got - i, &wrote, 0);
|
||||
}
|
||||
} while (ok && got);
|
||||
err = GetLastError();
|
||||
if (!ok) {
|
||||
if (err == kNtErrorHandleEof || err == kNtErrorBrokenPipe ||
|
||||
err == kNtErrorNoData) {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
NTTRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %u", w.reader, w.writer,
|
||||
w.consumer, err);
|
||||
return !ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts read-only file descriptor to pollable named pipe.
|
||||
*
|
||||
* @param fd is open file descriptor to convert
|
||||
* @return new object on success, or 0 w/ errno
|
||||
*/
|
||||
textwindows struct NtStdinWorker *NewNtStdinWorker(int fd) {
|
||||
struct NtStdinWorker *w;
|
||||
NTTRACE("LaunchNtStdinWorker(%d) pid %d tid %d", fd, getpid(), gettid());
|
||||
assert(!g_fds.p[fd].worker);
|
||||
assert(__isfdopen(fd));
|
||||
if (!(w = calloc(1, sizeof(struct NtStdinWorker)))) return 0;
|
||||
w->refs = 1;
|
||||
w->sync = 1;
|
||||
w->reader = g_fds.p[fd].handle;
|
||||
if ((w->consumer = CreateNamedPipe(
|
||||
CreatePipeName(w->name),
|
||||
kNtPipeAccessInbound | kNtFileFlagOverlapped,
|
||||
kNtPipeTypeByte | kNtPipeReadmodeByte | kNtPipeRejectRemoteClients,
|
||||
1, 512, 512, 0, 0)) != -1) {
|
||||
if ((w->writer = CreateFile(w->name, kNtGenericWrite, 0, 0, kNtOpenExisting,
|
||||
kNtFileFlagOverlapped, 0)) != -1) {
|
||||
if ((w->worker = CreateThread(0, 0, NT2SYSV(StdinWorkerThread), w, 0,
|
||||
&w->tid)) != -1) {
|
||||
_spinlock(&w->sync);
|
||||
g_fds.p[fd].handle = w->consumer;
|
||||
g_fds.p[fd].worker = w;
|
||||
return w;
|
||||
}
|
||||
CloseHandle(w->writer);
|
||||
}
|
||||
CloseHandle(w->consumer);
|
||||
}
|
||||
free(w);
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* References stdin worker on the New Technology.
|
||||
* @param w is non-null worker object
|
||||
* @return worker object for new fd
|
||||
*/
|
||||
textwindows struct NtStdinWorker *RefNtStdinWorker(struct NtStdinWorker *w) {
|
||||
_incref(&w->refs);
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dereferences stdin worker on the New Technology.
|
||||
* @param w is non-null worker object
|
||||
* @return true if ok otherwise false
|
||||
*/
|
||||
textwindows bool UnrefNtStdinWorker(struct NtStdinWorker *w) {
|
||||
bool ok = true;
|
||||
if (_decref(&w->refs)) return true;
|
||||
if (!CloseHandle(w->consumer)) ok = false;
|
||||
if (!CloseHandle(w->writer)) ok = false;
|
||||
if (!CloseHandle(w->reader)) ok = false;
|
||||
if (!CloseHandle(w->worker)) ok = false;
|
||||
free(w);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs post fork for stdin workers on the New Technology.
|
||||
*/
|
||||
textwindows void ForkNtStdinWorker(void) {
|
||||
for (int i = 0; i < g_fds.n; ++i) {
|
||||
if (g_fds.p[i].kind && g_fds.p[i].worker) {
|
||||
g_fds.p[i].handle = g_fds.p[i].worker->reader;
|
||||
free(g_fds.p[i].worker);
|
||||
g_fds.p[i].worker = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct NtStdinWorker { /* non-inherited */
|
||||
volatile char sync; /* spin sync start */
|
||||
int refs; /* reference count */
|
||||
uint32_t tid; /* of the worker */
|
||||
int64_t reader; /* the real handle */
|
||||
int64_t writer; /* for the worker */
|
||||
int64_t worker; /* thread handle */
|
||||
int64_t consumer; /* same as Fd::handle */
|
||||
char16_t name[64]; /* for named pipe */
|
||||
};
|
||||
|
||||
struct NtStdinWorker *NewNtStdinWorker(int) hidden;
|
||||
struct NtStdinWorker *RefNtStdinWorker(struct NtStdinWorker *) hidden;
|
||||
bool UnrefNtStdinWorker(struct NtStdinWorker *) hidden;
|
||||
void ForkNtStdinWorker(void) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_SOCK_NTSTDIN_INTERNAL_H_ */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue