Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'nolibc-20250526-for-6.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc

Pull nolibc updates from Thomas Weißschuh:

- New supported architectures: m68k, SPARC (32 and 64 bit)

- Compatibility with kselftest_harness.h

- A more robust mechanism to include all of nolibc from each header

- Split existing features into new headers to simplify adoption

- Compatibility with UBSAN and it is used in the testsuite

- Many small new features focussing on usage in kselftests

* tag 'nolibc-20250526-for-6.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc: (83 commits)
selftests: harness: Stop using setjmp()/longjmp()
selftests: harness: Add "variant" and "self" to test metadata
selftests: harness: Add teardown callback to test metadata
selftests: harness: Move teardown conditional into test metadata
selftests: harness: Don't set setup_completed for fixtureless tests
selftests: harness: Implement test timeouts through pidfd
selftests: harness: Remove dependency on libatomic
selftests: harness: Remove inline qualifier for wrappers
selftests: harness: Mark functions without prototypes static
selftests: harness: Ignore unused variant argument warning
selftests: harness: Use C89 comment style
selftests: harness: Add kselftest harness selftest
selftests/nolibc: drop include guards around standard headers
tools/nolibc: move NULL and offsetof() to sys/stddef.h
tools/nolibc: move uname() and friends to sys/utsname.h
tools/nolibc: move makedev() and friends to sys/sysmacros.h
tools/nolibc: move getrlimit() and friends to sys/resource.h
tools/nolibc: move reboot() to sys/reboot.h
tools/nolibc: move prctl() to sys/prctl.h
tools/nolibc: move mount() to sys/mount.h
...

+2632 -665
+1
MAINTAINERS
··· 21971 21971 F: include/uapi/linux/seccomp.h 21972 21972 F: kernel/seccomp.c 21973 21973 F: tools/testing/selftests/kselftest_harness.h 21974 + F: tools/testing/selftests/kselftest_harness/ 21974 21975 F: tools/testing/selftests/seccomp/* 21975 21976 K: \bsecure_computing 21976 21977 K: \bTIF_SECCOMP\b
+33 -1
tools/include/nolibc/Makefile
··· 30 30 crt.h \ 31 31 ctype.h \ 32 32 dirent.h \ 33 + elf.h \ 33 34 errno.h \ 35 + fcntl.h \ 36 + getopt.h \ 34 37 limits.h \ 38 + math.h \ 35 39 nolibc.h \ 40 + poll.h \ 41 + sched.h \ 36 42 signal.h \ 37 43 stackprotector.h \ 38 44 std.h \ 39 45 stdarg.h \ 40 46 stdbool.h \ 47 + stddef.h \ 41 48 stdint.h \ 42 49 stdlib.h \ 43 50 string.h \ 44 51 sys.h \ 52 + sys/auxv.h \ 53 + sys/ioctl.h \ 54 + sys/mman.h \ 55 + sys/mount.h \ 56 + sys/prctl.h \ 57 + sys/random.h \ 58 + sys/reboot.h \ 59 + sys/resource.h \ 60 + sys/stat.h \ 61 + sys/syscall.h \ 62 + sys/sysmacros.h \ 63 + sys/time.h \ 64 + sys/timerfd.h \ 65 + sys/types.h \ 66 + sys/utsname.h \ 67 + sys/wait.h \ 45 68 time.h \ 46 69 types.h \ 47 70 unistd.h \ ··· 95 72 headers: 96 73 $(Q)mkdir -p $(OUTPUT)sysroot 97 74 $(Q)mkdir -p $(OUTPUT)sysroot/include 98 - $(Q)cp $(all_files) $(OUTPUT)sysroot/include/ 75 + $(Q)cp --parents $(all_files) $(OUTPUT)sysroot/include/ 99 76 $(Q)if [ "$(ARCH)" = "x86" ]; then \ 100 77 sed -e \ 101 78 's,^#ifndef _NOLIBC_ARCH_X86_64_H,#if !defined(_NOLIBC_ARCH_X86_64_H) \&\& defined(__x86_64__),' \ ··· 113 90 headers_standalone: headers 114 91 $(Q)$(MAKE) -C $(srctree) headers 115 92 $(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)sysroot 93 + 94 + # GCC uses "s390", clang "systemz" 95 + CLANG_CROSS_FLAGS := $(subst --target=s390-linux,--target=systemz-linux,$(CLANG_CROSS_FLAGS)) 96 + 97 + headers_check: headers_standalone 98 + for header in $(filter-out crt.h std.h,$(all_files)); do \ 99 + $(CC) $(CLANG_CROSS_FLAGS) -Wall -Werror -nostdinc -fsyntax-only -x c /dev/null \ 100 + -I$(or $(objtree),$(srctree))/usr/include -include $$header -include $$header || exit 1; \ 101 + done 116 102 117 103 clean: 118 104 $(call QUIET_CLEAN, nolibc) rm -rf "$(OUTPUT)sysroot"
-1
tools/include/nolibc/arch-aarch64.h
··· 146 146 { 147 147 __asm__ volatile ( 148 148 "mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */ 149 - "and sp, x0, -16\n" /* sp must be 16-byte aligned in the callee */ 150 149 "bl _start_c\n" /* transfer to c runtime */ 151 150 ); 152 151 __nolibc_entrypoint_epilogue();
-2
tools/include/nolibc/arch-arm.h
··· 189 189 { 190 190 __asm__ volatile ( 191 191 "mov r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */ 192 - "and ip, r0, #-8\n" /* sp must be 8-byte aligned in the callee */ 193 - "mov sp, ip\n" 194 192 "bl _start_c\n" /* transfer to c runtime */ 195 193 ); 196 194 __nolibc_entrypoint_epilogue();
-2
tools/include/nolibc/arch-i386.h
··· 167 167 __asm__ volatile ( 168 168 "xor %ebp, %ebp\n" /* zero the stack frame */ 169 169 "mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */ 170 - "add $12, %esp\n" /* avoid over-estimating after the 'and' & 'sub' below */ 171 - "and $-16, %esp\n" /* the %esp must be 16-byte aligned on 'call' */ 172 170 "sub $12, %esp\n" /* sub 12 to keep it aligned after the push %eax */ 173 171 "push %eax\n" /* push arg1 on stack to support plain stack modes too */ 174 172 "call _start_c\n" /* transfer to c runtime */
-7
tools/include/nolibc/arch-loongarch.h
··· 142 142 _arg1; \ 143 143 }) 144 144 145 - #if __loongarch_grlen == 32 146 - #define LONG_BSTRINS "bstrins.w" 147 - #else /* __loongarch_grlen == 64 */ 148 - #define LONG_BSTRINS "bstrins.d" 149 - #endif 150 - 151 145 /* startup code */ 152 146 void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) 153 147 { 154 148 __asm__ volatile ( 155 149 "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ 156 - LONG_BSTRINS " $sp, $zero, 3, 0\n" /* $sp must be 16-byte aligned */ 157 150 "bl _start_c\n" /* transfer to c runtime */ 158 151 ); 159 152 __nolibc_entrypoint_epilogue();
+141
tools/include/nolibc/arch-m68k.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * m68k specific definitions for NOLIBC 4 + * Copyright (C) 2025 Daniel Palmer<daniel@thingy.jp> 5 + * 6 + * Roughly based on one or more of the other arch files. 7 + * 8 + */ 9 + 10 + #ifndef _NOLIBC_ARCH_M68K_H 11 + #define _NOLIBC_ARCH_M68K_H 12 + 13 + #include "compiler.h" 14 + #include "crt.h" 15 + 16 + #define _NOLIBC_SYSCALL_CLOBBERLIST "memory" 17 + 18 + #define my_syscall0(num) \ 19 + ({ \ 20 + register long _num __asm__ ("d0") = (num); \ 21 + \ 22 + __asm__ volatile ( \ 23 + "trap #0\n" \ 24 + : "+r"(_num) \ 25 + : "r"(_num) \ 26 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 27 + ); \ 28 + _num; \ 29 + }) 30 + 31 + #define my_syscall1(num, arg1) \ 32 + ({ \ 33 + register long _num __asm__ ("d0") = (num); \ 34 + register long _arg1 __asm__ ("d1") = (long)(arg1); \ 35 + \ 36 + __asm__ volatile ( \ 37 + "trap #0\n" \ 38 + : "+r"(_num) \ 39 + : "r"(_arg1) \ 40 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 41 + ); \ 42 + _num; \ 43 + }) 44 + 45 + #define my_syscall2(num, arg1, arg2) \ 46 + ({ \ 47 + register long _num __asm__ ("d0") = (num); \ 48 + register long _arg1 __asm__ ("d1") = (long)(arg1); \ 49 + register long _arg2 __asm__ ("d2") = (long)(arg2); \ 50 + \ 51 + __asm__ volatile ( \ 52 + "trap #0\n" \ 53 + : "+r"(_num) \ 54 + : "r"(_arg1), "r"(_arg2) \ 55 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 56 + ); \ 57 + _num; \ 58 + }) 59 + 60 + #define my_syscall3(num, arg1, arg2, arg3) \ 61 + ({ \ 62 + register long _num __asm__ ("d0") = (num); \ 63 + register long _arg1 __asm__ ("d1") = (long)(arg1); \ 64 + register long _arg2 __asm__ ("d2") = (long)(arg2); \ 65 + register long _arg3 __asm__ ("d3") = (long)(arg3); \ 66 + \ 67 + __asm__ volatile ( \ 68 + "trap #0\n" \ 69 + : "+r"(_num) \ 70 + : "r"(_arg1), "r"(_arg2), "r"(_arg3) \ 71 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 72 + ); \ 73 + _num; \ 74 + }) 75 + 76 + #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 77 + ({ \ 78 + register long _num __asm__ ("d0") = (num); \ 79 + register long _arg1 __asm__ ("d1") = (long)(arg1); \ 80 + register long _arg2 __asm__ ("d2") = (long)(arg2); \ 81 + register long _arg3 __asm__ ("d3") = (long)(arg3); \ 82 + register long _arg4 __asm__ ("d4") = (long)(arg4); \ 83 + \ 84 + __asm__ volatile ( \ 85 + "trap #0\n" \ 86 + : "+r" (_num) \ 87 + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ 88 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 89 + ); \ 90 + _num; \ 91 + }) 92 + 93 + #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 94 + ({ \ 95 + register long _num __asm__ ("d0") = (num); \ 96 + register long _arg1 __asm__ ("d1") = (long)(arg1); \ 97 + register long _arg2 __asm__ ("d2") = (long)(arg2); \ 98 + register long _arg3 __asm__ ("d3") = (long)(arg3); \ 99 + register long _arg4 __asm__ ("d4") = (long)(arg4); \ 100 + register long _arg5 __asm__ ("d5") = (long)(arg5); \ 101 + \ 102 + __asm__ volatile ( \ 103 + "trap #0\n" \ 104 + : "+r" (_num) \ 105 + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \ 106 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 107 + ); \ 108 + _num; \ 109 + }) 110 + 111 + #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 112 + ({ \ 113 + register long _num __asm__ ("d0") = (num); \ 114 + register long _arg1 __asm__ ("d1") = (long)(arg1); \ 115 + register long _arg2 __asm__ ("d2") = (long)(arg2); \ 116 + register long _arg3 __asm__ ("d3") = (long)(arg3); \ 117 + register long _arg4 __asm__ ("d4") = (long)(arg4); \ 118 + register long _arg5 __asm__ ("d5") = (long)(arg5); \ 119 + register long _arg6 __asm__ ("a0") = (long)(arg6); \ 120 + \ 121 + __asm__ volatile ( \ 122 + "trap #0\n" \ 123 + : "+r" (_num) \ 124 + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 125 + "r"(_arg6) \ 126 + : _NOLIBC_SYSCALL_CLOBBERLIST \ 127 + ); \ 128 + _num; \ 129 + }) 130 + 131 + void _start(void); 132 + void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) 133 + { 134 + __asm__ volatile ( 135 + "movel %sp, %sp@-\n" 136 + "jsr _start_c\n" 137 + ); 138 + __nolibc_entrypoint_epilogue(); 139 + } 140 + 141 + #endif /* _NOLIBC_ARCH_M68K_H */
-2
tools/include/nolibc/arch-powerpc.h
··· 201 201 202 202 __asm__ volatile ( 203 203 "mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */ 204 - "clrrdi 1, 1, 4\n" /* align the stack to 16 bytes */ 205 204 "li 0, 0\n" /* zero the frame pointer */ 206 205 "stdu 1, -32(1)\n" /* the initial stack frame */ 207 206 "bl _start_c\n" /* transfer to c runtime */ ··· 208 209 #else 209 210 __asm__ volatile ( 210 211 "mr 3, 1\n" /* save stack pointer to r3, as arg1 of _start_c */ 211 - "clrrwi 1, 1, 4\n" /* align the stack to 16 bytes */ 212 212 "li 0, 0\n" /* zero the frame pointer */ 213 213 "stwu 1, -16(1)\n" /* the initial stack frame */ 214 214 "bl _start_c\n" /* transfer to c runtime */
-1
tools/include/nolibc/arch-riscv.h
··· 148 148 "lla gp, __global_pointer$\n" 149 149 ".option pop\n" 150 150 "mv a0, sp\n" /* save stack pointer to a0, as arg1 of _start_c */ 151 - "andi sp, a0, -16\n" /* sp must be 16-byte aligned */ 152 151 "call _start_c\n" /* transfer to c runtime */ 153 152 ); 154 153 __nolibc_entrypoint_epilogue();
+191
tools/include/nolibc/arch-sparc.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * SPARC (32bit and 64bit) specific definitions for NOLIBC 4 + * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net> 5 + */ 6 + 7 + #ifndef _NOLIBC_ARCH_SPARC_H 8 + #define _NOLIBC_ARCH_SPARC_H 9 + 10 + #include <linux/unistd.h> 11 + 12 + #include "compiler.h" 13 + #include "crt.h" 14 + 15 + /* 16 + * Syscalls for SPARC: 17 + * - registers are native word size 18 + * - syscall number is passed in g1 19 + * - arguments are in o0-o5 20 + * - the system call is performed by calling a trap instruction 21 + * - syscall return value is in o0 22 + * - syscall error flag is in the carry bit of the processor status register 23 + */ 24 + 25 + #ifdef __arch64__ 26 + 27 + #define _NOLIBC_SYSCALL "t 0x6d\n" \ 28 + "bcs,a %%xcc, 1f\n" \ 29 + "sub %%g0, %%o0, %%o0\n" \ 30 + "1:\n" 31 + 32 + #else 33 + 34 + #define _NOLIBC_SYSCALL "t 0x10\n" \ 35 + "bcs,a 1f\n" \ 36 + "sub %%g0, %%o0, %%o0\n" \ 37 + "1:\n" 38 + 39 + #endif /* __arch64__ */ 40 + 41 + #define my_syscall0(num) \ 42 + ({ \ 43 + register long _num __asm__ ("g1") = (num); \ 44 + register long _arg1 __asm__ ("o0"); \ 45 + \ 46 + __asm__ volatile ( \ 47 + _NOLIBC_SYSCALL \ 48 + : "+r"(_arg1) \ 49 + : "r"(_num) \ 50 + : "memory", "cc" \ 51 + ); \ 52 + _arg1; \ 53 + }) 54 + 55 + #define my_syscall1(num, arg1) \ 56 + ({ \ 57 + register long _num __asm__ ("g1") = (num); \ 58 + register long _arg1 __asm__ ("o0") = (long)(arg1); \ 59 + \ 60 + __asm__ volatile ( \ 61 + _NOLIBC_SYSCALL \ 62 + : "+r"(_arg1) \ 63 + : "r"(_num) \ 64 + : "memory", "cc" \ 65 + ); \ 66 + _arg1; \ 67 + }) 68 + 69 + #define my_syscall2(num, arg1, arg2) \ 70 + ({ \ 71 + register long _num __asm__ ("g1") = (num); \ 72 + register long _arg1 __asm__ ("o0") = (long)(arg1); \ 73 + register long _arg2 __asm__ ("o1") = (long)(arg2); \ 74 + \ 75 + __asm__ volatile ( \ 76 + _NOLIBC_SYSCALL \ 77 + : "+r"(_arg1) \ 78 + : "r"(_arg2), "r"(_num) \ 79 + : "memory", "cc" \ 80 + ); \ 81 + _arg1; \ 82 + }) 83 + 84 + #define my_syscall3(num, arg1, arg2, arg3) \ 85 + ({ \ 86 + register long _num __asm__ ("g1") = (num); \ 87 + register long _arg1 __asm__ ("o0") = (long)(arg1); \ 88 + register long _arg2 __asm__ ("o1") = (long)(arg2); \ 89 + register long _arg3 __asm__ ("o2") = (long)(arg3); \ 90 + \ 91 + __asm__ volatile ( \ 92 + _NOLIBC_SYSCALL \ 93 + : "+r"(_arg1) \ 94 + : "r"(_arg2), "r"(_arg3), "r"(_num) \ 95 + : "memory", "cc" \ 96 + ); \ 97 + _arg1; \ 98 + }) 99 + 100 + #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 101 + ({ \ 102 + register long _num __asm__ ("g1") = (num); \ 103 + register long _arg1 __asm__ ("o0") = (long)(arg1); \ 104 + register long _arg2 __asm__ ("o1") = (long)(arg2); \ 105 + register long _arg3 __asm__ ("o2") = (long)(arg3); \ 106 + register long _arg4 __asm__ ("o3") = (long)(arg4); \ 107 + \ 108 + __asm__ volatile ( \ 109 + _NOLIBC_SYSCALL \ 110 + : "+r"(_arg1) \ 111 + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_num) \ 112 + : "memory", "cc" \ 113 + ); \ 114 + _arg1; \ 115 + }) 116 + 117 + #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 118 + ({ \ 119 + register long _num __asm__ ("g1") = (num); \ 120 + register long _arg1 __asm__ ("o0") = (long)(arg1); \ 121 + register long _arg2 __asm__ ("o1") = (long)(arg2); \ 122 + register long _arg3 __asm__ ("o2") = (long)(arg3); \ 123 + register long _arg4 __asm__ ("o3") = (long)(arg4); \ 124 + register long _arg5 __asm__ ("o4") = (long)(arg5); \ 125 + \ 126 + __asm__ volatile ( \ 127 + _NOLIBC_SYSCALL \ 128 + : "+r"(_arg1) \ 129 + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_num) \ 130 + : "memory", "cc" \ 131 + ); \ 132 + _arg1; \ 133 + }) 134 + 135 + #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 136 + ({ \ 137 + register long _num __asm__ ("g1") = (num); \ 138 + register long _arg1 __asm__ ("o0") = (long)(arg1); \ 139 + register long _arg2 __asm__ ("o1") = (long)(arg2); \ 140 + register long _arg3 __asm__ ("o2") = (long)(arg3); \ 141 + register long _arg4 __asm__ ("o3") = (long)(arg4); \ 142 + register long _arg5 __asm__ ("o4") = (long)(arg5); \ 143 + register long _arg6 __asm__ ("o5") = (long)(arg6); \ 144 + \ 145 + __asm__ volatile ( \ 146 + _NOLIBC_SYSCALL \ 147 + : "+r"(_arg1) \ 148 + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 149 + "r"(_num) \ 150 + : "memory", "cc" \ 151 + ); \ 152 + _arg1; \ 153 + }) 154 + 155 + /* startup code */ 156 + void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) 157 + { 158 + __asm__ volatile ( 159 + /* 160 + * Save argc pointer to o0, as arg1 of _start_c. 161 + * Account for the window save area, which is 16 registers wide. 162 + */ 163 + #ifdef __arch64__ 164 + "add %sp, 128 + 2047, %o0\n" /* on sparc64 / v9 the stack is offset by 2047 */ 165 + #else 166 + "add %sp, 64, %o0\n" 167 + #endif 168 + "b,a _start_c\n" /* transfer to c runtime */ 169 + ); 170 + __nolibc_entrypoint_epilogue(); 171 + } 172 + 173 + static pid_t getpid(void); 174 + 175 + static __attribute__((unused)) 176 + pid_t sys_fork(void) 177 + { 178 + pid_t parent, ret; 179 + 180 + parent = getpid(); 181 + ret = my_syscall0(__NR_fork); 182 + 183 + /* The syscall returns the parent pid in the child instead of 0 */ 184 + if (ret == parent) 185 + return 0; 186 + else 187 + return ret; 188 + } 189 + #define sys_fork sys_fork 190 + 191 + #endif /* _NOLIBC_ARCH_SPARC_H */
-1
tools/include/nolibc/arch-x86_64.h
··· 166 166 __asm__ volatile ( 167 167 "xor %ebp, %ebp\n" /* zero the stack frame */ 168 168 "mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */ 169 - "and $-16, %rsp\n" /* %rsp must be 16-byte aligned before call */ 170 169 "call _start_c\n" /* transfer to c runtime */ 171 170 "hlt\n" /* ensure it does not return */ 172 171 );
+4
tools/include/nolibc/arch.h
··· 33 33 #include "arch-s390.h" 34 34 #elif defined(__loongarch__) 35 35 #include "arch-loongarch.h" 36 + #elif defined(__sparc__) 37 + #include "arch-sparc.h" 38 + #elif defined(__m68k__) 39 + #include "arch-m68k.h" 36 40 #else 37 41 #error Unsupported Architecture 38 42 #endif
+9
tools/include/nolibc/compiler.h
··· 12 12 # define __nolibc_has_attribute(attr) 0 13 13 #endif 14 14 15 + #if defined(__has_feature) 16 + # define __nolibc_has_feature(feature) __has_feature(feature) 17 + #else 18 + # define __nolibc_has_feature(feature) 0 19 + #endif 20 + 21 + #define __nolibc_aligned(alignment) __attribute__((aligned(alignment))) 22 + #define __nolibc_aligned_as(type) __nolibc_aligned(__alignof__(type)) 23 + 15 24 #if __nolibc_has_attribute(naked) 16 25 # define __nolibc_entrypoint __attribute__((naked)) 17 26 # define __nolibc_entrypoint_epilogue()
+5
tools/include/nolibc/crt.h
··· 7 7 #ifndef _NOLIBC_CRT_H 8 8 #define _NOLIBC_CRT_H 9 9 10 + #include "compiler.h" 11 + 10 12 char **environ __attribute__((weak)); 11 13 const unsigned long *_auxv __attribute__((weak)); 12 14 ··· 27 25 28 26 void _start_c(long *sp); 29 27 __attribute__((weak,used)) 28 + #if __nolibc_has_feature(undefined_behavior_sanitizer) 29 + __attribute__((no_sanitize("function"))) 30 + #endif 30 31 void _start_c(long *sp) 31 32 { 32 33 long argc;
+3 -3
tools/include/nolibc/ctype.h
··· 4 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_CTYPE_H 8 11 #define _NOLIBC_CTYPE_H 9 12 ··· 98 95 { 99 96 return isgraph(c) && !isalnum(c); 100 97 } 101 - 102 - /* make sure to include all global symbols */ 103 - #include "nolibc.h" 104 98 105 99 #endif /* _NOLIBC_CTYPE_H */
+6 -4
tools/include/nolibc/dirent.h
··· 4 4 * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_DIRENT_H 8 11 #define _NOLIBC_DIRENT_H 9 12 13 + #include "compiler.h" 10 14 #include "stdint.h" 11 15 #include "types.h" 16 + #include "fcntl.h" 12 17 13 18 #include <linux/limits.h> 14 19 ··· 63 58 static __attribute__((unused)) 64 59 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) 65 60 { 66 - char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1]; 61 + char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1] __nolibc_aligned_as(struct linux_dirent64); 67 62 struct linux_dirent64 *ldir = (void *)buf; 68 63 intptr_t i = (intptr_t)dirp; 69 64 int fd, ret; ··· 96 91 *result = entry; 97 92 return 0; 98 93 } 99 - 100 - /* make sure to include all global symbols */ 101 - #include "nolibc.h" 102 94 103 95 #endif /* _NOLIBC_DIRENT_H */
+15
tools/include/nolibc/elf.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Shim elf.h header for NOLIBC. 4 + * Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_ELF_H 11 + #define _NOLIBC_SYS_ELF_H 12 + 13 + #include <linux/elf.h> 14 + 15 + #endif /* _NOLIBC_SYS_ELF_H */
+3 -3
tools/include/nolibc/errno.h
··· 4 4 * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_ERRNO_H 8 11 #define _NOLIBC_ERRNO_H 9 12 ··· 24 21 * because they all correspond to the highest addressable memory page. 25 22 */ 26 23 #define MAX_ERRNO 4095 27 - 28 - /* make sure to include all global symbols */ 29 - #include "nolibc.h" 30 24 31 25 #endif /* _NOLIBC_ERRNO_H */
+69
tools/include/nolibc/fcntl.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * fcntl definition for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 10 + #ifndef _NOLIBC_FCNTL_H 11 + #define _NOLIBC_FCNTL_H 12 + 13 + #include "arch.h" 14 + #include "types.h" 15 + #include "sys.h" 16 + 17 + /* 18 + * int openat(int dirfd, const char *path, int flags[, mode_t mode]); 19 + */ 20 + 21 + static __attribute__((unused)) 22 + int sys_openat(int dirfd, const char *path, int flags, mode_t mode) 23 + { 24 + return my_syscall4(__NR_openat, dirfd, path, flags, mode); 25 + } 26 + 27 + static __attribute__((unused)) 28 + int openat(int dirfd, const char *path, int flags, ...) 29 + { 30 + mode_t mode = 0; 31 + 32 + if (flags & O_CREAT) { 33 + va_list args; 34 + 35 + va_start(args, flags); 36 + mode = va_arg(args, mode_t); 37 + va_end(args); 38 + } 39 + 40 + return __sysret(sys_openat(dirfd, path, flags, mode)); 41 + } 42 + 43 + /* 44 + * int open(const char *path, int flags[, mode_t mode]); 45 + */ 46 + 47 + static __attribute__((unused)) 48 + int sys_open(const char *path, int flags, mode_t mode) 49 + { 50 + return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); 51 + } 52 + 53 + static __attribute__((unused)) 54 + int open(const char *path, int flags, ...) 55 + { 56 + mode_t mode = 0; 57 + 58 + if (flags & O_CREAT) { 59 + va_list args; 60 + 61 + va_start(args, flags); 62 + mode = va_arg(args, mode_t); 63 + va_end(args); 64 + } 65 + 66 + return __sysret(sys_open(path, flags, mode)); 67 + } 68 + 69 + #endif /* _NOLIBC_FCNTL_H */
+101
tools/include/nolibc/getopt.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * getopt function definitions for NOLIBC, adapted from musl libc 4 + * Copyright (C) 2005-2020 Rich Felker, et al. 5 + * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net> 6 + */ 7 + 8 + /* make sure to include all global symbols */ 9 + #include "nolibc.h" 10 + 11 + #ifndef _NOLIBC_GETOPT_H 12 + #define _NOLIBC_GETOPT_H 13 + 14 + struct FILE; 15 + static struct FILE *const stderr; 16 + static int fprintf(struct FILE *stream, const char *fmt, ...); 17 + 18 + __attribute__((weak,unused,section(".data.nolibc_getopt"))) 19 + char *optarg; 20 + 21 + __attribute__((weak,unused,section(".data.nolibc_getopt"))) 22 + int optind = 1, opterr = 1, optopt; 23 + 24 + static __attribute__((unused)) 25 + int getopt(int argc, char * const argv[], const char *optstring) 26 + { 27 + static int __optpos; 28 + int i; 29 + char c, d; 30 + char *optchar; 31 + 32 + if (!optind) { 33 + __optpos = 0; 34 + optind = 1; 35 + } 36 + 37 + if (optind >= argc || !argv[optind]) 38 + return -1; 39 + 40 + if (argv[optind][0] != '-') { 41 + if (optstring[0] == '-') { 42 + optarg = argv[optind++]; 43 + return 1; 44 + } 45 + return -1; 46 + } 47 + 48 + if (!argv[optind][1]) 49 + return -1; 50 + 51 + if (argv[optind][1] == '-' && !argv[optind][2]) 52 + return optind++, -1; 53 + 54 + if (!__optpos) 55 + __optpos++; 56 + c = argv[optind][__optpos]; 57 + optchar = argv[optind] + __optpos; 58 + __optpos++; 59 + 60 + if (!argv[optind][__optpos]) { 61 + optind++; 62 + __optpos = 0; 63 + } 64 + 65 + if (optstring[0] == '-' || optstring[0] == '+') 66 + optstring++; 67 + 68 + i = 0; 69 + d = 0; 70 + do { 71 + d = optstring[i++]; 72 + } while (d && d != c); 73 + 74 + if (d != c || c == ':') { 75 + optopt = c; 76 + if (optstring[0] != ':' && opterr) 77 + fprintf(stderr, "%s: unrecognized option: %c\n", argv[0], *optchar); 78 + return '?'; 79 + } 80 + if (optstring[i] == ':') { 81 + optarg = 0; 82 + if (optstring[i + 1] != ':' || __optpos) { 83 + optarg = argv[optind++]; 84 + if (__optpos) 85 + optarg += __optpos; 86 + __optpos = 0; 87 + } 88 + if (optind > argc) { 89 + optopt = c; 90 + if (optstring[0] == ':') 91 + return ':'; 92 + if (opterr) 93 + fprintf(stderr, "%s: option requires argument: %c\n", 94 + argv[0], *optchar); 95 + return '?'; 96 + } 97 + } 98 + return c; 99 + } 100 + 101 + #endif /* _NOLIBC_GETOPT_H */
+31
tools/include/nolibc/math.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * math definitions for NOLIBC 4 + * Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_MATH_H 11 + #define _NOLIBC_SYS_MATH_H 12 + 13 + static __inline__ 14 + double fabs(double x) 15 + { 16 + return x >= 0 ? x : -x; 17 + } 18 + 19 + static __inline__ 20 + float fabsf(float x) 21 + { 22 + return x >= 0 ? x : -x; 23 + } 24 + 25 + static __inline__ 26 + long double fabsl(long double x) 27 + { 28 + return x >= 0 ? x : -x; 29 + } 30 + 31 + #endif /* _NOLIBC_SYS_MATH_H */
+21
tools/include/nolibc/nolibc.h
··· 96 96 #include "arch.h" 97 97 #include "types.h" 98 98 #include "sys.h" 99 + #include "sys/auxv.h" 100 + #include "sys/ioctl.h" 101 + #include "sys/mman.h" 102 + #include "sys/mount.h" 103 + #include "sys/prctl.h" 104 + #include "sys/random.h" 105 + #include "sys/reboot.h" 106 + #include "sys/resource.h" 107 + #include "sys/stat.h" 108 + #include "sys/syscall.h" 109 + #include "sys/sysmacros.h" 110 + #include "sys/time.h" 111 + #include "sys/timerfd.h" 112 + #include "sys/utsname.h" 113 + #include "sys/wait.h" 99 114 #include "ctype.h" 115 + #include "elf.h" 116 + #include "sched.h" 100 117 #include "signal.h" 101 118 #include "unistd.h" 102 119 #include "stdio.h" ··· 122 105 #include "time.h" 123 106 #include "stackprotector.h" 124 107 #include "dirent.h" 108 + #include "fcntl.h" 109 + #include "getopt.h" 110 + #include "poll.h" 111 + #include "math.h" 125 112 126 113 /* Used by programs to avoid std includes */ 127 114 #define NOLIBC
+55
tools/include/nolibc/poll.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * poll definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 10 + #ifndef _NOLIBC_POLL_H 11 + #define _NOLIBC_POLL_H 12 + 13 + #include "arch.h" 14 + #include "sys.h" 15 + 16 + #include <linux/poll.h> 17 + #include <linux/time.h> 18 + 19 + /* 20 + * int poll(struct pollfd *fds, int nfds, int timeout); 21 + */ 22 + 23 + static __attribute__((unused)) 24 + int sys_poll(struct pollfd *fds, int nfds, int timeout) 25 + { 26 + #if defined(__NR_ppoll) 27 + struct timespec t; 28 + 29 + if (timeout >= 0) { 30 + t.tv_sec = timeout / 1000; 31 + t.tv_nsec = (timeout % 1000) * 1000000; 32 + } 33 + return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0); 34 + #elif defined(__NR_ppoll_time64) 35 + struct __kernel_timespec t; 36 + 37 + if (timeout >= 0) { 38 + t.tv_sec = timeout / 1000; 39 + t.tv_nsec = (timeout % 1000) * 1000000; 40 + } 41 + return my_syscall5(__NR_ppoll_time64, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0); 42 + #elif defined(__NR_poll) 43 + return my_syscall3(__NR_poll, fds, nfds, timeout); 44 + #else 45 + return __nolibc_enosys(__func__, fds, nfds, timeout); 46 + #endif 47 + } 48 + 49 + static __attribute__((unused)) 50 + int poll(struct pollfd *fds, int nfds, int timeout) 51 + { 52 + return __sysret(sys_poll(fds, nfds, timeout)); 53 + } 54 + 55 + #endif /* _NOLIBC_POLL_H */
+50
tools/include/nolibc/sched.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * sched function definitions for NOLIBC 4 + * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 10 + #ifndef _NOLIBC_SCHED_H 11 + #define _NOLIBC_SCHED_H 12 + 13 + #include "sys.h" 14 + 15 + #include <linux/sched.h> 16 + 17 + /* 18 + * int setns(int fd, int nstype); 19 + */ 20 + 21 + static __attribute__((unused)) 22 + int sys_setns(int fd, int nstype) 23 + { 24 + return my_syscall2(__NR_setns, fd, nstype); 25 + } 26 + 27 + static __attribute__((unused)) 28 + int setns(int fd, int nstype) 29 + { 30 + return __sysret(sys_setns(fd, nstype)); 31 + } 32 + 33 + 34 + /* 35 + * int unshare(int flags); 36 + */ 37 + 38 + static __attribute__((unused)) 39 + int sys_unshare(int flags) 40 + { 41 + return my_syscall1(__NR_unshare, flags); 42 + } 43 + 44 + static __attribute__((unused)) 45 + int unshare(int flags) 46 + { 47 + return __sysret(sys_unshare(flags)); 48 + } 49 + 50 + #endif /* _NOLIBC_SCHED_H */
+3 -3
tools/include/nolibc/signal.h
··· 4 4 * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_SIGNAL_H 8 11 #define _NOLIBC_SIGNAL_H 9 12 ··· 22 19 { 23 20 return sys_kill(sys_getpid(), signal); 24 21 } 25 - 26 - /* make sure to include all global symbols */ 27 - #include "nolibc.h" 28 22 29 23 #endif /* _NOLIBC_SIGNAL_H */
+1 -5
tools/include/nolibc/std.h
··· 13 13 * syscall-specific stuff, as this file is expected to be included very early. 14 14 */ 15 15 16 - /* note: may already be defined */ 17 - #ifndef NULL 18 - #define NULL ((void *)0) 19 - #endif 20 - 21 16 #include "stdint.h" 17 + #include "stddef.h" 22 18 23 19 /* those are commonly provided by sys/types.h */ 24 20 typedef unsigned int dev_t;
+24
tools/include/nolibc/stddef.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Stddef definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 10 + #ifndef _NOLIBC_STDDEF_H 11 + #define _NOLIBC_STDDEF_H 12 + 13 + #include "stdint.h" 14 + 15 + /* note: may already be defined */ 16 + #ifndef NULL 17 + #define NULL ((void *)0) 18 + #endif 19 + 20 + #ifndef offsetof 21 + #define offsetof(TYPE, FIELD) ((size_t) &((TYPE *)0)->FIELD) 22 + #endif 23 + 24 + #endif /* _NOLIBC_STDDEF_H */
+2 -2
tools/include/nolibc/stdint.h
··· 39 39 typedef int64_t int_fast64_t; 40 40 typedef uint64_t uint_fast64_t; 41 41 42 - typedef int64_t intmax_t; 43 - typedef uint64_t uintmax_t; 42 + typedef __INTMAX_TYPE__ intmax_t; 43 + typedef __UINTMAX_TYPE__ uintmax_t; 44 44 45 45 /* limits of integral types */ 46 46
+157 -10
tools/include/nolibc/stdio.h
··· 4 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_STDIO_H 8 11 #define _NOLIBC_STDIO_H 9 12 10 13 #include "std.h" 11 14 #include "arch.h" 12 15 #include "errno.h" 16 + #include "fcntl.h" 13 17 #include "types.h" 14 18 #include "sys.h" 15 19 #include "stdarg.h" 16 20 #include "stdlib.h" 17 21 #include "string.h" 18 22 #include "compiler.h" 23 + 24 + static const char *strerror(int errnum); 19 25 20 26 #ifndef EOF 21 27 #define EOF (-1) ··· 54 48 return NULL; 55 49 } 56 50 return (FILE*)(intptr_t)~fd; 51 + } 52 + 53 + static __attribute__((unused)) 54 + FILE *fopen(const char *pathname, const char *mode) 55 + { 56 + int flags, fd; 57 + 58 + switch (*mode) { 59 + case 'r': 60 + flags = O_RDONLY; 61 + break; 62 + case 'w': 63 + flags = O_WRONLY | O_CREAT | O_TRUNC; 64 + break; 65 + case 'a': 66 + flags = O_WRONLY | O_CREAT | O_APPEND; 67 + break; 68 + default: 69 + SET_ERRNO(EINVAL); return NULL; 70 + } 71 + 72 + if (mode[1] == '+') 73 + flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; 74 + 75 + fd = open(pathname, flags, 0666); 76 + return fdopen(fd, mode); 57 77 } 58 78 59 79 /* provides the fd of stream. */ ··· 240 208 } 241 209 242 210 243 - /* minimal vfprintf(). It supports the following formats: 211 + /* minimal printf(). It supports the following formats: 244 212 * - %[l*]{d,u,c,x,p} 245 213 * - %s 246 214 * - unknown modifiers are ignored. 247 215 */ 248 - static __attribute__((unused, format(printf, 2, 0))) 249 - int vfprintf(FILE *stream, const char *fmt, va_list args) 216 + typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size); 217 + 218 + static __attribute__((unused, format(printf, 4, 0))) 219 + int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args) 250 220 { 251 221 char escape, lpref, c; 252 222 unsigned long long v; 253 - unsigned int written; 254 - size_t len, ofs; 223 + unsigned int written, width; 224 + size_t len, ofs, w; 255 225 char tmpbuf[21]; 256 226 const char *outstr; 257 227 258 228 written = ofs = escape = lpref = 0; 259 229 while (1) { 260 230 c = fmt[ofs++]; 231 + width = 0; 261 232 262 233 if (escape) { 263 234 /* we're in an escape sequence, ofs == 1 */ 264 235 escape = 0; 236 + 237 + /* width */ 238 + while (c >= '0' && c <= '9') { 239 + width *= 10; 240 + width += c - '0'; 241 + 242 + c = fmt[ofs++]; 243 + } 244 + 265 245 if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') { 266 246 char *out = tmpbuf; 267 247 ··· 321 277 if (!outstr) 322 278 outstr="(null)"; 323 279 } 280 + #ifndef NOLIBC_IGNORE_ERRNO 281 + else if (c == 'm') { 282 + outstr = strerror(errno); 283 + } 284 + #endif /* NOLIBC_IGNORE_ERRNO */ 324 285 else if (c == '%') { 325 286 /* queue it verbatim */ 326 287 continue; ··· 335 286 if (c == 'l') { 336 287 /* long format prefix, maintain the escape */ 337 288 lpref++; 289 + } else if (c == 'j') { 290 + lpref = 2; 338 291 } 339 292 escape = 1; 340 293 goto do_escape; ··· 353 302 outstr = fmt; 354 303 len = ofs - 1; 355 304 flush_str: 356 - if (_fwrite(outstr, len, stream) != 0) 357 - break; 305 + if (n) { 306 + w = len < n ? len : n; 307 + n -= w; 308 + while (width-- > w) { 309 + if (cb(state, " ", 1) != 0) 310 + break; 311 + written += 1; 312 + } 313 + if (cb(state, outstr, w) != 0) 314 + break; 315 + } 358 316 359 317 written += len; 360 318 do_escape: ··· 377 317 /* literal char, just queue it */ 378 318 } 379 319 return written; 320 + } 321 + 322 + static int __nolibc_fprintf_cb(intptr_t state, const char *buf, size_t size) 323 + { 324 + return _fwrite(buf, size, (FILE *)state); 325 + } 326 + 327 + static __attribute__((unused, format(printf, 2, 0))) 328 + int vfprintf(FILE *stream, const char *fmt, va_list args) 329 + { 330 + return __nolibc_printf(__nolibc_fprintf_cb, (intptr_t)stream, SIZE_MAX, fmt, args); 380 331 } 381 332 382 333 static __attribute__((unused, format(printf, 1, 0))) ··· 417 346 va_start(args, fmt); 418 347 ret = vfprintf(stdout, fmt, args); 419 348 va_end(args); 349 + return ret; 350 + } 351 + 352 + static __attribute__((unused, format(printf, 2, 0))) 353 + int vdprintf(int fd, const char *fmt, va_list args) 354 + { 355 + FILE *stream; 356 + 357 + stream = fdopen(fd, NULL); 358 + if (!stream) 359 + return -1; 360 + /* Technically 'stream' is leaked, but as it's only a wrapper around 'fd' that is fine */ 361 + return vfprintf(stream, fmt, args); 362 + } 363 + 364 + static __attribute__((unused, format(printf, 2, 3))) 365 + int dprintf(int fd, const char *fmt, ...) 366 + { 367 + va_list args; 368 + int ret; 369 + 370 + va_start(args, fmt); 371 + ret = vdprintf(fd, fmt, args); 372 + va_end(args); 373 + 374 + return ret; 375 + } 376 + 377 + static int __nolibc_sprintf_cb(intptr_t _state, const char *buf, size_t size) 378 + { 379 + char **state = (char **)_state; 380 + 381 + memcpy(*state, buf, size); 382 + *state += size; 383 + return 0; 384 + } 385 + 386 + static __attribute__((unused, format(printf, 3, 0))) 387 + int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) 388 + { 389 + char *state = buf; 390 + int ret; 391 + 392 + ret = __nolibc_printf(__nolibc_sprintf_cb, (intptr_t)&state, size, fmt, args); 393 + if (ret < 0) 394 + return ret; 395 + buf[(size_t)ret < size ? (size_t)ret : size - 1] = '\0'; 396 + return ret; 397 + } 398 + 399 + static __attribute__((unused, format(printf, 3, 4))) 400 + int snprintf(char *buf, size_t size, const char *fmt, ...) 401 + { 402 + va_list args; 403 + int ret; 404 + 405 + va_start(args, fmt); 406 + ret = vsnprintf(buf, size, fmt, args); 407 + va_end(args); 408 + 409 + return ret; 410 + } 411 + 412 + static __attribute__((unused, format(printf, 2, 0))) 413 + int vsprintf(char *buf, const char *fmt, va_list args) 414 + { 415 + return vsnprintf(buf, SIZE_MAX, fmt, args); 416 + } 417 + 418 + static __attribute__((unused, format(printf, 2, 3))) 419 + int sprintf(char *buf, const char *fmt, ...) 420 + { 421 + va_list args; 422 + int ret; 423 + 424 + va_start(args, fmt); 425 + ret = vsprintf(buf, fmt, args); 426 + va_end(args); 427 + 420 428 return ret; 421 429 } 422 430 ··· 634 484 635 485 return buf; 636 486 } 637 - 638 - /* make sure to include all global symbols */ 639 - #include "nolibc.h" 640 487 641 488 #endif /* _NOLIBC_STDIO_H */
+23 -31
tools/include/nolibc/stdlib.h
··· 4 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_STDLIB_H 8 11 #define _NOLIBC_STDLIB_H 9 12 ··· 31 28 /* 32 29 * As much as possible, please keep functions alphabetically sorted. 33 30 */ 31 + 32 + static __inline__ 33 + int abs(int j) 34 + { 35 + return j >= 0 ? j : -j; 36 + } 37 + 38 + static __inline__ 39 + long labs(long j) 40 + { 41 + return j >= 0 ? j : -j; 42 + } 43 + 44 + static __inline__ 45 + long long llabs(long long j) 46 + { 47 + return j >= 0 ? j : -j; 48 + } 34 49 35 50 /* must be exported, as it's used by libgcc for various divide functions */ 36 51 void abort(void); ··· 121 100 } 122 101 } 123 102 return NULL; 124 - } 125 - 126 - static __attribute__((unused)) 127 - unsigned long getauxval(unsigned long type) 128 - { 129 - const unsigned long *auxv = _auxv; 130 - unsigned long ret; 131 - 132 - if (!auxv) 133 - return 0; 134 - 135 - while (1) { 136 - if (!auxv[0] && !auxv[1]) { 137 - ret = 0; 138 - break; 139 - } 140 - 141 - if (auxv[0] == type) { 142 - ret = auxv[1]; 143 - break; 144 - } 145 - 146 - auxv += 2; 147 - } 148 - 149 - return ret; 150 103 } 151 104 152 105 static __attribute__((unused)) ··· 270 275 int len = 0; 271 276 272 277 if (in < 0) { 273 - in = -in; 278 + in = -(unsigned long)in; 274 279 *(ptr++) = '-'; 275 280 len++; 276 281 } ··· 406 411 int len = 0; 407 412 408 413 if (in < 0) { 409 - in = -in; 414 + in = -(uint64_t)in; 410 415 *(ptr++) = '-'; 411 416 len++; 412 417 } ··· 542 547 { 543 548 return __strtox(nptr, endptr, base, 0, UINTMAX_MAX); 544 549 } 545 - 546 - /* make sure to include all global symbols */ 547 - #include "nolibc.h" 548 550 549 551 #endif /* _NOLIBC_STDLIB_H */
+38 -2
tools/include/nolibc/string.h
··· 4 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_STRING_H 8 11 #define _NOLIBC_STRING_H 9 12 ··· 292 289 return (char *)ret; 293 290 } 294 291 295 - /* make sure to include all global symbols */ 296 - #include "nolibc.h" 292 + static __attribute__((unused)) 293 + char *strstr(const char *haystack, const char *needle) 294 + { 295 + size_t len_haystack, len_needle; 296 + 297 + len_needle = strlen(needle); 298 + if (!len_needle) 299 + return NULL; 300 + 301 + len_haystack = strlen(haystack); 302 + while (len_haystack >= len_needle) { 303 + if (!memcmp(haystack, needle, len_needle)) 304 + return (char *)haystack; 305 + haystack++; 306 + len_haystack--; 307 + } 308 + 309 + return NULL; 310 + } 311 + 312 + static __attribute__((unused)) 313 + int tolower(int c) 314 + { 315 + if (c >= 'A' && c <= 'Z') 316 + return c - 'A' + 'a'; 317 + return c; 318 + } 319 + 320 + static __attribute__((unused)) 321 + int toupper(int c) 322 + { 323 + if (c >= 'a' && c <= 'z') 324 + return c - 'a' + 'A'; 325 + return c; 326 + } 297 327 298 328 #endif /* _NOLIBC_STRING_H */
+28 -399
tools/include/nolibc/sys.h
··· 4 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_SYS_H 8 11 #define _NOLIBC_SYS_H 9 12 ··· 23 20 #include <linux/auxvec.h> 24 21 #include <linux/fcntl.h> /* for O_* and AT_* */ 25 22 #include <linux/stat.h> /* for statx() */ 26 - #include <linux/prctl.h> 27 - #include <linux/resource.h> 28 - #include <linux/utsname.h> 29 23 30 - #include "arch.h" 31 24 #include "errno.h" 32 25 #include "stdarg.h" 33 26 #include "types.h" ··· 300 301 } 301 302 302 303 static __attribute__((noreturn,unused)) 303 - void exit(int status) 304 + void _exit(int status) 304 305 { 305 306 sys_exit(status); 307 + } 308 + 309 + static __attribute__((noreturn,unused)) 310 + void exit(int status) 311 + { 312 + _exit(status); 306 313 } 307 314 308 315 ··· 494 489 495 490 496 491 /* 497 - * int gettimeofday(struct timeval *tv, struct timezone *tz); 498 - */ 499 - 500 - static __attribute__((unused)) 501 - int sys_gettimeofday(struct timeval *tv, struct timezone *tz) 502 - { 503 - #ifdef __NR_gettimeofday 504 - return my_syscall2(__NR_gettimeofday, tv, tz); 505 - #else 506 - return __nolibc_enosys(__func__, tv, tz); 507 - #endif 508 - } 509 - 510 - static __attribute__((unused)) 511 - int gettimeofday(struct timeval *tv, struct timezone *tz) 512 - { 513 - return __sysret(sys_gettimeofday(tv, tz)); 514 - } 515 - 516 - 517 - /* 518 492 * uid_t getuid(void); 519 493 */ 520 494 ··· 513 529 return sys_getuid(); 514 530 } 515 531 516 - 517 - /* 518 - * int ioctl(int fd, unsigned long cmd, ... arg); 519 - */ 520 - 521 - static __attribute__((unused)) 522 - long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 523 - { 524 - return my_syscall3(__NR_ioctl, fd, cmd, arg); 525 - } 526 - 527 - #define ioctl(fd, cmd, arg) __sysret(sys_ioctl(fd, cmd, (unsigned long)(arg))) 528 532 529 533 /* 530 534 * int kill(pid_t pid, int signal); ··· 669 697 return __sysret(sys_mknod(path, mode, dev)); 670 698 } 671 699 672 - #ifndef sys_mmap 673 - static __attribute__((unused)) 674 - void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, 675 - off_t offset) 676 - { 677 - int n; 678 - 679 - #if defined(__NR_mmap2) 680 - n = __NR_mmap2; 681 - offset >>= 12; 682 - #else 683 - n = __NR_mmap; 684 - #endif 685 - 686 - return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); 687 - } 688 - #endif 689 - 690 - /* Note that on Linux, MAP_FAILED is -1 so we can use the generic __sysret() 691 - * which returns -1 upon error and still satisfy user land that checks for 692 - * MAP_FAILED. 693 - */ 694 - 695 - static __attribute__((unused)) 696 - void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) 697 - { 698 - void *ret = sys_mmap(addr, length, prot, flags, fd, offset); 699 - 700 - if ((unsigned long)ret >= -4095UL) { 701 - SET_ERRNO(-(long)ret); 702 - ret = MAP_FAILED; 703 - } 704 - return ret; 705 - } 706 - 707 - static __attribute__((unused)) 708 - int sys_munmap(void *addr, size_t length) 709 - { 710 - return my_syscall2(__NR_munmap, addr, length); 711 - } 712 - 713 - static __attribute__((unused)) 714 - int munmap(void *addr, size_t length) 715 - { 716 - return __sysret(sys_munmap(addr, length)); 717 - } 718 - 719 - /* 720 - * int mount(const char *source, const char *target, 721 - * const char *fstype, unsigned long flags, 722 - * const void *data); 723 - */ 724 - static __attribute__((unused)) 725 - int sys_mount(const char *src, const char *tgt, const char *fst, 726 - unsigned long flags, const void *data) 727 - { 728 - return my_syscall5(__NR_mount, src, tgt, fst, flags, data); 729 - } 730 - 731 - static __attribute__((unused)) 732 - int mount(const char *src, const char *tgt, 733 - const char *fst, unsigned long flags, 734 - const void *data) 735 - { 736 - return __sysret(sys_mount(src, tgt, fst, flags, data)); 737 - } 738 - 739 - /* 740 - * int openat(int dirfd, const char *path, int flags[, mode_t mode]); 741 - */ 742 - 743 - static __attribute__((unused)) 744 - int sys_openat(int dirfd, const char *path, int flags, mode_t mode) 745 - { 746 - return my_syscall4(__NR_openat, dirfd, path, flags, mode); 747 - } 748 - 749 - static __attribute__((unused)) 750 - int openat(int dirfd, const char *path, int flags, ...) 751 - { 752 - mode_t mode = 0; 753 - 754 - if (flags & O_CREAT) { 755 - va_list args; 756 - 757 - va_start(args, flags); 758 - mode = va_arg(args, mode_t); 759 - va_end(args); 760 - } 761 - 762 - return __sysret(sys_openat(dirfd, path, flags, mode)); 763 - } 764 - 765 - /* 766 - * int open(const char *path, int flags[, mode_t mode]); 767 - */ 768 - 769 - static __attribute__((unused)) 770 - int sys_open(const char *path, int flags, mode_t mode) 771 - { 772 - return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); 773 - } 774 - 775 - static __attribute__((unused)) 776 - int open(const char *path, int flags, ...) 777 - { 778 - mode_t mode = 0; 779 - 780 - if (flags & O_CREAT) { 781 - va_list args; 782 - 783 - va_start(args, flags); 784 - mode = va_arg(args, mode_t); 785 - va_end(args); 786 - } 787 - 788 - return __sysret(sys_open(path, flags, mode)); 789 - } 790 - 791 700 792 701 /* 793 702 * int pipe2(int pipefd[2], int flags); ··· 695 842 696 843 697 844 /* 698 - * int prctl(int option, unsigned long arg2, unsigned long arg3, 699 - * unsigned long arg4, unsigned long arg5); 700 - */ 701 - 702 - static __attribute__((unused)) 703 - int sys_prctl(int option, unsigned long arg2, unsigned long arg3, 704 - unsigned long arg4, unsigned long arg5) 705 - { 706 - return my_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5); 707 - } 708 - 709 - static __attribute__((unused)) 710 - int prctl(int option, unsigned long arg2, unsigned long arg3, 711 - unsigned long arg4, unsigned long arg5) 712 - { 713 - return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); 714 - } 715 - 716 - 717 - /* 718 845 * int pivot_root(const char *new, const char *old); 719 846 */ 720 847 ··· 712 879 713 880 714 881 /* 715 - * int poll(struct pollfd *fds, int nfds, int timeout); 716 - */ 717 - 718 - static __attribute__((unused)) 719 - int sys_poll(struct pollfd *fds, int nfds, int timeout) 720 - { 721 - #if defined(__NR_ppoll) 722 - struct timespec t; 723 - 724 - if (timeout >= 0) { 725 - t.tv_sec = timeout / 1000; 726 - t.tv_nsec = (timeout % 1000) * 1000000; 727 - } 728 - return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0); 729 - #elif defined(__NR_poll) 730 - return my_syscall3(__NR_poll, fds, nfds, timeout); 731 - #else 732 - return __nolibc_enosys(__func__, fds, nfds, timeout); 733 - #endif 734 - } 735 - 736 - static __attribute__((unused)) 737 - int poll(struct pollfd *fds, int nfds, int timeout) 738 - { 739 - return __sysret(sys_poll(fds, nfds, timeout)); 740 - } 741 - 742 - 743 - /* 744 882 * ssize_t read(int fd, void *buf, size_t count); 745 883 */ 746 884 ··· 725 921 ssize_t read(int fd, void *buf, size_t count) 726 922 { 727 923 return __sysret(sys_read(fd, buf, count)); 728 - } 729 - 730 - 731 - /* 732 - * int reboot(int cmd); 733 - * <cmd> is among LINUX_REBOOT_CMD_* 734 - */ 735 - 736 - static __attribute__((unused)) 737 - ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) 738 - { 739 - return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); 740 - } 741 - 742 - static __attribute__((unused)) 743 - int reboot(int cmd) 744 - { 745 - return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0)); 746 - } 747 - 748 - 749 - /* 750 - * int getrlimit(int resource, struct rlimit *rlim); 751 - * int setrlimit(int resource, const struct rlimit *rlim); 752 - */ 753 - 754 - static __attribute__((unused)) 755 - int sys_prlimit64(pid_t pid, int resource, 756 - const struct rlimit64 *new_limit, struct rlimit64 *old_limit) 757 - { 758 - return my_syscall4(__NR_prlimit64, pid, resource, new_limit, old_limit); 759 - } 760 - 761 - static __attribute__((unused)) 762 - int getrlimit(int resource, struct rlimit *rlim) 763 - { 764 - struct rlimit64 rlim64; 765 - int ret; 766 - 767 - ret = __sysret(sys_prlimit64(0, resource, NULL, &rlim64)); 768 - rlim->rlim_cur = rlim64.rlim_cur; 769 - rlim->rlim_max = rlim64.rlim_max; 770 - 771 - return ret; 772 - } 773 - 774 - static __attribute__((unused)) 775 - int setrlimit(int resource, const struct rlimit *rlim) 776 - { 777 - struct rlimit64 rlim64 = { 778 - .rlim_cur = rlim->rlim_cur, 779 - .rlim_max = rlim->rlim_max, 780 - }; 781 - 782 - return __sysret(sys_prlimit64(0, resource, &rlim64, NULL)); 783 924 } 784 925 785 926 ··· 772 1023 t.tv_nsec = timeout->tv_usec * 1000; 773 1024 } 774 1025 return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); 1026 + #elif defined(__NR_pselect6_time64) 1027 + struct __kernel_timespec t; 1028 + 1029 + if (timeout) { 1030 + t.tv_sec = timeout->tv_sec; 1031 + t.tv_nsec = timeout->tv_usec * 1000; 1032 + } 1033 + return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); 775 1034 #else 776 1035 return __nolibc_enosys(__func__, nfds, rfds, wfds, efds, timeout); 777 1036 #endif ··· 808 1051 return __sysret(sys_setpgid(pid, pgid)); 809 1052 } 810 1053 1054 + /* 1055 + * pid_t setpgrp(void) 1056 + */ 1057 + 1058 + static __attribute__((unused)) 1059 + pid_t setpgrp(void) 1060 + { 1061 + return setpgid(0, 0); 1062 + } 1063 + 811 1064 812 1065 /* 813 1066 * pid_t setsid(void); ··· 833 1066 pid_t setsid(void) 834 1067 { 835 1068 return __sysret(sys_setsid()); 836 - } 837 - 838 - /* 839 - * int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf); 840 - * int stat(const char *path, struct stat *buf); 841 - */ 842 - 843 - static __attribute__((unused)) 844 - int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) 845 - { 846 - #ifdef __NR_statx 847 - return my_syscall5(__NR_statx, fd, path, flags, mask, buf); 848 - #else 849 - return __nolibc_enosys(__func__, fd, path, flags, mask, buf); 850 - #endif 851 - } 852 - 853 - static __attribute__((unused)) 854 - int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) 855 - { 856 - return __sysret(sys_statx(fd, path, flags, mask, buf)); 857 - } 858 - 859 - 860 - static __attribute__((unused)) 861 - int stat(const char *path, struct stat *buf) 862 - { 863 - struct statx statx; 864 - long ret; 865 - 866 - ret = __sysret(sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx)); 867 - if (ret == -1) 868 - return ret; 869 - 870 - buf->st_dev = ((statx.stx_dev_minor & 0xff) 871 - | (statx.stx_dev_major << 8) 872 - | ((statx.stx_dev_minor & ~0xff) << 12)); 873 - buf->st_ino = statx.stx_ino; 874 - buf->st_mode = statx.stx_mode; 875 - buf->st_nlink = statx.stx_nlink; 876 - buf->st_uid = statx.stx_uid; 877 - buf->st_gid = statx.stx_gid; 878 - buf->st_rdev = ((statx.stx_rdev_minor & 0xff) 879 - | (statx.stx_rdev_major << 8) 880 - | ((statx.stx_rdev_minor & ~0xff) << 12)); 881 - buf->st_size = statx.stx_size; 882 - buf->st_blksize = statx.stx_blksize; 883 - buf->st_blocks = statx.stx_blocks; 884 - buf->st_atim.tv_sec = statx.stx_atime.tv_sec; 885 - buf->st_atim.tv_nsec = statx.stx_atime.tv_nsec; 886 - buf->st_mtim.tv_sec = statx.stx_mtime.tv_sec; 887 - buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec; 888 - buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec; 889 - buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec; 890 - 891 - return 0; 892 1069 } 893 1070 894 1071 ··· 894 1183 895 1184 896 1185 /* 897 - * int uname(struct utsname *buf); 898 - */ 899 - 900 - struct utsname { 901 - char sysname[65]; 902 - char nodename[65]; 903 - char release[65]; 904 - char version[65]; 905 - char machine[65]; 906 - char domainname[65]; 907 - }; 908 - 909 - static __attribute__((unused)) 910 - int sys_uname(struct utsname *buf) 911 - { 912 - return my_syscall1(__NR_uname, buf); 913 - } 914 - 915 - static __attribute__((unused)) 916 - int uname(struct utsname *buf) 917 - { 918 - return __sysret(sys_uname(buf)); 919 - } 920 - 921 - 922 - /* 923 1186 * int unlink(const char *path); 924 1187 */ 925 1188 ··· 913 1228 int unlink(const char *path) 914 1229 { 915 1230 return __sysret(sys_unlink(path)); 916 - } 917 - 918 - 919 - /* 920 - * pid_t wait(int *status); 921 - * pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage); 922 - * pid_t waitpid(pid_t pid, int *status, int options); 923 - */ 924 - 925 - static __attribute__((unused)) 926 - pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) 927 - { 928 - #ifdef __NR_wait4 929 - return my_syscall4(__NR_wait4, pid, status, options, rusage); 930 - #else 931 - return __nolibc_enosys(__func__, pid, status, options, rusage); 932 - #endif 933 - } 934 - 935 - static __attribute__((unused)) 936 - pid_t wait(int *status) 937 - { 938 - return __sysret(sys_wait4(-1, status, 0, NULL)); 939 - } 940 - 941 - static __attribute__((unused)) 942 - pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) 943 - { 944 - return __sysret(sys_wait4(pid, status, options, rusage)); 945 - } 946 - 947 - 948 - static __attribute__((unused)) 949 - pid_t waitpid(pid_t pid, int *status, int options) 950 - { 951 - return __sysret(sys_wait4(pid, status, options, NULL)); 952 - } 953 - 954 - 955 - /* 956 - * int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); 957 - */ 958 - 959 - static __attribute__((unused)) 960 - int sys_waitid(int which, pid_t pid, siginfo_t *infop, int options, struct rusage *rusage) 961 - { 962 - return my_syscall5(__NR_waitid, which, pid, infop, options, rusage); 963 - } 964 - 965 - static __attribute__((unused)) 966 - int waitid(int which, pid_t pid, siginfo_t *infop, int options) 967 - { 968 - return __sysret(sys_waitid(which, pid, infop, options, NULL)); 969 1231 } 970 1232 971 1233 ··· 948 1316 { 949 1317 return __sysret(sys_memfd_create(name, flags)); 950 1318 } 951 - 952 - /* make sure to include all global symbols */ 953 - #include "nolibc.h" 954 1319 955 1320 #endif /* _NOLIBC_SYS_H */
+41
tools/include/nolibc/sys/auxv.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * auxv definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_AUXV_H 11 + #define _NOLIBC_SYS_AUXV_H 12 + 13 + #include "../crt.h" 14 + 15 + static __attribute__((unused)) 16 + unsigned long getauxval(unsigned long type) 17 + { 18 + const unsigned long *auxv = _auxv; 19 + unsigned long ret; 20 + 21 + if (!auxv) 22 + return 0; 23 + 24 + while (1) { 25 + if (!auxv[0] && !auxv[1]) { 26 + ret = 0; 27 + break; 28 + } 29 + 30 + if (auxv[0] == type) { 31 + ret = auxv[1]; 32 + break; 33 + } 34 + 35 + auxv += 2; 36 + } 37 + 38 + return ret; 39 + } 40 + 41 + #endif /* _NOLIBC_SYS_AUXV_H */
+29
tools/include/nolibc/sys/ioctl.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Ioctl definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_IOCTL_H 11 + #define _NOLIBC_SYS_IOCTL_H 12 + 13 + #include "../sys.h" 14 + 15 + #include <linux/ioctl.h> 16 + 17 + /* 18 + * int ioctl(int fd, unsigned long cmd, ... arg); 19 + */ 20 + 21 + static __attribute__((unused)) 22 + long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 23 + { 24 + return my_syscall3(__NR_ioctl, fd, cmd, arg); 25 + } 26 + 27 + #define ioctl(fd, cmd, arg) __sysret(sys_ioctl(fd, cmd, (unsigned long)(arg))) 28 + 29 + #endif /* _NOLIBC_SYS_IOCTL_H */
+82
tools/include/nolibc/sys/mman.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * mm definition for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_MMAN_H 11 + #define _NOLIBC_SYS_MMAN_H 12 + 13 + #include "../arch.h" 14 + #include "../sys.h" 15 + 16 + #ifndef sys_mmap 17 + static __attribute__((unused)) 18 + void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, 19 + off_t offset) 20 + { 21 + int n; 22 + 23 + #if defined(__NR_mmap2) 24 + n = __NR_mmap2; 25 + offset >>= 12; 26 + #else 27 + n = __NR_mmap; 28 + #endif 29 + 30 + return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); 31 + } 32 + #endif 33 + 34 + /* Note that on Linux, MAP_FAILED is -1 so we can use the generic __sysret() 35 + * which returns -1 upon error and still satisfy user land that checks for 36 + * MAP_FAILED. 37 + */ 38 + 39 + static __attribute__((unused)) 40 + void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) 41 + { 42 + void *ret = sys_mmap(addr, length, prot, flags, fd, offset); 43 + 44 + if ((unsigned long)ret >= -4095UL) { 45 + SET_ERRNO(-(long)ret); 46 + ret = MAP_FAILED; 47 + } 48 + return ret; 49 + } 50 + 51 + static __attribute__((unused)) 52 + void *sys_mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) 53 + { 54 + return (void *)my_syscall5(__NR_mremap, old_address, old_size, 55 + new_size, flags, new_address); 56 + } 57 + 58 + static __attribute__((unused)) 59 + void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) 60 + { 61 + void *ret = sys_mremap(old_address, old_size, new_size, flags, new_address); 62 + 63 + if ((unsigned long)ret >= -4095UL) { 64 + SET_ERRNO(-(long)ret); 65 + ret = MAP_FAILED; 66 + } 67 + return ret; 68 + } 69 + 70 + static __attribute__((unused)) 71 + int sys_munmap(void *addr, size_t length) 72 + { 73 + return my_syscall2(__NR_munmap, addr, length); 74 + } 75 + 76 + static __attribute__((unused)) 77 + int munmap(void *addr, size_t length) 78 + { 79 + return __sysret(sys_munmap(addr, length)); 80 + } 81 + 82 + #endif /* _NOLIBC_SYS_MMAN_H */
+37
tools/include/nolibc/sys/mount.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Mount definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_MOUNT_H 11 + #define _NOLIBC_SYS_MOUNT_H 12 + 13 + #include "../sys.h" 14 + 15 + #include <linux/mount.h> 16 + 17 + /* 18 + * int mount(const char *source, const char *target, 19 + * const char *fstype, unsigned long flags, 20 + * const void *data); 21 + */ 22 + static __attribute__((unused)) 23 + int sys_mount(const char *src, const char *tgt, const char *fst, 24 + unsigned long flags, const void *data) 25 + { 26 + return my_syscall5(__NR_mount, src, tgt, fst, flags, data); 27 + } 28 + 29 + static __attribute__((unused)) 30 + int mount(const char *src, const char *tgt, 31 + const char *fst, unsigned long flags, 32 + const void *data) 33 + { 34 + return __sysret(sys_mount(src, tgt, fst, flags, data)); 35 + } 36 + 37 + #endif /* _NOLIBC_SYS_MOUNT_H */
+36
tools/include/nolibc/sys/prctl.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Prctl definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_PRCTL_H 11 + #define _NOLIBC_SYS_PRCTL_H 12 + 13 + #include "../sys.h" 14 + 15 + #include <linux/prctl.h> 16 + 17 + /* 18 + * int prctl(int option, unsigned long arg2, unsigned long arg3, 19 + * unsigned long arg4, unsigned long arg5); 20 + */ 21 + 22 + static __attribute__((unused)) 23 + int sys_prctl(int option, unsigned long arg2, unsigned long arg3, 24 + unsigned long arg4, unsigned long arg5) 25 + { 26 + return my_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5); 27 + } 28 + 29 + static __attribute__((unused)) 30 + int prctl(int option, unsigned long arg2, unsigned long arg3, 31 + unsigned long arg4, unsigned long arg5) 32 + { 33 + return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); 34 + } 35 + 36 + #endif /* _NOLIBC_SYS_PRCTL_H */
+34
tools/include/nolibc/sys/random.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * random definitions for NOLIBC 4 + * Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_RANDOM_H 11 + #define _NOLIBC_SYS_RANDOM_H 12 + 13 + #include "../arch.h" 14 + #include "../sys.h" 15 + 16 + #include <linux/random.h> 17 + 18 + /* 19 + * ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); 20 + */ 21 + 22 + static __attribute__((unused)) 23 + ssize_t sys_getrandom(void *buf, size_t buflen, unsigned int flags) 24 + { 25 + return my_syscall3(__NR_getrandom, buf, buflen, flags); 26 + } 27 + 28 + static __attribute__((unused)) 29 + ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) 30 + { 31 + return __sysret(sys_getrandom(buf, buflen, flags)); 32 + } 33 + 34 + #endif /* _NOLIBC_SYS_RANDOM_H */
+34
tools/include/nolibc/sys/reboot.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Reboot definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_REBOOT_H 11 + #define _NOLIBC_SYS_REBOOT_H 12 + 13 + #include "../sys.h" 14 + 15 + #include <linux/reboot.h> 16 + 17 + /* 18 + * int reboot(int cmd); 19 + * <cmd> is among LINUX_REBOOT_CMD_* 20 + */ 21 + 22 + static __attribute__((unused)) 23 + ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) 24 + { 25 + return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); 26 + } 27 + 28 + static __attribute__((unused)) 29 + int reboot(int cmd) 30 + { 31 + return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0)); 32 + } 33 + 34 + #endif /* _NOLIBC_SYS_REBOOT_H */
+53
tools/include/nolibc/sys/resource.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Resource definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_RESOURCE_H 11 + #define _NOLIBC_SYS_RESOURCE_H 12 + 13 + #include "../sys.h" 14 + 15 + #include <linux/resource.h> 16 + 17 + /* 18 + * int getrlimit(int resource, struct rlimit *rlim); 19 + * int setrlimit(int resource, const struct rlimit *rlim); 20 + */ 21 + 22 + static __attribute__((unused)) 23 + int sys_prlimit64(pid_t pid, int resource, 24 + const struct rlimit64 *new_limit, struct rlimit64 *old_limit) 25 + { 26 + return my_syscall4(__NR_prlimit64, pid, resource, new_limit, old_limit); 27 + } 28 + 29 + static __attribute__((unused)) 30 + int getrlimit(int resource, struct rlimit *rlim) 31 + { 32 + struct rlimit64 rlim64; 33 + int ret; 34 + 35 + ret = __sysret(sys_prlimit64(0, resource, NULL, &rlim64)); 36 + rlim->rlim_cur = rlim64.rlim_cur; 37 + rlim->rlim_max = rlim64.rlim_max; 38 + 39 + return ret; 40 + } 41 + 42 + static __attribute__((unused)) 43 + int setrlimit(int resource, const struct rlimit *rlim) 44 + { 45 + struct rlimit64 rlim64 = { 46 + .rlim_cur = rlim->rlim_cur, 47 + .rlim_max = rlim->rlim_max, 48 + }; 49 + 50 + return __sysret(sys_prlimit64(0, resource, &rlim64, NULL)); 51 + } 52 + 53 + #endif /* _NOLIBC_SYS_RESOURCE_H */
+94
tools/include/nolibc/sys/stat.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * stat definition for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_STAT_H 11 + #define _NOLIBC_SYS_STAT_H 12 + 13 + #include "../arch.h" 14 + #include "../types.h" 15 + #include "../sys.h" 16 + 17 + /* 18 + * int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf); 19 + * int stat(const char *path, struct stat *buf); 20 + * int fstatat(int fd, const char *path, struct stat *buf, int flag); 21 + * int fstat(int fildes, struct stat *buf); 22 + * int lstat(const char *path, struct stat *buf); 23 + */ 24 + 25 + static __attribute__((unused)) 26 + int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) 27 + { 28 + #ifdef __NR_statx 29 + return my_syscall5(__NR_statx, fd, path, flags, mask, buf); 30 + #else 31 + return __nolibc_enosys(__func__, fd, path, flags, mask, buf); 32 + #endif 33 + } 34 + 35 + static __attribute__((unused)) 36 + int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) 37 + { 38 + return __sysret(sys_statx(fd, path, flags, mask, buf)); 39 + } 40 + 41 + 42 + static __attribute__((unused)) 43 + int fstatat(int fd, const char *path, struct stat *buf, int flag) 44 + { 45 + struct statx statx; 46 + long ret; 47 + 48 + ret = __sysret(sys_statx(fd, path, flag | AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx)); 49 + if (ret == -1) 50 + return ret; 51 + 52 + buf->st_dev = ((statx.stx_dev_minor & 0xff) 53 + | (statx.stx_dev_major << 8) 54 + | ((statx.stx_dev_minor & ~0xff) << 12)); 55 + buf->st_ino = statx.stx_ino; 56 + buf->st_mode = statx.stx_mode; 57 + buf->st_nlink = statx.stx_nlink; 58 + buf->st_uid = statx.stx_uid; 59 + buf->st_gid = statx.stx_gid; 60 + buf->st_rdev = ((statx.stx_rdev_minor & 0xff) 61 + | (statx.stx_rdev_major << 8) 62 + | ((statx.stx_rdev_minor & ~0xff) << 12)); 63 + buf->st_size = statx.stx_size; 64 + buf->st_blksize = statx.stx_blksize; 65 + buf->st_blocks = statx.stx_blocks; 66 + buf->st_atim.tv_sec = statx.stx_atime.tv_sec; 67 + buf->st_atim.tv_nsec = statx.stx_atime.tv_nsec; 68 + buf->st_mtim.tv_sec = statx.stx_mtime.tv_sec; 69 + buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec; 70 + buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec; 71 + buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec; 72 + 73 + return 0; 74 + } 75 + 76 + static __attribute__((unused)) 77 + int stat(const char *path, struct stat *buf) 78 + { 79 + return fstatat(AT_FDCWD, path, buf, 0); 80 + } 81 + 82 + static __attribute__((unused)) 83 + int fstat(int fildes, struct stat *buf) 84 + { 85 + return fstatat(fildes, "", buf, AT_EMPTY_PATH); 86 + } 87 + 88 + static __attribute__((unused)) 89 + int lstat(const char *path, struct stat *buf) 90 + { 91 + return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); 92 + } 93 + 94 + #endif /* _NOLIBC_SYS_STAT_H */
+19
tools/include/nolibc/sys/syscall.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * syscall() definition for NOLIBC 4 + * Copyright (C) 2024 Thomas Weißschuh <linux@weissschuh.net> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_SYSCALL_H 11 + #define _NOLIBC_SYS_SYSCALL_H 12 + 13 + #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N 14 + #define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) 15 + #define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) 16 + #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) 17 + #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) 18 + 19 + #endif /* _NOLIBC_SYS_SYSCALL_H */
+20
tools/include/nolibc/sys/sysmacros.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Sysmacro definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_SYSMACROS_H 11 + #define _NOLIBC_SYS_SYSMACROS_H 12 + 13 + #include "../std.h" 14 + 15 + /* WARNING, it only deals with the 4096 first majors and 256 first minors */ 16 + #define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff))) 17 + #define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff)) 18 + #define minor(dev) ((unsigned int)((dev) & 0xff)) 19 + 20 + #endif /* _NOLIBC_SYS_SYSMACROS_H */
+49
tools/include/nolibc/sys/time.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * time definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_TIME_H 11 + #define _NOLIBC_SYS_TIME_H 12 + 13 + #include "../arch.h" 14 + #include "../sys.h" 15 + 16 + static int sys_clock_gettime(clockid_t clockid, struct timespec *tp); 17 + 18 + /* 19 + * int gettimeofday(struct timeval *tv, struct timezone *tz); 20 + */ 21 + 22 + static __attribute__((unused)) 23 + int sys_gettimeofday(struct timeval *tv, struct timezone *tz) 24 + { 25 + #ifdef __NR_gettimeofday 26 + return my_syscall2(__NR_gettimeofday, tv, tz); 27 + #else 28 + (void) tz; /* Non-NULL tz is undefined behaviour */ 29 + 30 + struct timespec tp; 31 + int ret; 32 + 33 + ret = sys_clock_gettime(CLOCK_REALTIME, &tp); 34 + if (!ret && tv) { 35 + tv->tv_sec = tp.tv_sec; 36 + tv->tv_usec = tp.tv_nsec / 1000; 37 + } 38 + 39 + return ret; 40 + #endif 41 + } 42 + 43 + static __attribute__((unused)) 44 + int gettimeofday(struct timeval *tv, struct timezone *tz) 45 + { 46 + return __sysret(sys_gettimeofday(tv, tz)); 47 + } 48 + 49 + #endif /* _NOLIBC_SYS_TIME_H */
+87
tools/include/nolibc/sys/timerfd.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * timerfd definitions for NOLIBC 4 + * Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_TIMERFD_H 11 + #define _NOLIBC_SYS_TIMERFD_H 12 + 13 + #include "../sys.h" 14 + #include "../time.h" 15 + 16 + #include <linux/timerfd.h> 17 + 18 + 19 + static __attribute__((unused)) 20 + int sys_timerfd_create(int clockid, int flags) 21 + { 22 + return my_syscall2(__NR_timerfd_create, clockid, flags); 23 + } 24 + 25 + static __attribute__((unused)) 26 + int timerfd_create(int clockid, int flags) 27 + { 28 + return __sysret(sys_timerfd_create(clockid, flags)); 29 + } 30 + 31 + 32 + static __attribute__((unused)) 33 + int sys_timerfd_gettime(int fd, struct itimerspec *curr_value) 34 + { 35 + #if defined(__NR_timerfd_gettime) 36 + return my_syscall2(__NR_timerfd_gettime, fd, curr_value); 37 + #elif defined(__NR_timerfd_gettime64) 38 + struct __kernel_itimerspec kcurr_value; 39 + int ret; 40 + 41 + ret = my_syscall2(__NR_timerfd_gettime64, fd, &kcurr_value); 42 + __nolibc_timespec_kernel_to_user(&kcurr_value.it_interval, &curr_value->it_interval); 43 + __nolibc_timespec_kernel_to_user(&kcurr_value.it_value, &curr_value->it_value); 44 + return ret; 45 + #else 46 + return __nolibc_enosys(__func__, fd, curr_value); 47 + #endif 48 + } 49 + 50 + static __attribute__((unused)) 51 + int timerfd_gettime(int fd, struct itimerspec *curr_value) 52 + { 53 + return __sysret(sys_timerfd_gettime(fd, curr_value)); 54 + } 55 + 56 + 57 + static __attribute__((unused)) 58 + int sys_timerfd_settime(int fd, int flags, 59 + const struct itimerspec *new_value, struct itimerspec *old_value) 60 + { 61 + #if defined(__NR_timerfd_settime) 62 + return my_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value); 63 + #elif defined(__NR_timerfd_settime64) 64 + struct __kernel_itimerspec knew_value, kold_value; 65 + int ret; 66 + 67 + __nolibc_timespec_user_to_kernel(&new_value->it_value, &knew_value.it_value); 68 + __nolibc_timespec_user_to_kernel(&new_value->it_interval, &knew_value.it_interval); 69 + ret = my_syscall4(__NR_timerfd_settime64, fd, flags, &knew_value, &kold_value); 70 + if (old_value) { 71 + __nolibc_timespec_kernel_to_user(&kold_value.it_interval, &old_value->it_interval); 72 + __nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value); 73 + } 74 + return ret; 75 + #else 76 + return __nolibc_enosys(__func__, fd, flags, new_value, old_value); 77 + #endif 78 + } 79 + 80 + static __attribute__((unused)) 81 + int timerfd_settime(int fd, int flags, 82 + const struct itimerspec *new_value, struct itimerspec *old_value) 83 + { 84 + return __sysret(sys_timerfd_settime(fd, flags, new_value, old_value)); 85 + } 86 + 87 + #endif /* _NOLIBC_SYS_TIMERFD_H */
+7
tools/include/nolibc/sys/types.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * sys/types.h shim for NOLIBC 4 + * Copyright (C) 2025 Thomas Weißschuh <thomas.weissschuh@linutronix.de> 5 + */ 6 + 7 + #include "../types.h"
+42
tools/include/nolibc/sys/utsname.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * Utsname definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_UTSNAME_H 11 + #define _NOLIBC_SYS_UTSNAME_H 12 + 13 + #include "../sys.h" 14 + 15 + #include <linux/utsname.h> 16 + 17 + /* 18 + * int uname(struct utsname *buf); 19 + */ 20 + 21 + struct utsname { 22 + char sysname[65]; 23 + char nodename[65]; 24 + char release[65]; 25 + char version[65]; 26 + char machine[65]; 27 + char domainname[65]; 28 + }; 29 + 30 + static __attribute__((unused)) 31 + int sys_uname(struct utsname *buf) 32 + { 33 + return my_syscall1(__NR_uname, buf); 34 + } 35 + 36 + static __attribute__((unused)) 37 + int uname(struct utsname *buf) 38 + { 39 + return __sysret(sys_uname(buf)); 40 + } 41 + 42 + #endif /* _NOLIBC_SYS_UTSNAME_H */
+116
tools/include/nolibc/sys/wait.h
··· 1 + /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 + /* 3 + * wait definitions for NOLIBC 4 + * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 + */ 6 + 7 + /* make sure to include all global symbols */ 8 + #include "../nolibc.h" 9 + 10 + #ifndef _NOLIBC_SYS_WAIT_H 11 + #define _NOLIBC_SYS_WAIT_H 12 + 13 + #include "../arch.h" 14 + #include "../std.h" 15 + #include "../types.h" 16 + 17 + /* 18 + * pid_t wait(int *status); 19 + * pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage); 20 + * pid_t waitpid(pid_t pid, int *status, int options); 21 + * int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); 22 + */ 23 + 24 + static __attribute__((unused)) 25 + pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) 26 + { 27 + #ifdef __NR_wait4 28 + return my_syscall4(__NR_wait4, pid, status, options, rusage); 29 + #else 30 + return __nolibc_enosys(__func__, pid, status, options, rusage); 31 + #endif 32 + } 33 + 34 + static __attribute__((unused)) 35 + pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) 36 + { 37 + return __sysret(sys_wait4(pid, status, options, rusage)); 38 + } 39 + 40 + static __attribute__((unused)) 41 + int sys_waitid(int which, pid_t pid, siginfo_t *infop, int options, struct rusage *rusage) 42 + { 43 + return my_syscall5(__NR_waitid, which, pid, infop, options, rusage); 44 + } 45 + 46 + static __attribute__((unused)) 47 + int waitid(int which, pid_t pid, siginfo_t *infop, int options) 48 + { 49 + return __sysret(sys_waitid(which, pid, infop, options, NULL)); 50 + } 51 + 52 + 53 + static __attribute__((unused)) 54 + pid_t waitpid(pid_t pid, int *status, int options) 55 + { 56 + int idtype, ret; 57 + siginfo_t info; 58 + pid_t id; 59 + 60 + if (pid == INT_MIN) { 61 + SET_ERRNO(ESRCH); 62 + return -1; 63 + } else if (pid < -1) { 64 + idtype = P_PGID; 65 + id = -pid; 66 + } else if (pid == -1) { 67 + idtype = P_ALL; 68 + id = 0; 69 + } else if (pid == 0) { 70 + idtype = P_PGID; 71 + id = 0; 72 + } else { 73 + idtype = P_PID; 74 + id = pid; 75 + } 76 + 77 + options |= WEXITED; 78 + 79 + ret = waitid(idtype, id, &info, options); 80 + if (ret) 81 + return ret; 82 + 83 + switch (info.si_code) { 84 + case 0: 85 + *status = 0; 86 + break; 87 + case CLD_EXITED: 88 + *status = (info.si_status & 0xff) << 8; 89 + break; 90 + case CLD_KILLED: 91 + *status = info.si_status & 0x7f; 92 + break; 93 + case CLD_DUMPED: 94 + *status = (info.si_status & 0x7f) | 0x80; 95 + break; 96 + case CLD_STOPPED: 97 + case CLD_TRAPPED: 98 + *status = (info.si_status << 8) + 0x7f; 99 + break; 100 + case CLD_CONTINUED: 101 + *status = 0xffff; 102 + break; 103 + default: 104 + return -1; 105 + } 106 + 107 + return info.si_pid; 108 + } 109 + 110 + static __attribute__((unused)) 111 + pid_t wait(int *status) 112 + { 113 + return waitpid(-1, status, 0); 114 + } 115 + 116 + #endif /* _NOLIBC_SYS_WAIT_H */
+187 -2
tools/include/nolibc/time.h
··· 4 4 * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_TIME_H 8 11 #define _NOLIBC_TIME_H 9 12 ··· 14 11 #include "arch.h" 15 12 #include "types.h" 16 13 #include "sys.h" 14 + 15 + #include <linux/signal.h> 16 + #include <linux/time.h> 17 + 18 + static __inline__ 19 + void __nolibc_timespec_user_to_kernel(const struct timespec *ts, struct __kernel_timespec *kts) 20 + { 21 + kts->tv_sec = ts->tv_sec; 22 + kts->tv_nsec = ts->tv_nsec; 23 + } 24 + 25 + static __inline__ 26 + void __nolibc_timespec_kernel_to_user(const struct __kernel_timespec *kts, struct timespec *ts) 27 + { 28 + ts->tv_sec = kts->tv_sec; 29 + ts->tv_nsec = kts->tv_nsec; 30 + } 31 + 32 + /* 33 + * int clock_getres(clockid_t clockid, struct timespec *res); 34 + * int clock_gettime(clockid_t clockid, struct timespec *tp); 35 + * int clock_settime(clockid_t clockid, const struct timespec *tp); 36 + */ 37 + 38 + static __attribute__((unused)) 39 + int sys_clock_getres(clockid_t clockid, struct timespec *res) 40 + { 41 + #if defined(__NR_clock_getres) 42 + return my_syscall2(__NR_clock_getres, clockid, res); 43 + #elif defined(__NR_clock_getres_time64) 44 + struct __kernel_timespec kres; 45 + int ret; 46 + 47 + ret = my_syscall2(__NR_clock_getres_time64, clockid, &kres); 48 + if (res) 49 + __nolibc_timespec_kernel_to_user(&kres, res); 50 + return ret; 51 + #else 52 + return __nolibc_enosys(__func__, clockid, res); 53 + #endif 54 + } 55 + 56 + static __attribute__((unused)) 57 + int clock_getres(clockid_t clockid, struct timespec *res) 58 + { 59 + return __sysret(sys_clock_getres(clockid, res)); 60 + } 61 + 62 + static __attribute__((unused)) 63 + int sys_clock_gettime(clockid_t clockid, struct timespec *tp) 64 + { 65 + #if defined(__NR_clock_gettime) 66 + return my_syscall2(__NR_clock_gettime, clockid, tp); 67 + #elif defined(__NR_clock_gettime64) 68 + struct __kernel_timespec ktp; 69 + int ret; 70 + 71 + ret = my_syscall2(__NR_clock_gettime64, clockid, &ktp); 72 + if (tp) 73 + __nolibc_timespec_kernel_to_user(&ktp, tp); 74 + return ret; 75 + #else 76 + return __nolibc_enosys(__func__, clockid, tp); 77 + #endif 78 + } 79 + 80 + static __attribute__((unused)) 81 + int clock_gettime(clockid_t clockid, struct timespec *tp) 82 + { 83 + return __sysret(sys_clock_gettime(clockid, tp)); 84 + } 85 + 86 + static __attribute__((unused)) 87 + int sys_clock_settime(clockid_t clockid, struct timespec *tp) 88 + { 89 + #if defined(__NR_clock_settime) 90 + return my_syscall2(__NR_clock_settime, clockid, tp); 91 + #elif defined(__NR_clock_settime64) 92 + struct __kernel_timespec ktp; 93 + 94 + __nolibc_timespec_user_to_kernel(tp, &ktp); 95 + return my_syscall2(__NR_clock_settime64, clockid, &ktp); 96 + #else 97 + return __nolibc_enosys(__func__, clockid, tp); 98 + #endif 99 + } 100 + 101 + static __attribute__((unused)) 102 + int clock_settime(clockid_t clockid, struct timespec *tp) 103 + { 104 + return __sysret(sys_clock_settime(clockid, tp)); 105 + } 106 + 107 + 108 + static __inline__ 109 + double difftime(time_t time1, time_t time2) 110 + { 111 + return time1 - time2; 112 + } 113 + 17 114 18 115 static __attribute__((unused)) 19 116 time_t time(time_t *tptr) ··· 128 25 return tv.tv_sec; 129 26 } 130 27 131 - /* make sure to include all global symbols */ 132 - #include "nolibc.h" 28 + 29 + /* 30 + * int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid); 31 + * int timer_gettime(timer_t timerid, struct itimerspec *curr_value); 32 + * int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value); 33 + */ 34 + 35 + static __attribute__((unused)) 36 + int sys_timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) 37 + { 38 + return my_syscall3(__NR_timer_create, clockid, evp, timerid); 39 + } 40 + 41 + static __attribute__((unused)) 42 + int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) 43 + { 44 + return __sysret(sys_timer_create(clockid, evp, timerid)); 45 + } 46 + 47 + static __attribute__((unused)) 48 + int sys_timer_delete(timer_t timerid) 49 + { 50 + return my_syscall1(__NR_timer_delete, timerid); 51 + } 52 + 53 + static __attribute__((unused)) 54 + int timer_delete(timer_t timerid) 55 + { 56 + return __sysret(sys_timer_delete(timerid)); 57 + } 58 + 59 + static __attribute__((unused)) 60 + int sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value) 61 + { 62 + #if defined(__NR_timer_gettime) 63 + return my_syscall2(__NR_timer_gettime, timerid, curr_value); 64 + #elif defined(__NR_timer_gettime64) 65 + struct __kernel_itimerspec kcurr_value; 66 + int ret; 67 + 68 + ret = my_syscall2(__NR_timer_gettime64, timerid, &kcurr_value); 69 + __nolibc_timespec_kernel_to_user(&kcurr_value.it_interval, &curr_value->it_interval); 70 + __nolibc_timespec_kernel_to_user(&kcurr_value.it_value, &curr_value->it_value); 71 + return ret; 72 + #else 73 + return __nolibc_enosys(__func__, timerid, curr_value); 74 + #endif 75 + } 76 + 77 + static __attribute__((unused)) 78 + int timer_gettime(timer_t timerid, struct itimerspec *curr_value) 79 + { 80 + return __sysret(sys_timer_gettime(timerid, curr_value)); 81 + } 82 + 83 + static __attribute__((unused)) 84 + int sys_timer_settime(timer_t timerid, int flags, 85 + const struct itimerspec *new_value, struct itimerspec *old_value) 86 + { 87 + #if defined(__NR_timer_settime) 88 + return my_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value); 89 + #elif defined(__NR_timer_settime64) 90 + struct __kernel_itimerspec knew_value, kold_value; 91 + int ret; 92 + 93 + __nolibc_timespec_user_to_kernel(&new_value->it_value, &knew_value.it_value); 94 + __nolibc_timespec_user_to_kernel(&new_value->it_interval, &knew_value.it_interval); 95 + ret = my_syscall4(__NR_timer_settime64, timerid, flags, &knew_value, &kold_value); 96 + if (old_value) { 97 + __nolibc_timespec_kernel_to_user(&kold_value.it_interval, &old_value->it_interval); 98 + __nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value); 99 + } 100 + return ret; 101 + #else 102 + return __nolibc_enosys(__func__, timerid, flags, new_value, old_value); 103 + #endif 104 + } 105 + 106 + static __attribute__((unused)) 107 + int timer_settime(timer_t timerid, int flags, 108 + const struct itimerspec *new_value, struct itimerspec *old_value) 109 + { 110 + return __sysret(sys_timer_settime(timerid, flags, new_value, old_value)); 111 + } 133 112 134 113 #endif /* _NOLIBC_TIME_H */
+5 -27
tools/include/nolibc/types.h
··· 4 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_TYPES_H 8 11 #define _NOLIBC_TYPES_H 9 12 10 13 #include "std.h" 11 14 #include <linux/mman.h> 12 - #include <linux/reboot.h> /* for LINUX_REBOOT_* */ 13 15 #include <linux/stat.h> 14 16 #include <linux/time.h> 15 17 #include <linux/wait.h> 16 - #include <linux/resource.h> 17 18 18 19 19 20 /* Only the generic macros and types may be defined here. The arch-specific ··· 157 156 __set->fds[__idx] = 0; \ 158 157 } while (0) 159 158 160 - /* for poll() */ 161 - #define POLLIN 0x0001 162 - #define POLLPRI 0x0002 163 - #define POLLOUT 0x0004 164 - #define POLLERR 0x0008 165 - #define POLLHUP 0x0010 166 - #define POLLNVAL 0x0020 167 - 168 - struct pollfd { 169 - int fd; 170 - short int events; 171 - short int revents; 172 - }; 173 - 174 159 /* for getdents64() */ 175 160 struct linux_dirent64 { 176 161 uint64_t d_ino; ··· 185 198 union { time_t st_ctime; struct timespec st_ctim; }; /* time of last status change */ 186 199 }; 187 200 188 - /* WARNING, it only deals with the 4096 first majors and 256 first minors */ 189 - #define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff))) 190 - #define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff)) 191 - #define minor(dev) ((unsigned int)(((dev) & 0xff)) 192 - 193 - #ifndef offsetof 194 - #define offsetof(TYPE, FIELD) ((size_t) &((TYPE *)0)->FIELD) 195 - #endif 201 + typedef __kernel_clockid_t clockid_t; 202 + typedef int timer_t; 196 203 197 204 #ifndef container_of 198 205 #define container_of(PTR, TYPE, FIELD) ({ \ ··· 194 213 (TYPE *)((char *) __FIELD_PTR - offsetof(TYPE, FIELD)); \ 195 214 }) 196 215 #endif 197 - 198 - /* make sure to include all global symbols */ 199 - #include "nolibc.h" 200 216 201 217 #endif /* _NOLIBC_TYPES_H */
+31 -9
tools/include/nolibc/unistd.h
··· 4 4 * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu> 5 5 */ 6 6 7 + /* make sure to include all global symbols */ 8 + #include "nolibc.h" 9 + 7 10 #ifndef _NOLIBC_UNISTD_H 8 11 #define _NOLIBC_UNISTD_H 9 12 ··· 19 16 #define STDIN_FILENO 0 20 17 #define STDOUT_FILENO 1 21 18 #define STDERR_FILENO 2 19 + 20 + #define F_OK 0 21 + #define X_OK 1 22 + #define W_OK 2 23 + #define R_OK 4 24 + 25 + /* 26 + * int access(const char *path, int amode); 27 + * int faccessat(int fd, const char *path, int amode, int flag); 28 + */ 29 + 30 + static __attribute__((unused)) 31 + int sys_faccessat(int fd, const char *path, int amode, int flag) 32 + { 33 + return my_syscall4(__NR_faccessat, fd, path, amode, flag); 34 + } 35 + 36 + static __attribute__((unused)) 37 + int faccessat(int fd, const char *path, int amode, int flag) 38 + { 39 + return __sysret(sys_faccessat(fd, path, amode, flag)); 40 + } 41 + 42 + static __attribute__((unused)) 43 + int access(const char *path, int amode) 44 + { 45 + return faccessat(AT_FDCWD, path, amode, 0); 46 + } 22 47 23 48 24 49 static __attribute__((unused)) ··· 86 55 { 87 56 return ioctl(fd, TIOCSPGRP, &pid); 88 57 } 89 - 90 - #define __syscall_narg(_0, _1, _2, _3, _4, _5, _6, N, ...) N 91 - #define _syscall_narg(...) __syscall_narg(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) 92 - #define _syscall(N, ...) __sysret(my_syscall##N(__VA_ARGS__)) 93 - #define _syscall_n(N, ...) _syscall(N, __VA_ARGS__) 94 - #define syscall(...) _syscall_n(_syscall_narg(__VA_ARGS__), ##__VA_ARGS__) 95 - 96 - /* make sure to include all global symbols */ 97 - #include "nolibc.h" 98 58 99 59 #endif /* _NOLIBC_UNISTD_H */
+1
tools/testing/selftests/Makefile
··· 48 48 TARGETS += ir 49 49 TARGETS += kcmp 50 50 TARGETS += kexec 51 + TARGETS += kselftest_harness 51 52 TARGETS += kvm 52 53 TARGETS += landlock 53 54 TARGETS += lib
+73 -99
tools/testing/selftests/kselftest_harness.h
··· 56 56 #include <asm/types.h> 57 57 #include <ctype.h> 58 58 #include <errno.h> 59 + #include <linux/unistd.h> 60 + #include <poll.h> 59 61 #include <stdbool.h> 60 62 #include <stdint.h> 61 63 #include <stdio.h> ··· 67 65 #include <sys/types.h> 68 66 #include <sys/wait.h> 69 67 #include <unistd.h> 70 - #include <setjmp.h> 71 68 72 69 #include "kselftest.h" 73 70 ··· 173 172 174 173 #define __TEST_IMPL(test_name, _signal) \ 175 174 static void test_name(struct __test_metadata *_metadata); \ 176 - static inline void wrapper_##test_name( \ 175 + static void wrapper_##test_name( \ 177 176 struct __test_metadata *_metadata, \ 178 - struct __fixture_variant_metadata *variant) \ 177 + struct __fixture_variant_metadata __attribute__((unused)) *variant) \ 179 178 { \ 180 - _metadata->setup_completed = true; \ 181 - if (setjmp(_metadata->env) == 0) \ 182 - test_name(_metadata); \ 183 - __test_check_assert(_metadata); \ 179 + test_name(_metadata); \ 184 180 } \ 185 181 static struct __test_metadata _##test_name##_object = \ 186 182 { .name = #test_name, \ ··· 256 258 * A bare "return;" statement may be used to return early. 257 259 */ 258 260 #define FIXTURE_SETUP(fixture_name) \ 259 - void fixture_name##_setup( \ 261 + static void fixture_name##_setup( \ 260 262 struct __test_metadata __attribute__((unused)) *_metadata, \ 261 263 FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \ 262 264 const FIXTURE_VARIANT(fixture_name) \ ··· 305 307 __FIXTURE_TEARDOWN(fixture_name) 306 308 307 309 #define __FIXTURE_TEARDOWN(fixture_name) \ 308 - void fixture_name##_teardown( \ 310 + static void fixture_name##_teardown( \ 309 311 struct __test_metadata __attribute__((unused)) *_metadata, \ 310 312 FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \ 311 313 const FIXTURE_VARIANT(fixture_name) \ ··· 399 401 struct __test_metadata *_metadata, \ 400 402 FIXTURE_DATA(fixture_name) *self, \ 401 403 const FIXTURE_VARIANT(fixture_name) *variant); \ 402 - static inline void wrapper_##fixture_name##_##test_name( \ 404 + static void wrapper_##fixture_name##_##test_name( \ 403 405 struct __test_metadata *_metadata, \ 404 406 struct __fixture_variant_metadata *variant) \ 405 407 { \ ··· 408 410 pid_t child = 1; \ 409 411 int status = 0; \ 410 412 /* Makes sure there is only one teardown, even when child forks again. */ \ 411 - bool *teardown = mmap(NULL, sizeof(*teardown), \ 413 + _metadata->no_teardown = mmap(NULL, sizeof(*_metadata->no_teardown), \ 412 414 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); \ 413 - *teardown = false; \ 415 + *_metadata->no_teardown = true; \ 414 416 if (sizeof(*self) > 0) { \ 415 417 if (fixture_name##_teardown_parent) { \ 416 418 self = mmap(NULL, sizeof(*self), PROT_READ | PROT_WRITE, \ ··· 420 422 self = &self_private; \ 421 423 } \ 422 424 } \ 423 - if (setjmp(_metadata->env) == 0) { \ 424 - /* _metadata and potentially self are shared with all forks. */ \ 425 - child = fork(); \ 426 - if (child == 0) { \ 427 - fixture_name##_setup(_metadata, self, variant->data); \ 428 - /* Let setup failure terminate early. */ \ 429 - if (_metadata->exit_code) \ 430 - _exit(0); \ 431 - _metadata->setup_completed = true; \ 432 - fixture_name##_##test_name(_metadata, self, variant->data); \ 433 - } else if (child < 0 || child != waitpid(child, &status, 0)) { \ 434 - ksft_print_msg("ERROR SPAWNING TEST GRANDCHILD\n"); \ 435 - _metadata->exit_code = KSFT_FAIL; \ 436 - } \ 437 - } \ 425 + _metadata->variant = variant->data; \ 426 + _metadata->self = self; \ 427 + /* _metadata and potentially self are shared with all forks. */ \ 428 + child = fork(); \ 438 429 if (child == 0) { \ 439 - if (_metadata->setup_completed && !fixture_name##_teardown_parent && \ 440 - __sync_bool_compare_and_swap(teardown, false, true)) \ 441 - fixture_name##_teardown(_metadata, self, variant->data); \ 430 + fixture_name##_setup(_metadata, self, variant->data); \ 431 + /* Let setup failure terminate early. */ \ 432 + if (_metadata->exit_code) \ 433 + _exit(0); \ 434 + *_metadata->no_teardown = false; \ 435 + fixture_name##_##test_name(_metadata, self, variant->data); \ 436 + _metadata->teardown_fn(false, _metadata, self, variant->data); \ 442 437 _exit(0); \ 438 + } else if (child < 0 || child != waitpid(child, &status, 0)) { \ 439 + ksft_print_msg("ERROR SPAWNING TEST GRANDCHILD\n"); \ 440 + _metadata->exit_code = KSFT_FAIL; \ 443 441 } \ 444 - if (_metadata->setup_completed && fixture_name##_teardown_parent && \ 445 - __sync_bool_compare_and_swap(teardown, false, true)) \ 446 - fixture_name##_teardown(_metadata, self, variant->data); \ 447 - munmap(teardown, sizeof(*teardown)); \ 442 + _metadata->teardown_fn(true, _metadata, self, variant->data); \ 443 + munmap(_metadata->no_teardown, sizeof(*_metadata->no_teardown)); \ 444 + _metadata->no_teardown = NULL; \ 448 445 if (self && fixture_name##_teardown_parent) \ 449 446 munmap(self, sizeof(*self)); \ 450 447 if (WIFEXITED(status)) { \ ··· 449 456 /* Forward signal to __wait_for_test(). */ \ 450 457 kill(getpid(), WTERMSIG(status)); \ 451 458 } \ 452 - __test_check_assert(_metadata); \ 459 + } \ 460 + static void wrapper_##fixture_name##_##test_name##_teardown( \ 461 + bool in_parent, struct __test_metadata *_metadata, \ 462 + void *self, const void *variant) \ 463 + { \ 464 + if (fixture_name##_teardown_parent == in_parent && \ 465 + !__atomic_test_and_set(_metadata->no_teardown, __ATOMIC_RELAXED)) \ 466 + fixture_name##_teardown(_metadata, self, variant); \ 453 467 } \ 454 468 static struct __test_metadata *_##fixture_name##_##test_name##_object; \ 455 469 static void __attribute__((constructor)) \ ··· 467 467 object->name = #test_name; \ 468 468 object->fn = &wrapper_##fixture_name##_##test_name; \ 469 469 object->fixture = &_##fixture_name##_fixture_object; \ 470 + object->teardown_fn = &wrapper_##fixture_name##_##test_name##_teardown; \ 470 471 object->termsig = signal; \ 471 472 object->timeout = tmout; \ 472 473 _##fixture_name##_##test_name##_object = object; \ ··· 911 910 struct __fixture_variant_metadata *); 912 911 pid_t pid; /* pid of test when being run */ 913 912 struct __fixture_metadata *fixture; 913 + void (*teardown_fn)(bool in_parent, struct __test_metadata *_metadata, 914 + void *self, const void *variant); 914 915 int termsig; 915 916 int exit_code; 916 917 int trigger; /* extra handler after the evaluation */ 917 918 int timeout; /* seconds to wait for test timeout */ 918 - bool timed_out; /* did this test timeout instead of exiting? */ 919 919 bool aborted; /* stopped test due to failed ASSERT */ 920 - bool setup_completed; /* did setup finish? */ 921 - jmp_buf env; /* for exiting out of test early */ 920 + bool *no_teardown; /* fixture needs teardown */ 921 + void *self; 922 + const void *variant; 922 923 struct __test_results *results; 923 924 struct __test_metadata *prev, *next; 924 925 }; ··· 954 951 { 955 952 /* if this is ASSERT, return immediately. */ 956 953 if (for_realz) { 957 - t->aborted = true; 958 - longjmp(t->env, 1); 954 + if (t->teardown_fn) 955 + t->teardown_fn(false, t, t->self, t->variant); 956 + abort(); 959 957 } 960 958 /* otherwise, end the for loop and continue. */ 961 959 return 0; 962 960 } 963 961 964 - static inline void __test_check_assert(struct __test_metadata *t) 962 + static void __wait_for_test(struct __test_metadata *t) 965 963 { 966 - if (t->aborted) 967 - abort(); 968 - } 969 - 970 - struct __test_metadata *__active_test; 971 - static void __timeout_handler(int sig, siginfo_t *info, void *ucontext) 972 - { 973 - struct __test_metadata *t = __active_test; 974 - 975 - /* Sanity check handler execution environment. */ 976 - if (!t) { 977 - fprintf(TH_LOG_STREAM, 978 - "# no active test in SIGALRM handler!?\n"); 979 - abort(); 980 - } 981 - if (sig != SIGALRM || sig != info->si_signo) { 982 - fprintf(TH_LOG_STREAM, 983 - "# %s: SIGALRM handler caught signal %d!?\n", 984 - t->name, sig != SIGALRM ? sig : info->si_signo); 985 - abort(); 986 - } 987 - 988 - t->timed_out = true; 989 - // signal process group 990 - kill(-(t->pid), SIGKILL); 991 - } 992 - 993 - void __wait_for_test(struct __test_metadata *t) 994 - { 995 - struct sigaction action = { 996 - .sa_sigaction = __timeout_handler, 997 - .sa_flags = SA_SIGINFO, 998 - }; 999 - struct sigaction saved_action; 1000 964 /* 1001 965 * Sets status so that WIFEXITED(status) returns true and 1002 966 * WEXITSTATUS(status) returns KSFT_FAIL. This safe default value 1003 967 * should never be evaluated because of the waitpid(2) check and 1004 - * SIGALRM handling. 968 + * timeout handling. 1005 969 */ 1006 970 int status = KSFT_FAIL << 8; 1007 - int child; 971 + struct pollfd poll_child; 972 + int ret, child, childfd; 973 + bool timed_out = false; 1008 974 1009 - if (sigaction(SIGALRM, &action, &saved_action)) { 975 + childfd = syscall(__NR_pidfd_open, t->pid, 0); 976 + if (childfd == -1) { 1010 977 t->exit_code = KSFT_FAIL; 1011 978 fprintf(TH_LOG_STREAM, 1012 - "# %s: unable to install SIGALRM handler\n", 979 + "# %s: unable to open pidfd\n", 1013 980 t->name); 1014 981 return; 1015 982 } 1016 - __active_test = t; 1017 - t->timed_out = false; 1018 - alarm(t->timeout); 1019 - child = waitpid(t->pid, &status, 0); 983 + 984 + poll_child.fd = childfd; 985 + poll_child.events = POLLIN; 986 + ret = poll(&poll_child, 1, t->timeout * 1000); 987 + if (ret == -1) { 988 + t->exit_code = KSFT_FAIL; 989 + fprintf(TH_LOG_STREAM, 990 + "# %s: unable to wait on child pidfd\n", 991 + t->name); 992 + return; 993 + } else if (ret == 0) { 994 + timed_out = true; 995 + /* signal process group */ 996 + kill(-(t->pid), SIGKILL); 997 + } 998 + child = waitpid(t->pid, &status, WNOHANG); 1020 999 if (child == -1 && errno != EINTR) { 1021 1000 t->exit_code = KSFT_FAIL; 1022 1001 fprintf(TH_LOG_STREAM, ··· 1007 1022 return; 1008 1023 } 1009 1024 1010 - alarm(0); 1011 - if (sigaction(SIGALRM, &saved_action, NULL)) { 1012 - t->exit_code = KSFT_FAIL; 1013 - fprintf(TH_LOG_STREAM, 1014 - "# %s: unable to uninstall SIGALRM handler\n", 1015 - t->name); 1016 - return; 1017 - } 1018 - __active_test = NULL; 1019 - 1020 - if (t->timed_out) { 1025 + if (timed_out) { 1021 1026 t->exit_code = KSFT_FAIL; 1022 1027 fprintf(TH_LOG_STREAM, 1023 1028 "# %s: Test terminated by timeout\n", t->name); ··· 1180 1205 return !has_positive; 1181 1206 } 1182 1207 1183 - void __run_test(struct __fixture_metadata *f, 1184 - struct __fixture_variant_metadata *variant, 1185 - struct __test_metadata *t) 1208 + static void __run_test(struct __fixture_metadata *f, 1209 + struct __fixture_variant_metadata *variant, 1210 + struct __test_metadata *t) 1186 1211 { 1187 1212 struct __test_xfail *xfail; 1188 1213 char test_name[1024]; ··· 1193 1218 t->exit_code = KSFT_PASS; 1194 1219 t->trigger = 0; 1195 1220 t->aborted = false; 1196 - t->setup_completed = false; 1197 - memset(t->env, 0, sizeof(t->env)); 1221 + t->no_teardown = NULL; 1198 1222 memset(t->results->reason, 0, sizeof(t->results->reason)); 1199 1223 1200 1224 snprintf(test_name, sizeof(test_name), "%s%s%s.%s",
+2
tools/testing/selftests/kselftest_harness/.gitignore
··· 1 + /harness-selftest 2 + /harness-selftest.seen
+7
tools/testing/selftests/kselftest_harness/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + TEST_GEN_PROGS_EXTENDED := harness-selftest 4 + TEST_PROGS := harness-selftest.sh 5 + EXTRA_CLEAN := harness-selftest.seen 6 + 7 + include ../lib.mk
+136
tools/testing/selftests/kselftest_harness/harness-selftest.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <stdio.h> 4 + 5 + #include <sys/resource.h> 6 + #include <sys/prctl.h> 7 + 8 + /* Avoid any inconsistencies */ 9 + #define TH_LOG_STREAM stdout 10 + 11 + #include "../kselftest_harness.h" 12 + 13 + static void test_helper(struct __test_metadata *_metadata) 14 + { 15 + ASSERT_EQ(0, 0); 16 + } 17 + 18 + TEST(standalone_pass) { 19 + TH_LOG("before"); 20 + ASSERT_EQ(0, 0); 21 + EXPECT_EQ(0, 0); 22 + test_helper(_metadata); 23 + TH_LOG("after"); 24 + } 25 + 26 + TEST(standalone_fail) { 27 + TH_LOG("before"); 28 + EXPECT_EQ(0, 0); 29 + EXPECT_EQ(0, 1); 30 + ASSERT_EQ(0, 1); 31 + TH_LOG("after"); 32 + } 33 + 34 + TEST_SIGNAL(signal_pass, SIGUSR1) { 35 + TH_LOG("before"); 36 + ASSERT_EQ(0, 0); 37 + TH_LOG("after"); 38 + kill(getpid(), SIGUSR1); 39 + } 40 + 41 + TEST_SIGNAL(signal_fail, SIGUSR1) { 42 + TH_LOG("before"); 43 + ASSERT_EQ(0, 1); 44 + TH_LOG("after"); 45 + kill(getpid(), SIGUSR1); 46 + } 47 + 48 + FIXTURE(fixture) { 49 + pid_t testpid; 50 + }; 51 + 52 + FIXTURE_SETUP(fixture) { 53 + TH_LOG("setup"); 54 + self->testpid = getpid(); 55 + } 56 + 57 + FIXTURE_TEARDOWN(fixture) { 58 + TH_LOG("teardown same-process=%d", self->testpid == getpid()); 59 + } 60 + 61 + TEST_F(fixture, pass) { 62 + TH_LOG("before"); 63 + ASSERT_EQ(0, 0); 64 + test_helper(_metadata); 65 + standalone_pass(_metadata); 66 + TH_LOG("after"); 67 + } 68 + 69 + TEST_F(fixture, fail) { 70 + TH_LOG("before"); 71 + ASSERT_EQ(0, 1); 72 + fixture_pass(_metadata, self, variant); 73 + TH_LOG("after"); 74 + } 75 + 76 + TEST_F_TIMEOUT(fixture, timeout, 1) { 77 + TH_LOG("before"); 78 + sleep(2); 79 + TH_LOG("after"); 80 + } 81 + 82 + FIXTURE(fixture_parent) { 83 + pid_t testpid; 84 + }; 85 + 86 + FIXTURE_SETUP(fixture_parent) { 87 + TH_LOG("setup"); 88 + self->testpid = getpid(); 89 + } 90 + 91 + FIXTURE_TEARDOWN_PARENT(fixture_parent) { 92 + TH_LOG("teardown same-process=%d", self->testpid == getpid()); 93 + } 94 + 95 + TEST_F(fixture_parent, pass) { 96 + TH_LOG("before"); 97 + ASSERT_EQ(0, 0); 98 + TH_LOG("after"); 99 + } 100 + 101 + FIXTURE(fixture_setup_failure) { 102 + pid_t testpid; 103 + }; 104 + 105 + FIXTURE_SETUP(fixture_setup_failure) { 106 + TH_LOG("setup"); 107 + self->testpid = getpid(); 108 + ASSERT_EQ(0, 1); 109 + } 110 + 111 + FIXTURE_TEARDOWN(fixture_setup_failure) { 112 + TH_LOG("teardown same-process=%d", self->testpid == getpid()); 113 + } 114 + 115 + TEST_F(fixture_setup_failure, pass) { 116 + TH_LOG("before"); 117 + ASSERT_EQ(0, 0); 118 + TH_LOG("after"); 119 + } 120 + 121 + int main(int argc, char **argv) 122 + { 123 + /* 124 + * The harness uses abort() to signal assertion failures, which triggers coredumps. 125 + * This may be useful to debug real failures but not for this selftest, disable them. 126 + */ 127 + struct rlimit rlimit = { 128 + .rlim_cur = 0, 129 + .rlim_max = 0, 130 + }; 131 + 132 + prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); 133 + setrlimit(RLIMIT_CORE, &rlimit); 134 + 135 + return test_harness_run(argc, argv); 136 + }
+64
tools/testing/selftests/kselftest_harness/harness-selftest.expected
··· 1 + TAP version 13 2 + 1..9 3 + # Starting 9 tests from 4 test cases. 4 + # RUN global.standalone_pass ... 5 + # harness-selftest.c:19:standalone_pass:before 6 + # harness-selftest.c:23:standalone_pass:after 7 + # OK global.standalone_pass 8 + ok 1 global.standalone_pass 9 + # RUN global.standalone_fail ... 10 + # harness-selftest.c:27:standalone_fail:before 11 + # harness-selftest.c:29:standalone_fail:Expected 0 (0) == 1 (1) 12 + # harness-selftest.c:30:standalone_fail:Expected 0 (0) == 1 (1) 13 + # standalone_fail: Test terminated by assertion 14 + # FAIL global.standalone_fail 15 + not ok 2 global.standalone_fail 16 + # RUN global.signal_pass ... 17 + # harness-selftest.c:35:signal_pass:before 18 + # harness-selftest.c:37:signal_pass:after 19 + # OK global.signal_pass 20 + ok 3 global.signal_pass 21 + # RUN global.signal_fail ... 22 + # harness-selftest.c:42:signal_fail:before 23 + # harness-selftest.c:43:signal_fail:Expected 0 (0) == 1 (1) 24 + # signal_fail: Test terminated by assertion 25 + # FAIL global.signal_fail 26 + not ok 4 global.signal_fail 27 + # RUN fixture.pass ... 28 + # harness-selftest.c:53:pass:setup 29 + # harness-selftest.c:62:pass:before 30 + # harness-selftest.c:19:pass:before 31 + # harness-selftest.c:23:pass:after 32 + # harness-selftest.c:66:pass:after 33 + # harness-selftest.c:58:pass:teardown same-process=1 34 + # OK fixture.pass 35 + ok 5 fixture.pass 36 + # RUN fixture.fail ... 37 + # harness-selftest.c:53:fail:setup 38 + # harness-selftest.c:70:fail:before 39 + # harness-selftest.c:71:fail:Expected 0 (0) == 1 (1) 40 + # harness-selftest.c:58:fail:teardown same-process=1 41 + # fail: Test terminated by assertion 42 + # FAIL fixture.fail 43 + not ok 6 fixture.fail 44 + # RUN fixture.timeout ... 45 + # harness-selftest.c:53:timeout:setup 46 + # harness-selftest.c:77:timeout:before 47 + # timeout: Test terminated by timeout 48 + # FAIL fixture.timeout 49 + not ok 7 fixture.timeout 50 + # RUN fixture_parent.pass ... 51 + # harness-selftest.c:87:pass:setup 52 + # harness-selftest.c:96:pass:before 53 + # harness-selftest.c:98:pass:after 54 + # harness-selftest.c:92:pass:teardown same-process=0 55 + # OK fixture_parent.pass 56 + ok 8 fixture_parent.pass 57 + # RUN fixture_setup_failure.pass ... 58 + # harness-selftest.c:106:pass:setup 59 + # harness-selftest.c:108:pass:Expected 0 (0) == 1 (1) 60 + # pass: Test terminated by assertion 61 + # FAIL fixture_setup_failure.pass 62 + not ok 9 fixture_setup_failure.pass 63 + # FAILED: 4 / 9 tests passed. 64 + # Totals: pass:4 fail:5 xfail:0 xpass:0 skip:0 error:0
+13
tools/testing/selftests/kselftest_harness/harness-selftest.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # Selftest for kselftest_harness.h 5 + # 6 + 7 + set -e 8 + 9 + DIR="$(dirname $(readlink -f "$0"))" 10 + 11 + "$DIR"/harness-selftest > harness-selftest.seen || true 12 + 13 + diff -u "$DIR"/harness-selftest.expected harness-selftest.seen
+25 -3
tools/testing/selftests/nolibc/Makefile
··· 56 56 ARCH_riscv32 = riscv 57 57 ARCH_riscv64 = riscv 58 58 ARCH_s390x = s390 59 + ARCH_sparc32 = sparc 60 + ARCH_sparc64 = sparc 59 61 ARCH := $(or $(ARCH_$(XARCH)),$(XARCH)) 60 62 61 63 # kernel image names by architecture ··· 78 76 IMAGE_s390x = arch/s390/boot/bzImage 79 77 IMAGE_s390 = arch/s390/boot/bzImage 80 78 IMAGE_loongarch = arch/loongarch/boot/vmlinuz.efi 79 + IMAGE_sparc32 = arch/sparc/boot/image 80 + IMAGE_sparc64 = arch/sparc/boot/image 81 + IMAGE_m68k = vmlinux 81 82 IMAGE = $(objtree)/$(IMAGE_$(XARCH)) 82 83 IMAGE_NAME = $(notdir $(IMAGE)) 83 84 ··· 102 97 DEFCONFIG_s390x = defconfig 103 98 DEFCONFIG_s390 = defconfig compat.config 104 99 DEFCONFIG_loongarch = defconfig 100 + DEFCONFIG_sparc32 = sparc32_defconfig 101 + DEFCONFIG_sparc64 = sparc64_defconfig 102 + DEFCONFIG_m68k = virt_defconfig 105 103 DEFCONFIG = $(DEFCONFIG_$(XARCH)) 106 104 105 + EXTRACONFIG_m68k = -e CONFIG_BLK_DEV_INITRD 107 106 EXTRACONFIG = $(EXTRACONFIG_$(XARCH)) 107 + EXTRACONFIG_arm = -e CONFIG_NAMESPACES 108 + EXTRACONFIG_armthumb = -e CONFIG_NAMESPACES 108 109 109 110 # optional tests to run (default = all) 110 111 TEST = ··· 133 122 QEMU_ARCH_s390x = s390x 134 123 QEMU_ARCH_s390 = s390x 135 124 QEMU_ARCH_loongarch = loongarch64 125 + QEMU_ARCH_sparc32 = sparc 126 + QEMU_ARCH_sparc64 = sparc64 127 + QEMU_ARCH_m68k = m68k 136 128 QEMU_ARCH = $(QEMU_ARCH_$(XARCH)) 137 129 138 130 QEMU_ARCH_USER_ppc64le = ppc64le ··· 166 152 QEMU_ARGS_s390x = -M s390-ccw-virtio -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 167 153 QEMU_ARGS_s390 = -M s390-ccw-virtio -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 168 154 QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 155 + QEMU_ARGS_sparc32 = -M SS-5 -m 256M -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 156 + QEMU_ARGS_sparc64 = -M sun4u -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 157 + QEMU_ARGS_m68k = -M virt -append "console=ttyGF0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" 169 158 QEMU_ARGS = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA) 170 159 171 160 # OUTPUT is only set when run from the main makefile, otherwise ··· 191 174 CFLAGS_s390 = -m31 192 175 CFLAGS_mips32le = -EL -mabi=32 -fPIC 193 176 CFLAGS_mips32be = -EB -mabi=32 177 + CFLAGS_sparc32 = $(call cc-option,-m32) 178 + ifeq ($(origin XARCH),command line) 179 + CFLAGS_XARCH = $(CFLAGS_$(XARCH)) 180 + endif 194 181 CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) 182 + CFLAGS_SANITIZER ?= $(call cc-option,-fsanitize=undefined -fsanitize-trap=all) 195 183 CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ 196 184 $(call cc-option,-fno-stack-protector) $(call cc-option,-Wmissing-prototypes) \ 197 - $(CFLAGS_$(XARCH)) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_EXTRA) 185 + $(CFLAGS_XARCH) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_SANITIZER) $(CFLAGS_EXTRA) 198 186 LDFLAGS := 199 187 200 188 LIBGCC := -lgcc ··· 254 232 255 233 sysroot: sysroot/$(ARCH)/include 256 234 257 - sysroot/$(ARCH)/include: | defconfig 235 + sysroot/$(ARCH)/include: 258 236 $(Q)rm -rf sysroot/$(ARCH) sysroot/sysroot 259 237 $(QUIET_MKDIR)mkdir -p sysroot 260 238 $(Q)$(MAKE) -C $(srctree) outputmakefile 261 - $(Q)$(MAKE) -C $(srctree)/tools/include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone 239 + $(Q)$(MAKE) -C $(srctree)/tools/include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone headers_check 262 240 $(Q)mv sysroot/sysroot sysroot/$(ARCH) 263 241 264 242 ifneq ($(NOLIBC_SYSROOT),0)
-2
tools/testing/selftests/nolibc/nolibc-test-linkage.c
··· 2 2 3 3 #include "nolibc-test-linkage.h" 4 4 5 - #ifndef NOLIBC 6 5 #include <errno.h> 7 - #endif 8 6 9 7 void *linkage_test_errno_addr(void) 10 8 {
+287 -44
tools/testing/selftests/nolibc/nolibc-test.c
··· 9 9 * $(CC) -nostdlib -I/path/to/nolibc/sysroot => _NOLIBC_* guards are present 10 10 * $(CC) with default libc => NOLIBC* never defined 11 11 */ 12 - #ifndef NOLIBC 13 12 #include <stdio.h> 14 13 #include <stdlib.h> 15 14 #include <string.h> 16 - #ifndef _NOLIBC_STDIO_H 17 - /* standard libcs need more includes */ 18 15 #include <sys/auxv.h> 19 - #include <sys/io.h> 20 16 #include <sys/ioctl.h> 21 17 #include <sys/mman.h> 22 18 #include <sys/mount.h> 23 19 #include <sys/prctl.h> 20 + #include <sys/random.h> 24 21 #include <sys/reboot.h> 25 22 #include <sys/resource.h> 26 23 #include <sys/stat.h> 27 24 #include <sys/syscall.h> 28 25 #include <sys/sysmacros.h> 29 26 #include <sys/time.h> 27 + #include <sys/timerfd.h> 30 28 #include <sys/utsname.h> 31 29 #include <sys/wait.h> 32 30 #include <dirent.h> ··· 36 38 #include <stdarg.h> 37 39 #include <stddef.h> 38 40 #include <stdint.h> 41 + #include <time.h> 39 42 #include <unistd.h> 40 43 #include <limits.h> 41 - #endif 42 - #endif 44 + #include <ctype.h> 43 45 44 46 #pragma GCC diagnostic ignored "-Wmissing-prototypes" 45 47 ··· 805 807 return 0; 806 808 } 807 809 810 + int test_getrandom(void) 811 + { 812 + uint64_t rng = 0; 813 + ssize_t ret; 814 + 815 + ret = getrandom(&rng, sizeof(rng), GRND_NONBLOCK); 816 + if (ret == -1 && errno == EAGAIN) 817 + return 0; /* No entropy available yet */ 818 + 819 + if (ret != sizeof(rng)) 820 + return ret; 821 + 822 + if (!rng) { 823 + errno = EINVAL; 824 + return -1; 825 + } 826 + 827 + return 0; 828 + } 829 + 808 830 int test_getpagesize(void) 809 831 { 810 832 int x = getpagesize(); ··· 852 834 #endif 853 835 854 836 return !c; 837 + } 838 + 839 + int test_file_stream(void) 840 + { 841 + FILE *f; 842 + int r; 843 + 844 + f = fopen("/dev/null", "r"); 845 + if (!f) 846 + return -1; 847 + 848 + errno = 0; 849 + r = fwrite("foo", 1, 3, f); 850 + if (r != 0 || errno != EBADF) { 851 + fclose(f); 852 + return -1; 853 + } 854 + 855 + r = fclose(f); 856 + if (r == EOF) 857 + return -1; 858 + 859 + return 0; 855 860 } 856 861 857 862 int test_fork(void) ··· 924 883 return 0; 925 884 } 926 885 886 + int test_timer(void) 887 + { 888 + struct itimerspec timerspec; 889 + struct sigevent evp; 890 + timer_t timer; 891 + int ret; 892 + 893 + evp.sigev_notify = SIGEV_NONE; 894 + 895 + ret = timer_create(CLOCK_MONOTONIC, &evp, &timer); 896 + if (ret) 897 + return ret; 898 + 899 + timerspec = (struct itimerspec) { 900 + .it_value.tv_sec = 1000000, 901 + }; 902 + ret = timer_settime(timer, 0, &timerspec, NULL); 903 + if (ret) 904 + goto err; 905 + 906 + timerspec = (struct itimerspec) { 907 + .it_value.tv_sec = -1, 908 + .it_value.tv_nsec = -1, 909 + .it_interval.tv_sec = -1, 910 + .it_interval.tv_nsec = -1, 911 + }; 912 + ret = timer_gettime(timer, &timerspec); 913 + if (ret) 914 + goto err; 915 + 916 + errno = EINVAL; 917 + ret = -1; 918 + 919 + if (timerspec.it_interval.tv_sec || timerspec.it_interval.tv_nsec) 920 + goto err; 921 + 922 + if (timerspec.it_value.tv_sec > 1000000) 923 + goto err; 924 + 925 + ret = timer_delete(timer); 926 + if (ret) 927 + return ret; 928 + 929 + return 0; 930 + 931 + err: 932 + timer_delete(timer); 933 + return ret; 934 + } 935 + 936 + int test_timerfd(void) 937 + { 938 + struct itimerspec timerspec; 939 + int timer, ret; 940 + 941 + timer = timerfd_create(CLOCK_MONOTONIC, 0); 942 + if (timer == -1) 943 + return -1; 944 + 945 + timerspec = (struct itimerspec) { 946 + .it_value.tv_sec = 1000000, 947 + }; 948 + ret = timerfd_settime(timer, 0, &timerspec, NULL); 949 + if (ret) 950 + goto err; 951 + 952 + timerspec = (struct itimerspec) { 953 + .it_value.tv_sec = -1, 954 + .it_value.tv_nsec = -1, 955 + .it_interval.tv_sec = -1, 956 + .it_interval.tv_nsec = -1, 957 + }; 958 + ret = timerfd_gettime(timer, &timerspec); 959 + if (ret) 960 + goto err; 961 + 962 + errno = EINVAL; 963 + ret = -1; 964 + 965 + if (timerspec.it_interval.tv_sec || timerspec.it_interval.tv_nsec) 966 + goto err; 967 + 968 + if (timerspec.it_value.tv_sec > 1000000) 969 + goto err; 970 + 971 + ret = close(timer); 972 + if (ret) 973 + return ret; 974 + 975 + return 0; 976 + 977 + err: 978 + close(timer); 979 + return ret; 980 + } 981 + 927 982 int test_uname(void) 928 983 { 929 984 struct utsname buf; ··· 1063 926 { 1064 927 int ret, fd, i, page_size; 1065 928 void *mem; 1066 - size_t file_size, length; 929 + size_t file_size, length, mem_length; 1067 930 off_t offset, pa_offset; 1068 931 struct stat stat_buf; 1069 932 const char * const files[] = { ··· 1103 966 offset = 0; 1104 967 length = file_size - offset; 1105 968 pa_offset = offset & ~(page_size - 1); 969 + mem_length = length + offset - pa_offset; 1106 970 1107 - mem = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_SHARED, fd, pa_offset); 971 + mem = mmap(NULL, mem_length, PROT_READ, MAP_SHARED, fd, pa_offset); 1108 972 if (mem == MAP_FAILED) { 1109 973 ret = 1; 1110 974 goto end; 1111 975 } 1112 976 1113 - ret = munmap(mem, length + offset - pa_offset); 977 + mem = mremap(mem, mem_length, mem_length * 2, MREMAP_MAYMOVE, 0); 978 + if (mem == MAP_FAILED) { 979 + munmap(mem, mem_length); 980 + ret = 1; 981 + goto end; 982 + } 983 + 984 + ret = munmap(mem, mem_length * 2); 1114 985 1115 986 end: 1116 987 close(fd); ··· 1190 1045 return 0; 1191 1046 } 1192 1047 1048 + int test_namespace(void) 1049 + { 1050 + int original_ns, new_ns, ret; 1051 + ino_t original_ns_ino; 1052 + struct stat stat_buf; 1053 + 1054 + original_ns = open("/proc/self/ns/uts", O_RDONLY); 1055 + if (original_ns == -1) 1056 + return -1; 1057 + 1058 + ret = fstat(original_ns, &stat_buf); 1059 + if (ret) 1060 + goto out; 1061 + 1062 + original_ns_ino = stat_buf.st_ino; 1063 + 1064 + ret = unshare(CLONE_NEWUTS); 1065 + if (ret) 1066 + goto out; 1067 + 1068 + new_ns = open("/proc/self/ns/uts", O_RDONLY); 1069 + if (new_ns == -1) { 1070 + ret = new_ns; 1071 + goto out; 1072 + } 1073 + 1074 + ret = fstat(new_ns, &stat_buf); 1075 + close(new_ns); 1076 + if (ret) 1077 + goto out; 1078 + 1079 + if (stat_buf.st_ino == original_ns_ino) { 1080 + errno = EINVAL; 1081 + ret = -1; 1082 + goto out; 1083 + } 1084 + 1085 + ret = setns(original_ns, CLONE_NEWUTS); 1086 + if (ret) 1087 + goto out; 1088 + 1089 + new_ns = open("/proc/self/ns/uts", O_RDONLY); 1090 + if (new_ns == -1) { 1091 + ret = new_ns; 1092 + goto out; 1093 + } 1094 + 1095 + ret = fstat(new_ns, &stat_buf); 1096 + if (ret) 1097 + goto out; 1098 + 1099 + close(new_ns); 1100 + 1101 + if (stat_buf.st_ino != original_ns_ino) { 1102 + errno = EINVAL; 1103 + ret = -1; 1104 + goto out; 1105 + } 1106 + 1107 + ret = 0; 1108 + 1109 + out: 1110 + close(original_ns); 1111 + return ret; 1112 + } 1113 + 1193 1114 /* Run syscall tests between IDs <min> and <max>. 1194 1115 * Return 0 on success, non-zero on failure. 1195 1116 */ ··· 1263 1052 { 1264 1053 struct timeval tv; 1265 1054 struct timezone tz; 1055 + struct timespec ts; 1266 1056 struct stat stat_buf; 1267 1057 int euid0; 1268 1058 int proc; ··· 1295 1083 * test numbers. 1296 1084 */ 1297 1085 switch (test + __LINE__ + 1) { 1086 + CASE_TEST(access); EXPECT_SYSZR(proc, access("/proc/self", R_OK)); break; 1087 + CASE_TEST(access_bad); EXPECT_SYSER(proc, access("/proc/self", W_OK), -1, EPERM); break; 1088 + CASE_TEST(clock_getres); EXPECT_SYSZR(1, clock_getres(CLOCK_MONOTONIC, &ts)); break; 1089 + CASE_TEST(clock_gettime); EXPECT_SYSZR(1, clock_gettime(CLOCK_MONOTONIC, &ts)); break; 1090 + CASE_TEST(clock_settime); EXPECT_SYSER(1, clock_settime(CLOCK_MONOTONIC, &ts), -1, EINVAL); break; 1298 1091 CASE_TEST(getpid); EXPECT_SYSNE(1, getpid(), -1); break; 1299 1092 CASE_TEST(getppid); EXPECT_SYSNE(1, getppid(), -1); break; 1300 1093 CASE_TEST(gettid); EXPECT_SYSNE(has_gettid, gettid(), -1); break; ··· 1329 1112 CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; 1330 1113 CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break; 1331 1114 CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break; 1115 + CASE_TEST(file_stream); EXPECT_SYSZR(1, test_file_stream()); break; 1332 1116 CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break; 1333 1117 CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; 1334 1118 CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; 1335 1119 CASE_TEST(directories); EXPECT_SYSZR(proc, test_dirent()); break; 1120 + CASE_TEST(getrandom); EXPECT_SYSZR(1, test_getrandom()); break; 1336 1121 CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break; 1337 1122 CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break; 1338 1123 CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break; ··· 1368 1149 CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break; 1369 1150 CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break; 1370 1151 CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; 1152 + CASE_TEST(timer); EXPECT_SYSZR(1, test_timer()); break; 1153 + CASE_TEST(timerfd); EXPECT_SYSZR(1, test_timerfd()); break; 1371 1154 CASE_TEST(uname); EXPECT_SYSZR(proc, test_uname()); break; 1372 1155 CASE_TEST(uname_fault); EXPECT_SYSER(1, uname(NULL), -1, EFAULT); break; 1373 1156 CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break; ··· 1381 1160 CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break; 1382 1161 CASE_TEST(syscall_noargs); EXPECT_SYSEQ(1, syscall(__NR_getpid), getpid()); break; 1383 1162 CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_statx, 0, NULL, 0, 0, NULL), -1, EFAULT); break; 1163 + CASE_TEST(namespace); EXPECT_SYSZR(euid0 && proc, test_namespace()); break; 1384 1164 case __LINE__: 1385 1165 return ret; /* must be last */ 1386 1166 /* note: do not set any defaults so as to permit holes above */ 1387 1167 } 1388 1168 } 1389 1169 return ret; 1170 + } 1171 + 1172 + int test_difftime(void) 1173 + { 1174 + if (difftime(200., 100.) != 100.) 1175 + return 1; 1176 + 1177 + if (difftime(100., 200.) != -100.) 1178 + return 1; 1179 + 1180 + return 0; 1390 1181 } 1391 1182 1392 1183 int run_stdlib(int min, int max) ··· 1444 1211 CASE_TEST(strlcpy_2); EXPECT_STRBUFEQ(is_nolibc, strlcpy(buf, "bar", 2), buf, 3, "b"); break; 1445 1212 CASE_TEST(strlcpy_3); EXPECT_STRBUFEQ(is_nolibc, strlcpy(buf, "bar", 3), buf, 3, "ba"); break; 1446 1213 CASE_TEST(strlcpy_4); EXPECT_STRBUFEQ(is_nolibc, strlcpy(buf, "bar", 4), buf, 3, "bar"); break; 1214 + CASE_TEST(strstr_foobar_foo); EXPECT_STREQ(1, strstr("foobar", "foo"), "foobar"); break; 1215 + CASE_TEST(strstr_foobar_bar); EXPECT_STREQ(1, strstr("foobar", "bar"), "bar"); break; 1216 + CASE_TEST(strstr_foobar_baz); EXPECT_PTREQ(1, strstr("foobar", "baz"), NULL); break; 1447 1217 CASE_TEST(memcmp_20_20); EXPECT_EQ(1, memcmp("aaa\x20", "aaa\x20", 4), 0); break; 1448 1218 CASE_TEST(memcmp_20_60); EXPECT_LT(1, memcmp("aaa\x20", "aaa\x60", 4), 0); break; 1449 1219 CASE_TEST(memcmp_60_20); EXPECT_GT(1, memcmp("aaa\x60", "aaa\x20", 4), 0); break; ··· 1517 1281 CASE_TEST(strerror_EINVAL); EXPECT_STREQ(is_nolibc, strerror(EINVAL), "errno=22"); break; 1518 1282 CASE_TEST(strerror_int_max); EXPECT_STREQ(is_nolibc, strerror(INT_MAX), "errno=2147483647"); break; 1519 1283 CASE_TEST(strerror_int_min); EXPECT_STREQ(is_nolibc, strerror(INT_MIN), "errno=-2147483648"); break; 1284 + CASE_TEST(tolower); EXPECT_EQ(1, tolower('A'), 'a'); break; 1285 + CASE_TEST(tolower_noop); EXPECT_EQ(1, tolower('a'), 'a'); break; 1286 + CASE_TEST(toupper); EXPECT_EQ(1, toupper('a'), 'A'); break; 1287 + CASE_TEST(toupper_noop); EXPECT_EQ(1, toupper('A'), 'A'); break; 1288 + CASE_TEST(abs); EXPECT_EQ(1, abs(-10), 10); break; 1289 + CASE_TEST(abs_noop); EXPECT_EQ(1, abs(10), 10); break; 1290 + CASE_TEST(difftime); EXPECT_ZR(1, test_difftime()); break; 1520 1291 1521 1292 case __LINE__: 1522 1293 return ret; /* must be last */ ··· 1538 1295 1539 1296 static int expect_vfprintf(int llen, int c, const char *expected, const char *fmt, ...) 1540 1297 { 1541 - int ret, pipefd[2]; 1542 - ssize_t w, r; 1543 1298 char buf[100]; 1544 - FILE *memfile; 1545 1299 va_list args; 1300 + ssize_t w; 1301 + int ret; 1546 1302 1547 - ret = pipe(pipefd); 1548 - if (ret == -1) { 1549 - llen += printf(" pipe() != %s", strerror(errno)); 1550 - result(llen, FAIL); 1551 - return 1; 1552 - } 1553 - 1554 - memfile = fdopen(pipefd[1], "w"); 1555 - if (!memfile) { 1556 - result(llen, FAIL); 1557 - return 1; 1558 - } 1559 1303 1560 1304 va_start(args, fmt); 1561 - w = vfprintf(memfile, fmt, args); 1305 + /* Only allow writing 21 bytes, to test truncation */ 1306 + w = vsnprintf(buf, 21, fmt, args); 1562 1307 va_end(args); 1563 1308 1564 1309 if (w != c) { ··· 1555 1324 return 1; 1556 1325 } 1557 1326 1558 - fclose(memfile); 1559 - 1560 - r = read(pipefd[0], buf, sizeof(buf) - 1); 1561 - 1562 - if (r != w) { 1563 - llen += printf(" written(%d) != read(%d)", (int)w, (int)r); 1564 - result(llen, FAIL); 1565 - return 1; 1566 - } 1567 - 1568 - buf[r] = '\0'; 1569 1327 llen += printf(" \"%s\" = \"%s\"", expected, buf); 1570 1328 ret = strncmp(expected, buf, c); 1571 1329 ··· 1629 1409 return 0; 1630 1410 } 1631 1411 1632 - static int run_vfprintf(int min, int max) 1412 + int test_strerror(void) 1413 + { 1414 + char buf[100]; 1415 + ssize_t ret; 1416 + 1417 + memset(buf, 'A', sizeof(buf)); 1418 + 1419 + errno = EINVAL; 1420 + ret = snprintf(buf, sizeof(buf), "%m"); 1421 + if (is_nolibc) { 1422 + if (ret < 6 || memcmp(buf, "errno=", 6)) 1423 + return 1; 1424 + } 1425 + 1426 + return 0; 1427 + } 1428 + 1429 + static int run_printf(int min, int max) 1633 1430 { 1634 1431 int test; 1635 1432 int ret = 0; ··· 1667 1430 CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; 1668 1431 CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break; 1669 1432 CASE_TEST(pointer); EXPECT_VFPRINTF(3, "0x1", "%p", (void *) 0x1); break; 1433 + CASE_TEST(uintmax_t); EXPECT_VFPRINTF(20, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; 1434 + CASE_TEST(intmax_t); EXPECT_VFPRINTF(20, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; 1435 + CASE_TEST(truncation); EXPECT_VFPRINTF(25, "01234567890123456789", "%s", "0123456789012345678901234"); break; 1436 + CASE_TEST(string_width); EXPECT_VFPRINTF(10, " 1", "%10s", "1"); break; 1437 + CASE_TEST(number_width); EXPECT_VFPRINTF(10, " 1", "%10d", 1); break; 1438 + CASE_TEST(width_trunc); EXPECT_VFPRINTF(25, " ", "%25d", 1); break; 1670 1439 CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; 1440 + CASE_TEST(strerror); EXPECT_ZR(1, test_strerror()); break; 1671 1441 case __LINE__: 1672 1442 return ret; /* must be last */ 1673 1443 /* note: do not set any defaults so as to permit holes above */ ··· 1683 1439 return ret; 1684 1440 } 1685 1441 1442 + __attribute__((no_sanitize("undefined"))) 1686 1443 static int smash_stack(void) 1687 1444 { 1688 1445 char buf[100]; ··· 1700 1455 int max __attribute__((unused))) 1701 1456 { 1702 1457 pid_t pid; 1703 - int llen = 0, ret; 1704 - siginfo_t siginfo = {}; 1458 + int llen = 0, status; 1705 1459 struct rlimit rlimit = { 0, 0 }; 1706 1460 1707 1461 llen += printf("0 -fstackprotector "); ··· 1738 1494 return 1; 1739 1495 1740 1496 default: 1741 - ret = waitid(P_PID, pid, &siginfo, WEXITED); 1497 + pid = waitpid(pid, &status, 0); 1742 1498 1743 - if (ret != 0 || siginfo.si_signo != SIGCHLD || 1744 - siginfo.si_code != CLD_KILLED || siginfo.si_status != SIGABRT) { 1745 - llen += printf("waitid()"); 1499 + if (pid == -1 || !WIFSIGNALED(status) || WTERMSIG(status) != SIGABRT) { 1500 + llen += printf("waitpid()"); 1746 1501 result(llen, FAIL); 1747 1502 return 1; 1748 1503 } ··· 1813 1570 { .name = "startup", .func = run_startup }, 1814 1571 { .name = "syscall", .func = run_syscall }, 1815 1572 { .name = "stdlib", .func = run_stdlib }, 1816 - { .name = "vfprintf", .func = run_vfprintf }, 1573 + { .name = "printf", .func = run_printf }, 1817 1574 { .name = "protection", .func = run_protection }, 1818 1575 { 0 } 1819 1576 };
+7
tools/testing/selftests/nolibc/run-tests.sh
··· 25 25 riscv32 riscv64 26 26 s390x s390 27 27 loongarch 28 + sparc32 sparc64 29 + m68k 28 30 ) 29 31 archs="${all_archs[@]}" 30 32 ··· 113 111 loongarch) echo loongarch64;; 114 112 mips*) echo mips;; 115 113 s390*) echo s390;; 114 + sparc*) echo sparc64;; 116 115 *) echo "$1";; 117 116 esac 118 117 } ··· 184 181 esac 185 182 printf '%-15s' "$arch:" 186 183 if [ "$arch" = "s390" ] && ([ "$llvm" = "1" ] || [ "$test_mode" = "user" ]); then 184 + echo "Unsupported configuration" 185 + return 186 + fi 187 + if [ "$arch" = "m68k" ] && [ "$llvm" = "1" ]; then 187 188 echo "Unsupported configuration" 188 189 return 189 190 fi