From 5f40eef1c734042548f491e35acab1a2e4d867e1 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 24 Mar 2025 23:01:28 +0100 Subject: selftests/nolibc: drop unnecessary sys/io.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The include of sys/io.h is not necessary anymore since commit 67eb617a8e1e ("selftests/nolibc: simplify call to ioperm"). It's existence is also problematic as the header does not exist on all architectures. Reported-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Weißschuh Acked-by: Shuah Khan Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250324-nolibc-ioperm-v1-1-8a7cfb2876ae@weissschuh.net --- tools/testing/selftests/nolibc/nolibc-test.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 5884a891c491..7a60b6ac1457 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -16,7 +16,6 @@ #ifndef _NOLIBC_STDIO_H /* standard libcs need more includes */ #include -#include #include #include #include -- cgit v1.2.3 From cdbf0f199e1f9ecb1af3c0ea8cb956d010447049 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Wed, 2 Apr 2025 23:38:59 +0200 Subject: selftests/nolibc: drop dependency from sysroot to defconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The creation of the sysroot does not require a kernel configuration. Drop the dependency. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250402-nolibc-nolibc-test-native-v1-1-62f2f8585220@weissschuh.net --- tools/testing/selftests/nolibc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 58bcbbd029bc..34d01e473c01 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -232,7 +232,7 @@ all: run sysroot: sysroot/$(ARCH)/include -sysroot/$(ARCH)/include: | defconfig +sysroot/$(ARCH)/include: $(Q)rm -rf sysroot/$(ARCH) sysroot/sysroot $(QUIET_MKDIR)mkdir -p sysroot $(Q)$(MAKE) -C $(srctree) outputmakefile -- cgit v1.2.3 From fd293cb81a7fe57f1314006c438ee67907b46f88 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Wed, 2 Apr 2025 23:39:00 +0200 Subject: selftests/nolibc: only consider XARCH for CFLAGS when requested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If no explicit XARCH is specified, use the toolchains default. Suggested-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/lkml/20250326205434.bPx_kVUx@breakpoint.cc/ Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250402-nolibc-nolibc-test-native-v1-2-62f2f8585220@weissschuh.net --- tools/testing/selftests/nolibc/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 34d01e473c01..89ee265f7467 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -174,10 +174,13 @@ CFLAGS_s390x = -m64 CFLAGS_s390 = -m31 CFLAGS_mips32le = -EL -mabi=32 -fPIC CFLAGS_mips32be = -EB -mabi=32 +ifeq ($(origin XARCH),command line) +CFLAGS_XARCH = $(CFLAGS_$(XARCH)) +endif CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ $(call cc-option,-fno-stack-protector) $(call cc-option,-Wmissing-prototypes) \ - $(CFLAGS_$(XARCH)) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_EXTRA) + $(CFLAGS_XARCH) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_EXTRA) LDFLAGS := LIBGCC := -lgcc -- cgit v1.2.3 From 8e1930296f921d3246f331c394c0516feb36993a Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Wed, 26 Feb 2025 15:05:17 +0100 Subject: tools/nolibc: Add support for SPARC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for 32bit and 64bit SPARC to nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Tested-by: Sebastian Andrzej Siewior # UltraSparc T4 (Niagara4) Link: https://lore.kernel.org/lkml/20250322-nolibc-sparc-v2-1-89af018c6296@weissschuh.net/ --- tools/include/nolibc/arch-sparc.h | 191 ++++++++++++++++++++++++++++ tools/include/nolibc/arch.h | 2 + tools/testing/selftests/nolibc/Makefile | 11 ++ tools/testing/selftests/nolibc/run-tests.sh | 2 + 4 files changed, 206 insertions(+) create mode 100644 tools/include/nolibc/arch-sparc.h (limited to 'tools/testing') diff --git a/tools/include/nolibc/arch-sparc.h b/tools/include/nolibc/arch-sparc.h new file mode 100644 index 000000000000..1435172f3dfe --- /dev/null +++ b/tools/include/nolibc/arch-sparc.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * SPARC (32bit and 64bit) specific definitions for NOLIBC + * Copyright (C) 2025 Thomas Weißschuh + */ + +#ifndef _NOLIBC_ARCH_SPARC_H +#define _NOLIBC_ARCH_SPARC_H + +#include + +#include "compiler.h" +#include "crt.h" + +/* + * Syscalls for SPARC: + * - registers are native word size + * - syscall number is passed in g1 + * - arguments are in o0-o5 + * - the system call is performed by calling a trap instruction + * - syscall return value is in o0 + * - syscall error flag is in the carry bit of the processor status register + */ + +#ifdef __arch64__ + +#define _NOLIBC_SYSCALL "t 0x6d\n" \ + "bcs,a %%xcc, 1f\n" \ + "sub %%g0, %%o0, %%o0\n" \ + "1:\n" + +#else + +#define _NOLIBC_SYSCALL "t 0x10\n" \ + "bcs,a 1f\n" \ + "sub %%g0, %%o0, %%o0\n" \ + "1:\n" + +#endif /* __arch64__ */ + +#define my_syscall0(num) \ +({ \ + register long _num __asm__ ("g1") = (num); \ + register long _arg1 __asm__ ("o0"); \ + \ + __asm__ volatile ( \ + _NOLIBC_SYSCALL \ + : "+r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + register long _num __asm__ ("g1") = (num); \ + register long _arg1 __asm__ ("o0") = (long)(arg1); \ + \ + __asm__ volatile ( \ + _NOLIBC_SYSCALL \ + : "+r"(_arg1) \ + : "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num __asm__ ("g1") = (num); \ + register long _arg1 __asm__ ("o0") = (long)(arg1); \ + register long _arg2 __asm__ ("o1") = (long)(arg2); \ + \ + __asm__ volatile ( \ + _NOLIBC_SYSCALL \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ ("g1") = (num); \ + register long _arg1 __asm__ ("o0") = (long)(arg1); \ + register long _arg2 __asm__ ("o1") = (long)(arg2); \ + register long _arg3 __asm__ ("o2") = (long)(arg3); \ + \ + __asm__ volatile ( \ + _NOLIBC_SYSCALL \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num __asm__ ("g1") = (num); \ + register long _arg1 __asm__ ("o0") = (long)(arg1); \ + register long _arg2 __asm__ ("o1") = (long)(arg2); \ + register long _arg3 __asm__ ("o2") = (long)(arg3); \ + register long _arg4 __asm__ ("o3") = (long)(arg4); \ + \ + __asm__ volatile ( \ + _NOLIBC_SYSCALL \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ ("g1") = (num); \ + register long _arg1 __asm__ ("o0") = (long)(arg1); \ + register long _arg2 __asm__ ("o1") = (long)(arg2); \ + register long _arg3 __asm__ ("o2") = (long)(arg3); \ + register long _arg4 __asm__ ("o3") = (long)(arg4); \ + register long _arg5 __asm__ ("o4") = (long)(arg5); \ + \ + __asm__ volatile ( \ + _NOLIBC_SYSCALL \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("g1") = (num); \ + register long _arg1 __asm__ ("o0") = (long)(arg1); \ + register long _arg2 __asm__ ("o1") = (long)(arg2); \ + register long _arg3 __asm__ ("o2") = (long)(arg3); \ + register long _arg4 __asm__ ("o3") = (long)(arg4); \ + register long _arg5 __asm__ ("o4") = (long)(arg5); \ + register long _arg6 __asm__ ("o5") = (long)(arg6); \ + \ + __asm__ volatile ( \ + _NOLIBC_SYSCALL \ + : "+r"(_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +/* startup code */ +void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) +{ + __asm__ volatile ( + /* + * Save argc pointer to o0, as arg1 of _start_c. + * Account for the window save area, which is 16 registers wide. + */ +#ifdef __arch64__ + "add %sp, 128 + 2047, %o0\n" /* on sparc64 / v9 the stack is offset by 2047 */ +#else + "add %sp, 64, %o0\n" +#endif + "b,a _start_c\n" /* transfer to c runtime */ + ); + __nolibc_entrypoint_epilogue(); +} + +static pid_t getpid(void); + +static __attribute__((unused)) +pid_t sys_fork(void) +{ + pid_t parent, ret; + + parent = getpid(); + ret = my_syscall0(__NR_fork); + + /* The syscall returns the parent pid in the child instead of 0 */ + if (ret == parent) + return 0; + else + return ret; +} +#define sys_fork sys_fork + +#endif /* _NOLIBC_ARCH_SPARC_H */ diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h index 8a2c143c0fba..b8c1da9a88d1 100644 --- a/tools/include/nolibc/arch.h +++ b/tools/include/nolibc/arch.h @@ -33,6 +33,8 @@ #include "arch-s390.h" #elif defined(__loongarch__) #include "arch-loongarch.h" +#elif defined(__sparc__) +#include "arch-sparc.h" #else #error Unsupported Architecture #endif diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 89ee265f7467..aa05c1faac20 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -56,6 +56,8 @@ ARCH_mips32be = mips ARCH_riscv32 = riscv ARCH_riscv64 = riscv ARCH_s390x = s390 +ARCH_sparc32 = sparc +ARCH_sparc64 = sparc ARCH := $(or $(ARCH_$(XARCH)),$(XARCH)) # kernel image names by architecture @@ -76,6 +78,8 @@ IMAGE_riscv64 = arch/riscv/boot/Image IMAGE_s390x = arch/s390/boot/bzImage IMAGE_s390 = arch/s390/boot/bzImage IMAGE_loongarch = arch/loongarch/boot/vmlinuz.efi +IMAGE_sparc32 = arch/sparc/boot/image +IMAGE_sparc64 = arch/sparc/boot/image IMAGE = $(objtree)/$(IMAGE_$(XARCH)) IMAGE_NAME = $(notdir $(IMAGE)) @@ -97,6 +101,8 @@ DEFCONFIG_riscv64 = defconfig DEFCONFIG_s390x = defconfig DEFCONFIG_s390 = defconfig compat.config DEFCONFIG_loongarch = defconfig +DEFCONFIG_sparc32 = sparc32_defconfig +DEFCONFIG_sparc64 = sparc64_defconfig DEFCONFIG = $(DEFCONFIG_$(XARCH)) EXTRACONFIG = $(EXTRACONFIG_$(XARCH)) @@ -122,6 +128,8 @@ QEMU_ARCH_riscv64 = riscv64 QEMU_ARCH_s390x = s390x QEMU_ARCH_s390 = s390x QEMU_ARCH_loongarch = loongarch64 +QEMU_ARCH_sparc32 = sparc +QEMU_ARCH_sparc64 = sparc64 QEMU_ARCH = $(QEMU_ARCH_$(XARCH)) QEMU_ARCH_USER_ppc64le = ppc64le @@ -152,6 +160,8 @@ QEMU_ARGS_riscv64 = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_T QEMU_ARGS_s390x = -M s390-ccw-virtio -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_s390 = -M s390-ccw-virtio -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" +QEMU_ARGS_sparc32 = -M SS-5 -m 256M -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" +QEMU_ARGS_sparc64 = -M sun4u -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA) # OUTPUT is only set when run from the main makefile, otherwise @@ -174,6 +184,7 @@ CFLAGS_s390x = -m64 CFLAGS_s390 = -m31 CFLAGS_mips32le = -EL -mabi=32 -fPIC CFLAGS_mips32be = -EB -mabi=32 +CFLAGS_sparc32 = $(call cc-option,-m32) ifeq ($(origin XARCH),command line) CFLAGS_XARCH = $(CFLAGS_$(XARCH)) endif diff --git a/tools/testing/selftests/nolibc/run-tests.sh b/tools/testing/selftests/nolibc/run-tests.sh index 0299a0912d40..040956a9f5b8 100755 --- a/tools/testing/selftests/nolibc/run-tests.sh +++ b/tools/testing/selftests/nolibc/run-tests.sh @@ -25,6 +25,7 @@ all_archs=( riscv32 riscv64 s390x s390 loongarch + sparc32 sparc64 ) archs="${all_archs[@]}" @@ -111,6 +112,7 @@ crosstool_arch() { loongarch) echo loongarch64;; mips*) echo mips;; s390*) echo s390;; + sparc*) echo sparc64;; *) echo "$1";; esac } -- cgit v1.2.3 From 6478251f95121ae4b66e987c98482e0d0b149e5d Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sat, 19 Apr 2025 12:46:23 +0200 Subject: selftests/nolibc: disable ubsan for smash_stack() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit smash_stack() intentionally crashes. Prevent UBSAN from tripping over it. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250419-nolibc-ubsan-v2-6-060b8a016917@weissschuh.net --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7a60b6ac1457..b176a706609b 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1438,6 +1438,7 @@ static int run_vfprintf(int min, int max) return ret; } +__attribute__((no_sanitize("undefined"))) static int smash_stack(void) { char buf[100]; -- cgit v1.2.3 From 8509b5c9fa981f7e17874605af86d26159310d3c Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Sat, 19 Apr 2025 12:46:24 +0200 Subject: selftests/nolibc: enable UBSAN if available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UBSAN detects undefined behaviour at runtime. To avoid introduction of new UB, enable UBSAN for nolibc-test. By signalling detected errors through traps no runtime dependency is necessary. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250419-nolibc-ubsan-v2-7-060b8a016917@weissschuh.net --- tools/testing/selftests/nolibc/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index aa05c1faac20..94f3e8be7a68 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -189,9 +189,10 @@ ifeq ($(origin XARCH),command line) CFLAGS_XARCH = $(CFLAGS_$(XARCH)) endif CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) +CFLAGS_SANITIZER ?= $(call cc-option,-fsanitize=undefined -fsanitize-trap=all) CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ $(call cc-option,-fno-stack-protector) $(call cc-option,-Wmissing-prototypes) \ - $(CFLAGS_XARCH) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_EXTRA) + $(CFLAGS_XARCH) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_SANITIZER) $(CFLAGS_EXTRA) LDFLAGS := LIBGCC := -lgcc -- cgit v1.2.3 From 4c99fbc6a06f56e266f60f5f24d0cfd8311b2c09 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 11 Apr 2025 11:00:38 +0200 Subject: tools/nolibc: handle intmax_t/uintmax_t in printf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In nolibc intmax_t and uintmax_t are always the same as (unsigned) long long/uint64_t as 128bit numbers are not supported. Even libcs that do support 128bit numbers often fix intmax_t to 64bit as it is used in ABIs and any change would break those. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau --- tools/include/nolibc/stdio.h | 2 ++ tools/testing/selftests/nolibc/nolibc-test.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index a403351dbf60..b32b8b794015 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -286,6 +286,8 @@ int vfprintf(FILE *stream, const char *fmt, va_list args) if (c == 'l') { /* long format prefix, maintain the escape */ lpref++; + } else if (c == 'j') { + lpref = 2; } escape = 1; goto do_escape; diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index b176a706609b..143dddfcd01a 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1429,6 +1429,8 @@ static int run_vfprintf(int min, int max) CASE_TEST(char); EXPECT_VFPRINTF(1, "c", "%c", 'c'); break; CASE_TEST(hex); EXPECT_VFPRINTF(1, "f", "%x", 0xf); break; CASE_TEST(pointer); EXPECT_VFPRINTF(3, "0x1", "%p", (void *) 0x1); break; + CASE_TEST(uintmax_t); EXPECT_VFPRINTF(20, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; + CASE_TEST(intmax_t); EXPECT_VFPRINTF(20, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; case __LINE__: return ret; /* must be last */ -- cgit v1.2.3 From 9b070d97d9e52195c3a2ee084fdd7c45b6b35adf Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 11 Apr 2025 11:00:42 +0200 Subject: tools/nolibc: add tolower() and toupper() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kselftest harness uses these functions. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau --- tools/include/nolibc/string.h | 17 +++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 5 +++++ 2 files changed, 22 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index ba84ab700e30..f0d335f0e467 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -289,6 +289,23 @@ char *strrchr(const char *s, int c) return (char *)ret; } +static __attribute__((unused)) +int tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + return c - 'A' + 'a'; + return c; +} + +static __attribute__((unused)) +int toupper(int c) +{ + if (c >= 'a' && c <= 'z') + return c - 'a' + 'A'; + return c; +} + + /* make sure to include all global symbols */ #include "nolibc.h" diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 143dddfcd01a..b6f736fdeadf 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -39,6 +39,7 @@ #include #include #include +#include #endif #endif @@ -1280,6 +1281,10 @@ int run_stdlib(int min, int max) CASE_TEST(strerror_EINVAL); EXPECT_STREQ(is_nolibc, strerror(EINVAL), "errno=22"); break; CASE_TEST(strerror_int_max); EXPECT_STREQ(is_nolibc, strerror(INT_MAX), "errno=2147483647"); break; CASE_TEST(strerror_int_min); EXPECT_STREQ(is_nolibc, strerror(INT_MIN), "errno=-2147483648"); break; + CASE_TEST(tolower); EXPECT_EQ(1, tolower('A'), 'a'); break; + CASE_TEST(tolower_noop); EXPECT_EQ(1, tolower('a'), 'a'); break; + CASE_TEST(toupper); EXPECT_EQ(1, toupper('a'), 'A'); break; + CASE_TEST(toupper_noop); EXPECT_EQ(1, toupper('A'), 'A'); break; case __LINE__: return ret; /* must be last */ -- cgit v1.2.3 From 4175b5584510faa8acbfa98103781c36780d5a79 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 11 Apr 2025 11:00:46 +0200 Subject: Revert "selftests/nolibc: use waitid() over waitpid()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nolibc's waitpid() now uses the waitid() syscall internally. This removes the original reasoning for the reverted commit as waitpid() is now available on all platforms and has an easier interface. Switch back to waitpid(). This reverts commit a0bc8947ac731ff95a56e0c1737e69e8c56d5b78. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau --- tools/testing/selftests/nolibc/nolibc-test.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index b6f736fdeadf..64f88b492029 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1462,8 +1462,7 @@ static int run_protection(int min __attribute__((unused)), int max __attribute__((unused))) { pid_t pid; - int llen = 0, ret; - siginfo_t siginfo = {}; + int llen = 0, status; struct rlimit rlimit = { 0, 0 }; llen += printf("0 -fstackprotector "); @@ -1501,11 +1500,10 @@ static int run_protection(int min __attribute__((unused)), return 1; default: - ret = waitid(P_PID, pid, &siginfo, WEXITED); + pid = waitpid(pid, &status, 0); - if (ret != 0 || siginfo.si_signo != SIGCHLD || - siginfo.si_code != CLD_KILLED || siginfo.si_status != SIGABRT) { - llen += printf("waitid()"); + if (pid == -1 || !WIFSIGNALED(status) || WTERMSIG(status) != SIGABRT) { + llen += printf("waitpid()"); result(llen, FAIL); return 1; } -- cgit v1.2.3 From c685cd6db59cc4557c93538677a8bdaa05f49fbc Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 11 Apr 2025 11:00:52 +0200 Subject: selftests/nolibc: use snprintf() for printf tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With a proper snprintf() implementation in place, the ugly pipe usage is not necessary anymore. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau --- tools/testing/selftests/nolibc/nolibc-test.c | 30 +++------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 64f88b492029..1874199b2cf6 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1299,27 +1299,14 @@ int run_stdlib(int min, int max) static int expect_vfprintf(int llen, int c, const char *expected, const char *fmt, ...) { - int ret, pipefd[2]; - ssize_t w, r; char buf[100]; - FILE *memfile; va_list args; + ssize_t w; + int ret; - ret = pipe(pipefd); - if (ret == -1) { - llen += printf(" pipe() != %s", strerror(errno)); - result(llen, FAIL); - return 1; - } - - memfile = fdopen(pipefd[1], "w"); - if (!memfile) { - result(llen, FAIL); - return 1; - } va_start(args, fmt); - w = vfprintf(memfile, fmt, args); + w = vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (w != c) { @@ -1328,17 +1315,6 @@ static int expect_vfprintf(int llen, int c, const char *expected, const char *fm return 1; } - fclose(memfile); - - r = read(pipefd[0], buf, sizeof(buf) - 1); - - if (r != w) { - llen += printf(" written(%d) != read(%d)", (int)w, (int)r); - result(llen, FAIL); - return 1; - } - - buf[r] = '\0'; llen += printf(" \"%s\" = \"%s\"", expected, buf); ret = strncmp(expected, buf, c); -- cgit v1.2.3 From 6311e4893ad204695473caf167e22ebf23cb8f5d Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 11 Apr 2025 11:00:53 +0200 Subject: selftests/nolibc: rename vfprintf test suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the addition of snprintf() and its usage in nolibc-test, the name of the "vfprintf" test suite is not accurate anymore. Rename the suite to be more generic. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau --- tools/testing/selftests/nolibc/nolibc-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 1874199b2cf6..5fb4319545d5 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1389,7 +1389,7 @@ static int test_scanf(void) return 0; } -static int run_vfprintf(int min, int max) +static int run_printf(int min, int max) { int test; int ret = 0; @@ -1551,7 +1551,7 @@ static const struct test test_names[] = { { .name = "startup", .func = run_startup }, { .name = "syscall", .func = run_syscall }, { .name = "stdlib", .func = run_stdlib }, - { .name = "vfprintf", .func = run_vfprintf }, + { .name = "printf", .func = run_printf }, { .name = "protection", .func = run_protection }, { 0 } }; -- cgit v1.2.3 From b0bd7760df94714f78ccf98b3aa612ed71e48770 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 11 Apr 2025 11:00:54 +0200 Subject: selftests/nolibc: add test for snprintf() truncation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have a proper snprintf() implementation, make sure truncation is handled properly. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau --- tools/testing/selftests/nolibc/nolibc-test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 5fb4319545d5..33cd64a1b768 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1306,7 +1306,8 @@ static int expect_vfprintf(int llen, int c, const char *expected, const char *fm va_start(args, fmt); - w = vsnprintf(buf, sizeof(buf), fmt, args); + /* Only allow writing 21 bytes, to test truncation */ + w = vsnprintf(buf, 21, fmt, args); va_end(args); if (w != c) { @@ -1412,6 +1413,7 @@ static int run_printf(int min, int max) CASE_TEST(pointer); EXPECT_VFPRINTF(3, "0x1", "%p", (void *) 0x1); break; CASE_TEST(uintmax_t); EXPECT_VFPRINTF(20, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; CASE_TEST(intmax_t); EXPECT_VFPRINTF(20, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; + CASE_TEST(truncation); EXPECT_VFPRINTF(25, "01234567890123456789", "%s", "0123456789012345678901234"); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; case __LINE__: return ret; /* must be last */ -- cgit v1.2.3 From e90ce42e81381665dbcedc5fa12e74759ee89639 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Fri, 11 Apr 2025 11:00:55 +0200 Subject: tools/nolibc: implement width padding in printf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit printf can pad each argument to a certain width. Implement this for compatibility with the kselftest harness. Currently only padding with spaces is supported. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau --- tools/include/nolibc/stdio.h | 17 ++++++++++++++++- tools/testing/selftests/nolibc/nolibc-test.c | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 46bd90f96d65..fb0417477759 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -220,7 +220,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char { char escape, lpref, c; unsigned long long v; - unsigned int written; + unsigned int written, width; size_t len, ofs, w; char tmpbuf[21]; const char *outstr; @@ -228,10 +228,20 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char written = ofs = escape = lpref = 0; while (1) { c = fmt[ofs++]; + width = 0; if (escape) { /* we're in an escape sequence, ofs == 1 */ escape = 0; + + /* width */ + while (c >= '0' && c <= '9') { + width *= 10; + width += c - '0'; + + c = fmt[ofs++]; + } + if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') { char *out = tmpbuf; @@ -309,6 +319,11 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char if (n) { w = len < n ? len : n; n -= w; + while (width-- > w) { + if (cb(state, " ", 1) != 0) + break; + written += 1; + } if (cb(state, outstr, w) != 0) break; } diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 33cd64a1b768..1ad0db92f0ed 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1414,6 +1414,9 @@ static int run_printf(int min, int max) CASE_TEST(uintmax_t); EXPECT_VFPRINTF(20, "18446744073709551615", "%ju", 0xffffffffffffffffULL); break; CASE_TEST(intmax_t); EXPECT_VFPRINTF(20, "-9223372036854775807", "%jd", 0x8000000000000001LL); break; CASE_TEST(truncation); EXPECT_VFPRINTF(25, "01234567890123456789", "%s", "0123456789012345678901234"); break; + CASE_TEST(string_width); EXPECT_VFPRINTF(10, " 1", "%10s", "1"); break; + CASE_TEST(number_width); EXPECT_VFPRINTF(10, " 1", "%10d", 1); break; + CASE_TEST(width_trunc); EXPECT_VFPRINTF(25, " ", "%25d", 1); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; case __LINE__: return ret; /* must be last */ -- cgit v1.2.3 From 443c6467fcd65d10506b473cc6b187f95bcb2b22 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 24 Apr 2025 13:48:13 +0200 Subject: selftests/nolibc: always run nolibc header check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent regressions of issues validates by the header check by always running it together with the nolibc selftests. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250424-nolibc-header-check-v1-3-011576b6ed6f@linutronix.de --- tools/testing/selftests/nolibc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 94f3e8be7a68..d17750761d9f 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -251,7 +251,7 @@ sysroot/$(ARCH)/include: $(Q)rm -rf sysroot/$(ARCH) sysroot/sysroot $(QUIET_MKDIR)mkdir -p sysroot $(Q)$(MAKE) -C $(srctree) outputmakefile - $(Q)$(MAKE) -C $(srctree)/tools/include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone + $(Q)$(MAKE) -C $(srctree)/tools/include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone headers_check $(Q)mv sysroot/sysroot sysroot/$(ARCH) ifneq ($(NOLIBC_SYSROOT),0) -- cgit v1.2.3 From 66a4f9bb1e895aa64f0e786f4cd9864929242e4f Mon Sep 17 00:00:00 2001 From: Daniel Palmer Date: Sun, 27 Apr 2025 07:47:38 +0900 Subject: tools/nolibc: Add m68k support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add nolibc support for m68k. Should be helpful for nommu where linking libc can bloat even hello world to the point where you get an OOM just trying to load it. Signed-off-by: Daniel Palmer Link: https://lore.kernel.org/r/20250426224738.284874-1-daniel@0x0f.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/arch-m68k.h | 141 ++++++++++++++++++++++++++++ tools/include/nolibc/arch.h | 2 + tools/testing/selftests/nolibc/Makefile | 5 + tools/testing/selftests/nolibc/run-tests.sh | 5 + 4 files changed, 153 insertions(+) create mode 100644 tools/include/nolibc/arch-m68k.h (limited to 'tools/testing') diff --git a/tools/include/nolibc/arch-m68k.h b/tools/include/nolibc/arch-m68k.h new file mode 100644 index 000000000000..6dac1845f298 --- /dev/null +++ b/tools/include/nolibc/arch-m68k.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * m68k specific definitions for NOLIBC + * Copyright (C) 2025 Daniel Palmer + * + * Roughly based on one or more of the other arch files. + * + */ + +#ifndef _NOLIBC_ARCH_M68K_H +#define _NOLIBC_ARCH_M68K_H + +#include "compiler.h" +#include "crt.h" + +#define _NOLIBC_SYSCALL_CLOBBERLIST "memory" + +#define my_syscall0(num) \ +({ \ + register long _num __asm__ ("d0") = (num); \ + \ + __asm__ volatile ( \ + "trap #0\n" \ + : "+r"(_num) \ + : "r"(_num) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _num; \ +}) + +#define my_syscall1(num, arg1) \ +({ \ + register long _num __asm__ ("d0") = (num); \ + register long _arg1 __asm__ ("d1") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "trap #0\n" \ + : "+r"(_num) \ + : "r"(_arg1) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _num; \ +}) + +#define my_syscall2(num, arg1, arg2) \ +({ \ + register long _num __asm__ ("d0") = (num); \ + register long _arg1 __asm__ ("d1") = (long)(arg1); \ + register long _arg2 __asm__ ("d2") = (long)(arg2); \ + \ + __asm__ volatile ( \ + "trap #0\n" \ + : "+r"(_num) \ + : "r"(_arg1), "r"(_arg2) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _num; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ ("d0") = (num); \ + register long _arg1 __asm__ ("d1") = (long)(arg1); \ + register long _arg2 __asm__ ("d2") = (long)(arg2); \ + register long _arg3 __asm__ ("d3") = (long)(arg3); \ + \ + __asm__ volatile ( \ + "trap #0\n" \ + : "+r"(_num) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _num; \ +}) + +#define my_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num __asm__ ("d0") = (num); \ + register long _arg1 __asm__ ("d1") = (long)(arg1); \ + register long _arg2 __asm__ ("d2") = (long)(arg2); \ + register long _arg3 __asm__ ("d3") = (long)(arg3); \ + register long _arg4 __asm__ ("d4") = (long)(arg4); \ + \ + __asm__ volatile ( \ + "trap #0\n" \ + : "+r" (_num) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _num; \ +}) + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ ("d0") = (num); \ + register long _arg1 __asm__ ("d1") = (long)(arg1); \ + register long _arg2 __asm__ ("d2") = (long)(arg2); \ + register long _arg3 __asm__ ("d3") = (long)(arg3); \ + register long _arg4 __asm__ ("d4") = (long)(arg4); \ + register long _arg5 __asm__ ("d5") = (long)(arg5); \ + \ + __asm__ volatile ( \ + "trap #0\n" \ + : "+r" (_num) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _num; \ +}) + +#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("d0") = (num); \ + register long _arg1 __asm__ ("d1") = (long)(arg1); \ + register long _arg2 __asm__ ("d2") = (long)(arg2); \ + register long _arg3 __asm__ ("d3") = (long)(arg3); \ + register long _arg4 __asm__ ("d4") = (long)(arg4); \ + register long _arg5 __asm__ ("d5") = (long)(arg5); \ + register long _arg6 __asm__ ("a0") = (long)(arg6); \ + \ + __asm__ volatile ( \ + "trap #0\n" \ + : "+r" (_num) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_arg6) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _num; \ +}) + +void _start(void); +void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) +{ + __asm__ volatile ( + "movel %sp, %sp@-\n" + "jsr _start_c\n" + ); + __nolibc_entrypoint_epilogue(); +} + +#endif /* _NOLIBC_ARCH_M68K_H */ diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h index b8c1da9a88d1..d20b2304aac2 100644 --- a/tools/include/nolibc/arch.h +++ b/tools/include/nolibc/arch.h @@ -35,6 +35,8 @@ #include "arch-loongarch.h" #elif defined(__sparc__) #include "arch-sparc.h" +#elif defined(__m68k__) +#include "arch-m68k.h" #else #error Unsupported Architecture #endif diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index d17750761d9f..2671383045db 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -80,6 +80,7 @@ IMAGE_s390 = arch/s390/boot/bzImage IMAGE_loongarch = arch/loongarch/boot/vmlinuz.efi IMAGE_sparc32 = arch/sparc/boot/image IMAGE_sparc64 = arch/sparc/boot/image +IMAGE_m68k = vmlinux IMAGE = $(objtree)/$(IMAGE_$(XARCH)) IMAGE_NAME = $(notdir $(IMAGE)) @@ -103,8 +104,10 @@ DEFCONFIG_s390 = defconfig compat.config DEFCONFIG_loongarch = defconfig DEFCONFIG_sparc32 = sparc32_defconfig DEFCONFIG_sparc64 = sparc64_defconfig +DEFCONFIG_m68k = virt_defconfig DEFCONFIG = $(DEFCONFIG_$(XARCH)) +EXTRACONFIG_m68k = -e CONFIG_BLK_DEV_INITRD EXTRACONFIG = $(EXTRACONFIG_$(XARCH)) # optional tests to run (default = all) @@ -130,6 +133,7 @@ QEMU_ARCH_s390 = s390x QEMU_ARCH_loongarch = loongarch64 QEMU_ARCH_sparc32 = sparc QEMU_ARCH_sparc64 = sparc64 +QEMU_ARCH_m68k = m68k QEMU_ARCH = $(QEMU_ARCH_$(XARCH)) QEMU_ARCH_USER_ppc64le = ppc64le @@ -162,6 +166,7 @@ QEMU_ARGS_s390 = -M s390-ccw-virtio -append "console=ttyS0 panic=-1 $(TEST QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_sparc32 = -M SS-5 -m 256M -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS_sparc64 = -M sun4u -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" +QEMU_ARGS_m68k = -M virt -append "console=ttyGF0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)" QEMU_ARGS = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA) # OUTPUT is only set when run from the main makefile, otherwise diff --git a/tools/testing/selftests/nolibc/run-tests.sh b/tools/testing/selftests/nolibc/run-tests.sh index 040956a9f5b8..8277599e6441 100755 --- a/tools/testing/selftests/nolibc/run-tests.sh +++ b/tools/testing/selftests/nolibc/run-tests.sh @@ -26,6 +26,7 @@ all_archs=( s390x s390 loongarch sparc32 sparc64 + m68k ) archs="${all_archs[@]}" @@ -186,6 +187,10 @@ test_arch() { echo "Unsupported configuration" return fi + if [ "$arch" = "m68k" ] && [ "$llvm" = "1" ]; then + echo "Unsupported configuration" + return + fi mkdir -p "$build_dir" swallow_output "${MAKE[@]}" defconfig -- cgit v1.2.3 From 05b6b2a9efa4b40b7bc1668f887b7d98f719efb1 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:02 +0200 Subject: tools/nolibc: add strstr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-1-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/string.h | 20 ++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 3 +++ 2 files changed, 23 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/string.h b/tools/include/nolibc/string.h index febfd6978966..163a17e7dd38 100644 --- a/tools/include/nolibc/string.h +++ b/tools/include/nolibc/string.h @@ -292,6 +292,26 @@ char *strrchr(const char *s, int c) return (char *)ret; } +static __attribute__((unused)) +char *strstr(const char *haystack, const char *needle) +{ + size_t len_haystack, len_needle; + + len_needle = strlen(needle); + if (!len_needle) + return NULL; + + len_haystack = strlen(haystack); + while (len_haystack >= len_needle) { + if (!memcmp(haystack, needle, len_needle)) + return (char *)haystack; + haystack++; + len_haystack--; + } + + return NULL; +} + static __attribute__((unused)) int tolower(int c) { diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 1ad0db92f0ed..3e15a25ccddf 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1211,6 +1211,9 @@ int run_stdlib(int min, int max) CASE_TEST(strlcpy_2); EXPECT_STRBUFEQ(is_nolibc, strlcpy(buf, "bar", 2), buf, 3, "b"); break; CASE_TEST(strlcpy_3); EXPECT_STRBUFEQ(is_nolibc, strlcpy(buf, "bar", 3), buf, 3, "ba"); break; CASE_TEST(strlcpy_4); EXPECT_STRBUFEQ(is_nolibc, strlcpy(buf, "bar", 4), buf, 3, "bar"); break; + CASE_TEST(strstr_foobar_foo); EXPECT_STREQ(1, strstr("foobar", "foo"), "foobar"); break; + CASE_TEST(strstr_foobar_bar); EXPECT_STREQ(1, strstr("foobar", "bar"), "bar"); break; + CASE_TEST(strstr_foobar_baz); EXPECT_PTREQ(1, strstr("foobar", "baz"), NULL); break; CASE_TEST(memcmp_20_20); EXPECT_EQ(1, memcmp("aaa\x20", "aaa\x20", 4), 0); break; CASE_TEST(memcmp_20_60); EXPECT_LT(1, memcmp("aaa\x20", "aaa\x60", 4), 0); break; CASE_TEST(memcmp_60_20); EXPECT_GT(1, memcmp("aaa\x60", "aaa\x20", 4), 0); break; -- cgit v1.2.3 From 7a7cd445d9275be8e4650d390156595685c3ac03 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:03 +0200 Subject: tools/nolibc: add %m printf format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The %m format can be used to format the current errno. It is non-standard but supported by other commonly used libcs like glibc and musl, so applications do rely on them. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-2-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 7 +++++++ tools/testing/selftests/nolibc/nolibc-test.c | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 8fa98abab212..df5717d59182 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -20,6 +20,8 @@ #include "string.h" #include "compiler.h" +static const char *strerror(int errnum); + #ifndef EOF #define EOF (-1) #endif @@ -292,6 +294,11 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char if (!outstr) outstr="(null)"; } +#ifndef NOLIBC_IGNORE_ERRNO + else if (c == 'm') { + outstr = strerror(errno); + } +#endif /* NOLIBC_IGNORE_ERRNO */ else if (c == '%') { /* queue it verbatim */ continue; diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 3e15a25ccddf..b7440a667db6 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1393,6 +1393,23 @@ static int test_scanf(void) return 0; } +int test_strerror(void) +{ + char buf[100]; + ssize_t ret; + + memset(buf, 'A', sizeof(buf)); + + errno = EINVAL; + ret = snprintf(buf, sizeof(buf), "%m"); + if (is_nolibc) { + if (ret < 6 || memcmp(buf, "errno=", 6)) + return 1; + } + + return 0; +} + static int run_printf(int min, int max) { int test; @@ -1421,6 +1438,7 @@ static int run_printf(int min, int max) CASE_TEST(number_width); EXPECT_VFPRINTF(10, " 1", "%10d", 1); break; CASE_TEST(width_trunc); EXPECT_VFPRINTF(25, " ", "%25d", 1); break; CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break; + CASE_TEST(strerror); EXPECT_ZR(1, test_strerror()); break; case __LINE__: return ret; /* must be last */ /* note: do not set any defaults so as to permit holes above */ -- cgit v1.2.3 From 55175d8659d22bfde30d4a1277328f090d8c0c2f Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:05 +0200 Subject: tools/nolibc: add mremap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-4-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/sys/mman.h | 19 +++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 14 +++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/include/nolibc/sys/mman.h b/tools/include/nolibc/sys/mman.h index 41c7bf45e427..5228751b458c 100644 --- a/tools/include/nolibc/sys/mman.h +++ b/tools/include/nolibc/sys/mman.h @@ -48,6 +48,25 @@ void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) return ret; } +static __attribute__((unused)) +void *sys_mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) +{ + return (void *)my_syscall5(__NR_mremap, old_address, old_size, + new_size, flags, new_address); +} + +static __attribute__((unused)) +void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) +{ + void *ret = sys_mremap(old_address, old_size, new_size, flags, new_address); + + if ((unsigned long)ret >= -4095UL) { + SET_ERRNO(-(long)ret); + ret = MAP_FAILED; + } + return ret; +} + static __attribute__((unused)) int sys_munmap(void *addr, size_t length) { diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index b7440a667db6..abe0ae794208 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -926,7 +926,7 @@ int test_mmap_munmap(void) { int ret, fd, i, page_size; void *mem; - size_t file_size, length; + size_t file_size, length, mem_length; off_t offset, pa_offset; struct stat stat_buf; const char * const files[] = { @@ -966,14 +966,22 @@ int test_mmap_munmap(void) offset = 0; length = file_size - offset; pa_offset = offset & ~(page_size - 1); + mem_length = length + offset - pa_offset; - mem = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_SHARED, fd, pa_offset); + mem = mmap(NULL, mem_length, PROT_READ, MAP_SHARED, fd, pa_offset); if (mem == MAP_FAILED) { ret = 1; goto end; } - ret = munmap(mem, length + offset - pa_offset); + mem = mremap(mem, mem_length, mem_length * 2, MREMAP_MAYMOVE, 0); + if (mem == MAP_FAILED) { + munmap(mem, mem_length); + ret = 1; + goto end; + } + + ret = munmap(mem, mem_length * 2); end: close(fd); -- cgit v1.2.3 From 801f020b5f3d6159826ca38f63cd55e5536b35dd Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:06 +0200 Subject: tools/nolibc: add getrandom() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-5-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/Makefile | 1 + tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/sys/random.h | 34 ++++++++++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 22 ++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 tools/include/nolibc/sys/random.h (limited to 'tools/testing') diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index dda881d934d6..45beeecad52d 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -48,6 +48,7 @@ all_files := \ sys.h \ sys/auxv.h \ sys/mman.h \ + sys/random.h \ sys/stat.h \ sys/syscall.h \ sys/time.h \ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 05a4bd5fba8b..1d2f391ca4d0 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -98,6 +98,7 @@ #include "sys.h" #include "sys/auxv.h" #include "sys/mman.h" +#include "sys/random.h" #include "sys/stat.h" #include "sys/syscall.h" #include "sys/time.h" diff --git a/tools/include/nolibc/sys/random.h b/tools/include/nolibc/sys/random.h new file mode 100644 index 000000000000..8d9749f1c845 --- /dev/null +++ b/tools/include/nolibc/sys/random.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * random definitions for NOLIBC + * Copyright (C) 2025 Thomas Weißschuh + */ + +/* make sure to include all global symbols */ +#include "../nolibc.h" + +#ifndef _NOLIBC_SYS_RANDOM_H +#define _NOLIBC_SYS_RANDOM_H + +#include "../arch.h" +#include "../sys.h" + +#include + +/* + * ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); + */ + +static __attribute__((unused)) +ssize_t sys_getrandom(void *buf, size_t buflen, unsigned int flags) +{ + return my_syscall3(__NR_getrandom, buf, buflen, flags); +} + +static __attribute__((unused)) +ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) +{ + return __sysret(sys_getrandom(buf, buflen, flags)); +} + +#endif /* _NOLIBC_SYS_RANDOM_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index abe0ae794208..df1cb3e62564 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -807,6 +808,26 @@ static int test_dirent(void) return 0; } +int test_getrandom(void) +{ + uint64_t rng = 0; + ssize_t ret; + + ret = getrandom(&rng, sizeof(rng), GRND_NONBLOCK); + if (ret == -1 && errno == EAGAIN) + return 0; /* No entropy available yet */ + + if (ret != sizeof(rng)) + return ret; + + if (!rng) { + errno = EINVAL; + return -1; + } + + return 0; +} + int test_getpagesize(void) { int x = getpagesize(); @@ -1124,6 +1145,7 @@ int run_syscall(int min, int max) CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; CASE_TEST(directories); EXPECT_SYSZR(proc, test_dirent()); break; + CASE_TEST(getrandom); EXPECT_SYSZR(1, test_getrandom()); break; CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break; CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break; CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break; -- cgit v1.2.3 From bf5e8a78beded3503bbcfe86b3094a42ce492556 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:07 +0200 Subject: tools/nolibc: add abs() and friends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-6-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/Makefile | 1 + tools/include/nolibc/math.h | 31 ++++++++++++++++++++++++++++ tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/stdlib.h | 18 ++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 2 ++ 5 files changed, 53 insertions(+) create mode 100644 tools/include/nolibc/math.h (limited to 'tools/testing') diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 45beeecad52d..da4771ef8984 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -35,6 +35,7 @@ all_files := \ fcntl.h \ getopt.h \ limits.h \ + math.h \ nolibc.h \ poll.h \ signal.h \ diff --git a/tools/include/nolibc/math.h b/tools/include/nolibc/math.h new file mode 100644 index 000000000000..9df823ddd412 --- /dev/null +++ b/tools/include/nolibc/math.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * math definitions for NOLIBC + * Copyright (C) 2025 Thomas Weißschuh + */ + +/* make sure to include all global symbols */ +#include "nolibc.h" + +#ifndef _NOLIBC_SYS_MATH_H +#define _NOLIBC_SYS_MATH_H + +static __inline__ +double fabs(double x) +{ + return x >= 0 ? x : -x; +} + +static __inline__ +float fabsf(float x) +{ + return x >= 0 ? x : -x; +} + +static __inline__ +long double fabsl(long double x) +{ + return x >= 0 ? x : -x; +} + +#endif /* _NOLIBC_SYS_MATH_H */ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 1d2f391ca4d0..966302c9e8e1 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -116,6 +116,7 @@ #include "fcntl.h" #include "getopt.h" #include "poll.h" +#include "math.h" /* Used by programs to avoid std includes */ #define NOLIBC diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 4790298f985c..5fd99a480f82 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -32,6 +32,24 @@ static __attribute__((unused)) char itoa_buffer[21]; * As much as possible, please keep functions alphabetically sorted. */ +static __inline__ +int abs(int j) +{ + return j >= 0 ? j : -j; +} + +static __inline__ +long labs(long j) +{ + return j >= 0 ? j : -j; +} + +static __inline__ +long long llabs(long long j) +{ + return j >= 0 ? j : -j; +} + /* must be exported, as it's used by libgcc for various divide functions */ void abort(void); __attribute__((weak,unused,noreturn,section(".text.nolibc_abort"))) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index df1cb3e62564..14a27bc6c83e 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1318,6 +1318,8 @@ int run_stdlib(int min, int max) CASE_TEST(tolower_noop); EXPECT_EQ(1, tolower('a'), 'a'); break; CASE_TEST(toupper); EXPECT_EQ(1, toupper('a'), 'A'); break; CASE_TEST(toupper_noop); EXPECT_EQ(1, toupper('A'), 'A'); break; + CASE_TEST(abs); EXPECT_EQ(1, abs(-10), 10); break; + CASE_TEST(abs_noop); EXPECT_EQ(1, abs(10), 10); break; case __LINE__: return ret; /* must be last */ -- cgit v1.2.3 From 1e10b8534f5af42b7da528c254595f2a0cf4997d Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:08 +0200 Subject: tools/nolibc: add support for access() and faccessat() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-7-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/unistd.h | 28 ++++++++++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 2 ++ 2 files changed, 30 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h index ed253305fdba..25bfc7732ec7 100644 --- a/tools/include/nolibc/unistd.h +++ b/tools/include/nolibc/unistd.h @@ -20,6 +20,34 @@ #define STDOUT_FILENO 1 #define STDERR_FILENO 2 +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +/* + * int access(const char *path, int amode); + * int faccessat(int fd, const char *path, int amode, int flag); + */ + +static __attribute__((unused)) +int sys_faccessat(int fd, const char *path, int amode, int flag) +{ + return my_syscall4(__NR_faccessat, fd, path, amode, flag); +} + +static __attribute__((unused)) +int faccessat(int fd, const char *path, int amode, int flag) +{ + return __sysret(sys_faccessat(fd, path, amode, flag)); +} + +static __attribute__((unused)) +int access(const char *path, int amode) +{ + return faccessat(AT_FDCWD, path, amode, 0); +} + static __attribute__((unused)) int msleep(unsigned int msecs) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 14a27bc6c83e..10db118b8b11 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1112,6 +1112,8 @@ int run_syscall(int min, int max) * test numbers. */ switch (test + __LINE__ + 1) { + CASE_TEST(access); EXPECT_SYSZR(proc, access("/proc/self", R_OK)); break; + CASE_TEST(access_bad); EXPECT_SYSER(proc, access("/proc/self", W_OK), -1, EPERM); break; CASE_TEST(getpid); EXPECT_SYSNE(1, getpid(), -1); break; CASE_TEST(getppid); EXPECT_SYSNE(1, getppid(), -1); break; CASE_TEST(gettid); EXPECT_SYSNE(has_gettid, gettid(), -1); break; -- cgit v1.2.3 From 50647213e115cbf5eb92c56a076af34dcd984174 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:09 +0200 Subject: tools/nolibc: add clock_getres(), clock_gettime() and clock_settime() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-8-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/time.h | 92 ++++++++++++++++++++++++++++ tools/include/nolibc/types.h | 2 + tools/testing/selftests/nolibc/nolibc-test.c | 5 ++ 3 files changed, 99 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/time.h b/tools/include/nolibc/time.h index 9502f9aaf621..7e0b7eac0b7c 100644 --- a/tools/include/nolibc/time.h +++ b/tools/include/nolibc/time.h @@ -15,6 +15,98 @@ #include "types.h" #include "sys.h" +#include + +static __inline__ +void __nolibc_timespec_user_to_kernel(const struct timespec *ts, struct __kernel_timespec *kts) +{ + kts->tv_sec = ts->tv_sec; + kts->tv_nsec = ts->tv_nsec; +} + +static __inline__ +void __nolibc_timespec_kernel_to_user(const struct __kernel_timespec *kts, struct timespec *ts) +{ + ts->tv_sec = kts->tv_sec; + ts->tv_nsec = kts->tv_nsec; +} + +/* + * int clock_getres(clockid_t clockid, struct timespec *res); + * int clock_gettime(clockid_t clockid, struct timespec *tp); + * int clock_settime(clockid_t clockid, const struct timespec *tp); + */ + +static __attribute__((unused)) +int sys_clock_getres(clockid_t clockid, struct timespec *res) +{ +#if defined(__NR_clock_getres) + return my_syscall2(__NR_clock_getres, clockid, res); +#elif defined(__NR_clock_getres_time64) + struct __kernel_timespec kres; + int ret; + + ret = my_syscall2(__NR_clock_getres_time64, clockid, &kres); + if (res) + __nolibc_timespec_kernel_to_user(&kres, res); + return ret; +#else + return __nolibc_enosys(__func__, clockid, res); +#endif +} + +static __attribute__((unused)) +int clock_getres(clockid_t clockid, struct timespec *res) +{ + return __sysret(sys_clock_getres(clockid, res)); +} + +static __attribute__((unused)) +int sys_clock_gettime(clockid_t clockid, struct timespec *tp) +{ +#if defined(__NR_clock_gettime) + return my_syscall2(__NR_clock_gettime, clockid, tp); +#elif defined(__NR_clock_gettime64) + struct __kernel_timespec ktp; + int ret; + + ret = my_syscall2(__NR_clock_gettime64, clockid, &ktp); + if (tp) + __nolibc_timespec_kernel_to_user(&ktp, tp); + return ret; +#else + return __nolibc_enosys(__func__, clockid, tp); +#endif +} + +static __attribute__((unused)) +int clock_gettime(clockid_t clockid, struct timespec *tp) +{ + return __sysret(sys_clock_gettime(clockid, tp)); +} + +static __attribute__((unused)) +int sys_clock_settime(clockid_t clockid, struct timespec *tp) +{ +#if defined(__NR_clock_settime) + return my_syscall2(__NR_clock_settime, clockid, tp); +#elif defined(__NR_clock_settime64) + struct __kernel_timespec ktp; + + __nolibc_timespec_user_to_kernel(tp, &ktp); + return my_syscall2(__NR_clock_settime64, clockid, &ktp); +#else + return __nolibc_enosys(__func__, clockid, tp); +#endif +} + +static __attribute__((unused)) +int clock_settime(clockid_t clockid, struct timespec *tp) +{ + return __sysret(sys_clock_settime(clockid, tp)); +} + + static __attribute__((unused)) time_t time(time_t *tptr) { diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index 70f20519ebf9..ba6867aeeb91 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -187,6 +187,8 @@ struct stat { union { time_t st_ctime; struct timespec st_ctim; }; /* time of last status change */ }; +typedef __kernel_clockid_t clockid_t; + /* WARNING, it only deals with the 4096 first majors and 256 first minors */ #define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff))) #define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff)) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 10db118b8b11..9b8aa41a547b 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -1081,6 +1082,7 @@ int run_syscall(int min, int max) { struct timeval tv; struct timezone tz; + struct timespec ts; struct stat stat_buf; int euid0; int proc; @@ -1114,6 +1116,9 @@ int run_syscall(int min, int max) switch (test + __LINE__ + 1) { CASE_TEST(access); EXPECT_SYSZR(proc, access("/proc/self", R_OK)); break; CASE_TEST(access_bad); EXPECT_SYSER(proc, access("/proc/self", W_OK), -1, EPERM); break; + CASE_TEST(clock_getres); EXPECT_SYSZR(1, clock_getres(CLOCK_MONOTONIC, &ts)); break; + CASE_TEST(clock_gettime); EXPECT_SYSZR(1, clock_gettime(CLOCK_MONOTONIC, &ts)); break; + CASE_TEST(clock_settime); EXPECT_SYSER(1, clock_settime(CLOCK_MONOTONIC, &ts), -1, EINVAL); break; CASE_TEST(getpid); EXPECT_SYSNE(1, getpid(), -1); break; CASE_TEST(getppid); EXPECT_SYSNE(1, getppid(), -1); break; CASE_TEST(gettid); EXPECT_SYSNE(has_gettid, gettid(), -1); break; -- cgit v1.2.3 From fa7bf84486e48c65c5e450248b5d6922352203d1 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:10 +0200 Subject: tools/nolibc: add timer functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-9-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/time.h | 86 ++++++++++++++++++++++++++++ tools/include/nolibc/types.h | 1 + tools/testing/selftests/nolibc/nolibc-test.c | 51 +++++++++++++++++ 3 files changed, 138 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/time.h b/tools/include/nolibc/time.h index 7e0b7eac0b7c..48f602b661b3 100644 --- a/tools/include/nolibc/time.h +++ b/tools/include/nolibc/time.h @@ -15,6 +15,7 @@ #include "types.h" #include "sys.h" +#include #include static __inline__ @@ -120,4 +121,89 @@ time_t time(time_t *tptr) return tv.tv_sec; } + +/* + * int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid); + * int timer_gettime(timer_t timerid, struct itimerspec *curr_value); + * int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value); + */ + +static __attribute__((unused)) +int sys_timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) +{ + return my_syscall3(__NR_timer_create, clockid, evp, timerid); +} + +static __attribute__((unused)) +int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) +{ + return __sysret(sys_timer_create(clockid, evp, timerid)); +} + +static __attribute__((unused)) +int sys_timer_delete(timer_t timerid) +{ + return my_syscall1(__NR_timer_delete, timerid); +} + +static __attribute__((unused)) +int timer_delete(timer_t timerid) +{ + return __sysret(sys_timer_delete(timerid)); +} + +static __attribute__((unused)) +int sys_timer_gettime(timer_t timerid, struct itimerspec *curr_value) +{ +#if defined(__NR_timer_gettime) + return my_syscall2(__NR_timer_gettime, timerid, curr_value); +#elif defined(__NR_timer_gettime64) + struct __kernel_itimerspec kcurr_value; + int ret; + + ret = my_syscall2(__NR_timer_gettime64, timerid, &kcurr_value); + __nolibc_timespec_kernel_to_user(&kcurr_value.it_interval, &curr_value->it_interval); + __nolibc_timespec_kernel_to_user(&kcurr_value.it_value, &curr_value->it_value); + return ret; +#else + return __nolibc_enosys(__func__, timerid, curr_value); +#endif +} + +static __attribute__((unused)) +int timer_gettime(timer_t timerid, struct itimerspec *curr_value) +{ + return __sysret(sys_timer_gettime(timerid, curr_value)); +} + +static __attribute__((unused)) +int sys_timer_settime(timer_t timerid, int flags, + const struct itimerspec *new_value, struct itimerspec *old_value) +{ +#if defined(__NR_timer_settime) + return my_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value); +#elif defined(__NR_timer_settime64) + struct __kernel_itimerspec knew_value, kold_value; + int ret; + + __nolibc_timespec_user_to_kernel(&new_value->it_value, &knew_value.it_value); + __nolibc_timespec_user_to_kernel(&new_value->it_interval, &knew_value.it_interval); + ret = my_syscall4(__NR_timer_settime64, timerid, flags, &knew_value, &kold_value); + if (old_value) { + __nolibc_timespec_kernel_to_user(&kold_value.it_interval, &old_value->it_interval); + __nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value); + } + return ret; +#else + return __nolibc_enosys(__func__, timerid, flags, new_value, old_value); +#endif +} + +static __attribute__((unused)) +int timer_settime(timer_t timerid, int flags, + const struct itimerspec *new_value, struct itimerspec *old_value) +{ + return __sysret(sys_timer_settime(timerid, flags, new_value, old_value)); +} + #endif /* _NOLIBC_TIME_H */ diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h index ba6867aeeb91..93da29fe7719 100644 --- a/tools/include/nolibc/types.h +++ b/tools/include/nolibc/types.h @@ -188,6 +188,7 @@ struct stat { }; typedef __kernel_clockid_t clockid_t; +typedef int timer_t; /* WARNING, it only deals with the 4096 first majors and 256 first minors */ #define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff))) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 9b8aa41a547b..7530b442941f 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -905,6 +905,56 @@ int test_stat_timestamps(void) return 0; } +int test_timer(void) +{ + struct itimerspec timerspec; + struct sigevent evp; + timer_t timer; + int ret; + + evp.sigev_notify = SIGEV_NONE; + + ret = timer_create(CLOCK_MONOTONIC, &evp, &timer); + if (ret) + return ret; + + timerspec = (struct itimerspec) { + .it_value.tv_sec = 1000000, + }; + ret = timer_settime(timer, 0, &timerspec, NULL); + if (ret) + goto err; + + timerspec = (struct itimerspec) { + .it_value.tv_sec = -1, + .it_value.tv_nsec = -1, + .it_interval.tv_sec = -1, + .it_interval.tv_nsec = -1, + }; + ret = timer_gettime(timer, &timerspec); + if (ret) + goto err; + + errno = EINVAL; + ret = -1; + + if (timerspec.it_interval.tv_sec || timerspec.it_interval.tv_nsec) + goto err; + + if (timerspec.it_value.tv_sec > 1000000) + goto err; + + ret = timer_delete(timer); + if (ret) + return ret; + + return 0; + +err: + timer_delete(timer); + return ret; +} + int test_uname(void) { struct utsname buf; @@ -1186,6 +1236,7 @@ int run_syscall(int min, int max) CASE_TEST(stat_fault); EXPECT_SYSER(1, stat(NULL, &stat_buf), -1, EFAULT); break; CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break; CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; + CASE_TEST(timer); EXPECT_SYSZR(1, test_timer()); break; CASE_TEST(uname); EXPECT_SYSZR(proc, test_uname()); break; CASE_TEST(uname_fault); EXPECT_SYSER(1, uname(NULL), -1, EFAULT); break; CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break; -- cgit v1.2.3 From da69cfb17b2afbb8692b74eefb844f85febb6674 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:11 +0200 Subject: tools/nolibc: add timerfd functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-10-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/Makefile | 1 + tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/sys/timerfd.h | 87 ++++++++++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 48 +++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 tools/include/nolibc/sys/timerfd.h (limited to 'tools/testing') diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index da4771ef8984..58c4ede9c294 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -53,6 +53,7 @@ all_files := \ sys/stat.h \ sys/syscall.h \ sys/time.h \ + sys/timerfd.h \ sys/types.h \ sys/wait.h \ time.h \ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 966302c9e8e1..37a55f703dfc 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -102,6 +102,7 @@ #include "sys/stat.h" #include "sys/syscall.h" #include "sys/time.h" +#include "sys/timerfd.h" #include "sys/wait.h" #include "ctype.h" #include "elf.h" diff --git a/tools/include/nolibc/sys/timerfd.h b/tools/include/nolibc/sys/timerfd.h new file mode 100644 index 000000000000..4375d546ba58 --- /dev/null +++ b/tools/include/nolibc/sys/timerfd.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * timerfd definitions for NOLIBC + * Copyright (C) 2025 Thomas Weißschuh + */ + +/* make sure to include all global symbols */ +#include "../nolibc.h" + +#ifndef _NOLIBC_SYS_TIMERFD_H +#define _NOLIBC_SYS_TIMERFD_H + +#include "../sys.h" +#include "../time.h" + +#include + + +static __attribute__((unused)) +int sys_timerfd_create(int clockid, int flags) +{ + return my_syscall2(__NR_timerfd_create, clockid, flags); +} + +static __attribute__((unused)) +int timerfd_create(int clockid, int flags) +{ + return __sysret(sys_timerfd_create(clockid, flags)); +} + + +static __attribute__((unused)) +int sys_timerfd_gettime(int fd, struct itimerspec *curr_value) +{ +#if defined(__NR_timerfd_gettime) + return my_syscall2(__NR_timerfd_gettime, fd, curr_value); +#elif defined(__NR_timerfd_gettime64) + struct __kernel_itimerspec kcurr_value; + int ret; + + ret = my_syscall2(__NR_timerfd_gettime64, fd, &kcurr_value); + __nolibc_timespec_kernel_to_user(&kcurr_value.it_interval, &curr_value->it_interval); + __nolibc_timespec_kernel_to_user(&kcurr_value.it_value, &curr_value->it_value); + return ret; +#else + return __nolibc_enosys(__func__, fd, curr_value); +#endif +} + +static __attribute__((unused)) +int timerfd_gettime(int fd, struct itimerspec *curr_value) +{ + return __sysret(sys_timerfd_gettime(fd, curr_value)); +} + + +static __attribute__((unused)) +int sys_timerfd_settime(int fd, int flags, + const struct itimerspec *new_value, struct itimerspec *old_value) +{ +#if defined(__NR_timerfd_settime) + return my_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value); +#elif defined(__NR_timerfd_settime64) + struct __kernel_itimerspec knew_value, kold_value; + int ret; + + __nolibc_timespec_user_to_kernel(&new_value->it_value, &knew_value.it_value); + __nolibc_timespec_user_to_kernel(&new_value->it_interval, &knew_value.it_interval); + ret = my_syscall4(__NR_timerfd_settime64, fd, flags, &knew_value, &kold_value); + if (old_value) { + __nolibc_timespec_kernel_to_user(&kold_value.it_interval, &old_value->it_interval); + __nolibc_timespec_kernel_to_user(&kold_value.it_value, &old_value->it_value); + } + return ret; +#else + return __nolibc_enosys(__func__, fd, flags, new_value, old_value); +#endif +} + +static __attribute__((unused)) +int timerfd_settime(int fd, int flags, + const struct itimerspec *new_value, struct itimerspec *old_value) +{ + return __sysret(sys_timerfd_settime(fd, flags, new_value, old_value)); +} + +#endif /* _NOLIBC_SYS_TIMERFD_H */ diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7530b442941f..d73125c41096 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -955,6 +956,52 @@ err: return ret; } +int test_timerfd(void) +{ + struct itimerspec timerspec; + int timer, ret; + + timer = timerfd_create(CLOCK_MONOTONIC, 0); + if (timer == -1) + return -1; + + timerspec = (struct itimerspec) { + .it_value.tv_sec = 1000000, + }; + ret = timerfd_settime(timer, 0, &timerspec, NULL); + if (ret) + goto err; + + timerspec = (struct itimerspec) { + .it_value.tv_sec = -1, + .it_value.tv_nsec = -1, + .it_interval.tv_sec = -1, + .it_interval.tv_nsec = -1, + }; + ret = timerfd_gettime(timer, &timerspec); + if (ret) + goto err; + + errno = EINVAL; + ret = -1; + + if (timerspec.it_interval.tv_sec || timerspec.it_interval.tv_nsec) + goto err; + + if (timerspec.it_value.tv_sec > 1000000) + goto err; + + ret = close(timer); + if (ret) + return ret; + + return 0; + +err: + close(timer); + return ret; +} + int test_uname(void) { struct utsname buf; @@ -1237,6 +1284,7 @@ int run_syscall(int min, int max) CASE_TEST(stat_timestamps); EXPECT_SYSZR(1, test_stat_timestamps()); break; CASE_TEST(symlink_root); EXPECT_SYSER(1, symlink("/", "/"), -1, EEXIST); break; CASE_TEST(timer); EXPECT_SYSZR(1, test_timer()); break; + CASE_TEST(timerfd); EXPECT_SYSZR(1, test_timerfd()); break; CASE_TEST(uname); EXPECT_SYSZR(proc, test_uname()); break; CASE_TEST(uname_fault); EXPECT_SYSER(1, uname(NULL), -1, EFAULT); break; CASE_TEST(unlink_root); EXPECT_SYSER(1, unlink("/"), -1, EISDIR); break; -- cgit v1.2.3 From 7ff3c71a4795f524b4dc643db4d00d4467be26a0 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:12 +0200 Subject: tools/nolibc: add difftime() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-11-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/time.h | 7 +++++++ tools/testing/selftests/nolibc/nolibc-test.c | 12 ++++++++++++ 2 files changed, 19 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/time.h b/tools/include/nolibc/time.h index 48f602b661b3..fc387940d51f 100644 --- a/tools/include/nolibc/time.h +++ b/tools/include/nolibc/time.h @@ -108,6 +108,13 @@ int clock_settime(clockid_t clockid, struct timespec *tp) } +static __inline__ +double difftime(time_t time1, time_t time2) +{ + return time1 - time2; +} + + static __attribute__((unused)) time_t time(time_t *tptr) { diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index d73125c41096..665d7631fbc6 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1304,6 +1304,17 @@ int run_syscall(int min, int max) return ret; } +int test_difftime(void) +{ + if (difftime(200., 100.) != 100.) + return 1; + + if (difftime(100., 200.) != -100.) + return 1; + + return 0; +} + int run_stdlib(int min, int max) { int test; @@ -1426,6 +1437,7 @@ int run_stdlib(int min, int max) CASE_TEST(toupper_noop); EXPECT_EQ(1, toupper('A'), 'A'); break; CASE_TEST(abs); EXPECT_EQ(1, abs(-10), 10); break; CASE_TEST(abs_noop); EXPECT_EQ(1, abs(10), 10); break; + CASE_TEST(difftime); EXPECT_ZR(1, test_difftime()); break; case __LINE__: return ret; /* must be last */ -- cgit v1.2.3 From 256dc7339d466f4d928be48ced6d590a99d447cc Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:13 +0200 Subject: tools/nolibc: add namespace functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Not all configurations support namespaces, so skip the tests where necessary. Also if the tests are running without privileges. Enable the namespace configuration for those architectures where it is not enabled by default. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-12-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/Makefile | 1 + tools/include/nolibc/nolibc.h | 1 + tools/include/nolibc/sched.h | 50 +++++++++++++++++++++ tools/testing/selftests/nolibc/Makefile | 2 + tools/testing/selftests/nolibc/nolibc-test.c | 67 ++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+) create mode 100644 tools/include/nolibc/sched.h (limited to 'tools/testing') diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 58c4ede9c294..9ff78ae21522 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -38,6 +38,7 @@ all_files := \ math.h \ nolibc.h \ poll.h \ + sched.h \ signal.h \ stackprotector.h \ std.h \ diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 37a55f703dfc..51c423a36b59 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -106,6 +106,7 @@ #include "sys/wait.h" #include "ctype.h" #include "elf.h" +#include "sched.h" #include "signal.h" #include "unistd.h" #include "stdio.h" diff --git a/tools/include/nolibc/sched.h b/tools/include/nolibc/sched.h new file mode 100644 index 000000000000..32221562c166 --- /dev/null +++ b/tools/include/nolibc/sched.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * sched function definitions for NOLIBC + * Copyright (C) 2025 Thomas Weißschuh + */ + +/* make sure to include all global symbols */ +#include "nolibc.h" + +#ifndef _NOLIBC_SCHED_H +#define _NOLIBC_SCHED_H + +#include "sys.h" + +#include + +/* + * int setns(int fd, int nstype); + */ + +static __attribute__((unused)) +int sys_setns(int fd, int nstype) +{ + return my_syscall2(__NR_setns, fd, nstype); +} + +static __attribute__((unused)) +int setns(int fd, int nstype) +{ + return __sysret(sys_setns(fd, nstype)); +} + + +/* + * int unshare(int flags); + */ + +static __attribute__((unused)) +int sys_unshare(int flags) +{ + return my_syscall1(__NR_unshare, flags); +} + +static __attribute__((unused)) +int unshare(int flags) +{ + return __sysret(sys_unshare(flags)); +} + +#endif /* _NOLIBC_SCHED_H */ diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index 2671383045db..94176ffe4646 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -109,6 +109,8 @@ DEFCONFIG = $(DEFCONFIG_$(XARCH)) EXTRACONFIG_m68k = -e CONFIG_BLK_DEV_INITRD EXTRACONFIG = $(EXTRACONFIG_$(XARCH)) +EXTRACONFIG_arm = -e CONFIG_NAMESPACES +EXTRACONFIG_armthumb = -e CONFIG_NAMESPACES # optional tests to run (default = all) TEST = diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 665d7631fbc6..d1157319b5d7 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1172,6 +1172,72 @@ int test_openat(void) return 0; } +int test_namespace(void) +{ + int original_ns, new_ns, ret; + ino_t original_ns_ino; + struct stat stat_buf; + + original_ns = open("/proc/self/ns/uts", O_RDONLY); + if (original_ns == -1) + return -1; + + ret = fstat(original_ns, &stat_buf); + if (ret) + goto out; + + original_ns_ino = stat_buf.st_ino; + + ret = unshare(CLONE_NEWUTS); + if (ret) + goto out; + + new_ns = open("/proc/self/ns/uts", O_RDONLY); + if (new_ns == -1) { + ret = new_ns; + goto out; + } + + ret = fstat(new_ns, &stat_buf); + close(new_ns); + if (ret) + goto out; + + if (stat_buf.st_ino == original_ns_ino) { + errno = EINVAL; + ret = -1; + goto out; + } + + ret = setns(original_ns, CLONE_NEWUTS); + if (ret) + goto out; + + new_ns = open("/proc/self/ns/uts", O_RDONLY); + if (new_ns == -1) { + ret = new_ns; + goto out; + } + + ret = fstat(new_ns, &stat_buf); + if (ret) + goto out; + + close(new_ns); + + if (stat_buf.st_ino != original_ns_ino) { + errno = EINVAL; + ret = -1; + goto out; + } + + ret = 0; + +out: + close(original_ns); + return ret; +} + /* Run syscall tests between IDs and . * Return 0 on success, non-zero on failure. */ @@ -1296,6 +1362,7 @@ int run_syscall(int min, int max) CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break; CASE_TEST(syscall_noargs); EXPECT_SYSEQ(1, syscall(__NR_getpid), getpid()); break; CASE_TEST(syscall_args); EXPECT_SYSER(1, syscall(__NR_statx, 0, NULL, 0, 0, NULL), -1, EFAULT); break; + CASE_TEST(namespace); EXPECT_SYSZR(euid0 && proc, test_namespace()); break; case __LINE__: return ret; /* must be last */ /* note: do not set any defaults so as to permit holes above */ -- cgit v1.2.3 From a009a0c6faa9e7ffac13d55ef6cdac1f9a68efbe Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 28 Apr 2025 14:40:14 +0200 Subject: tools/nolibc: add fopen() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is used in various selftests and will be handy when integrating those with nolibc. Only the standard POSIX modes are supported. No extensions nor the (noop) "b" from ISO C are accepted. Signed-off-by: Thomas Weißschuh Acked-by: Willy Tarreau Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-13-3c043eeab06c@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 27 +++++++++++++++++++++++++++ tools/testing/selftests/nolibc/nolibc-test.c | 24 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'tools/testing') diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index df5717d59182..c470d334ef3f 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -13,6 +13,7 @@ #include "std.h" #include "arch.h" #include "errno.h" +#include "fcntl.h" #include "types.h" #include "sys.h" #include "stdarg.h" @@ -55,6 +56,32 @@ FILE *fdopen(int fd, const char *mode __attribute__((unused))) return (FILE*)(intptr_t)~fd; } +static __attribute__((unused)) +FILE *fopen(const char *pathname, const char *mode) +{ + int flags, fd; + + switch (*mode) { + case 'r': + flags = O_RDONLY; + break; + case 'w': + flags = O_WRONLY | O_CREAT | O_TRUNC; + break; + case 'a': + flags = O_WRONLY | O_CREAT | O_APPEND; + break; + default: + SET_ERRNO(EINVAL); return NULL; + } + + if (mode[1] == '+') + flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; + + fd = open(pathname, flags, 0666); + return fdopen(fd, mode); +} + /* provides the fd of stream. */ static __attribute__((unused)) int fileno(FILE *stream) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index d1157319b5d7..0391c7d01380 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -859,6 +859,29 @@ int test_getpagesize(void) return !c; } +int test_file_stream(void) +{ + FILE *f; + int r; + + f = fopen("/dev/null", "r"); + if (!f) + return -1; + + errno = 0; + r = fwrite("foo", 1, 3, f); + if (r != 0 || errno != EBADF) { + fclose(f); + return -1; + } + + r = fclose(f); + if (r == EOF) + return -1; + + return 0; +} + int test_fork(void) { int status; @@ -1311,6 +1334,7 @@ int run_syscall(int min, int max) CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break; CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break; CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break; + CASE_TEST(file_stream); EXPECT_SYSZR(1, test_file_stream()); break; CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break; CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break; CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break; -- cgit v1.2.3 From 2011097c17c6c947efd57ade071927c13784dcbc Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 15 May 2025 21:57:55 +0200 Subject: selftests/nolibc: drop include guards around standard headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nolibc now provides all the headers required by nolibc-test.c. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250515-nolibc-sys-v1-9-74f82eea3b59@weissschuh.net Acked-by: Willy Tarreau --- tools/testing/selftests/nolibc/nolibc-test-linkage.c | 2 -- tools/testing/selftests/nolibc/nolibc-test.c | 5 ----- 2 files changed, 7 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/nolibc/nolibc-test-linkage.c b/tools/testing/selftests/nolibc/nolibc-test-linkage.c index a7ca8325863f..0636d1b6e808 100644 --- a/tools/testing/selftests/nolibc/nolibc-test-linkage.c +++ b/tools/testing/selftests/nolibc/nolibc-test-linkage.c @@ -2,9 +2,7 @@ #include "nolibc-test-linkage.h" -#ifndef NOLIBC #include -#endif void *linkage_test_errno_addr(void) { diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 0391c7d01380..dbe13000fb1a 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -9,12 +9,9 @@ * $(CC) -nostdlib -I/path/to/nolibc/sysroot => _NOLIBC_* guards are present * $(CC) with default libc => NOLIBC* never defined */ -#ifndef NOLIBC #include #include #include -#ifndef _NOLIBC_STDIO_H -/* standard libcs need more includes */ #include #include #include @@ -43,8 +40,6 @@ #include #include #include -#endif -#endif #pragma GCC diagnostic ignored "-Wmissing-prototypes" -- cgit v1.2.3 From df82ffc5a3c18b21ea0140faed81241c7d273e88 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:19 +0200 Subject: selftests: harness: Add kselftest harness selftest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a selftest for the kselftest harness itself so any changes can be validated. Signed-off-by: Thomas Weißschuh Reviewed-by: Muhammad Usama Anjum Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-1-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- MAINTAINERS | 1 + tools/testing/selftests/Makefile | 1 + .../testing/selftests/kselftest_harness/.gitignore | 2 + tools/testing/selftests/kselftest_harness/Makefile | 7 ++ .../selftests/kselftest_harness/harness-selftest.c | 136 +++++++++++++++++++++ .../kselftest_harness/harness-selftest.expected | 64 ++++++++++ .../kselftest_harness/harness-selftest.sh | 13 ++ 7 files changed, 224 insertions(+) create mode 100644 tools/testing/selftests/kselftest_harness/.gitignore create mode 100644 tools/testing/selftests/kselftest_harness/Makefile create mode 100644 tools/testing/selftests/kselftest_harness/harness-selftest.c create mode 100644 tools/testing/selftests/kselftest_harness/harness-selftest.expected create mode 100755 tools/testing/selftests/kselftest_harness/harness-selftest.sh (limited to 'tools/testing') diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..9d5278df33c8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21742,6 +21742,7 @@ F: include/linux/seccomp.h F: include/uapi/linux/seccomp.h F: kernel/seccomp.c F: tools/testing/selftests/kselftest_harness.h +F: tools/testing/selftests/kselftest_harness/ F: tools/testing/selftests/seccomp/* K: \bsecure_computing K: \bTIF_SECCOMP\b diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index c77c8c8e3d9b..27592909a596 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -48,6 +48,7 @@ TARGETS += ipc TARGETS += ir TARGETS += kcmp TARGETS += kexec +TARGETS += kselftest_harness TARGETS += kvm TARGETS += landlock TARGETS += lib diff --git a/tools/testing/selftests/kselftest_harness/.gitignore b/tools/testing/selftests/kselftest_harness/.gitignore new file mode 100644 index 000000000000..e4e476a333c9 --- /dev/null +++ b/tools/testing/selftests/kselftest_harness/.gitignore @@ -0,0 +1,2 @@ +/harness-selftest +/harness-selftest.seen diff --git a/tools/testing/selftests/kselftest_harness/Makefile b/tools/testing/selftests/kselftest_harness/Makefile new file mode 100644 index 000000000000..0617535a6ce4 --- /dev/null +++ b/tools/testing/selftests/kselftest_harness/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +TEST_GEN_PROGS_EXTENDED := harness-selftest +TEST_PROGS := harness-selftest.sh +EXTRA_CLEAN := harness-selftest.seen + +include ../lib.mk diff --git a/tools/testing/selftests/kselftest_harness/harness-selftest.c b/tools/testing/selftests/kselftest_harness/harness-selftest.c new file mode 100644 index 000000000000..b555493bdb4d --- /dev/null +++ b/tools/testing/selftests/kselftest_harness/harness-selftest.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#include +#include + +/* Avoid any inconsistencies */ +#define TH_LOG_STREAM stdout + +#include "../kselftest_harness.h" + +static void test_helper(struct __test_metadata *_metadata) +{ + ASSERT_EQ(0, 0); +} + +TEST(standalone_pass) { + TH_LOG("before"); + ASSERT_EQ(0, 0); + EXPECT_EQ(0, 0); + test_helper(_metadata); + TH_LOG("after"); +} + +TEST(standalone_fail) { + TH_LOG("before"); + EXPECT_EQ(0, 0); + EXPECT_EQ(0, 1); + ASSERT_EQ(0, 1); + TH_LOG("after"); +} + +TEST_SIGNAL(signal_pass, SIGUSR1) { + TH_LOG("before"); + ASSERT_EQ(0, 0); + TH_LOG("after"); + kill(getpid(), SIGUSR1); +} + +TEST_SIGNAL(signal_fail, SIGUSR1) { + TH_LOG("before"); + ASSERT_EQ(0, 1); + TH_LOG("after"); + kill(getpid(), SIGUSR1); +} + +FIXTURE(fixture) { + pid_t testpid; +}; + +FIXTURE_SETUP(fixture) { + TH_LOG("setup"); + self->testpid = getpid(); +} + +FIXTURE_TEARDOWN(fixture) { + TH_LOG("teardown same-process=%d", self->testpid == getpid()); +} + +TEST_F(fixture, pass) { + TH_LOG("before"); + ASSERT_EQ(0, 0); + test_helper(_metadata); + standalone_pass(_metadata); + TH_LOG("after"); +} + +TEST_F(fixture, fail) { + TH_LOG("before"); + ASSERT_EQ(0, 1); + fixture_pass(_metadata, self, variant); + TH_LOG("after"); +} + +TEST_F_TIMEOUT(fixture, timeout, 1) { + TH_LOG("before"); + sleep(2); + TH_LOG("after"); +} + +FIXTURE(fixture_parent) { + pid_t testpid; +}; + +FIXTURE_SETUP(fixture_parent) { + TH_LOG("setup"); + self->testpid = getpid(); +} + +FIXTURE_TEARDOWN_PARENT(fixture_parent) { + TH_LOG("teardown same-process=%d", self->testpid == getpid()); +} + +TEST_F(fixture_parent, pass) { + TH_LOG("before"); + ASSERT_EQ(0, 0); + TH_LOG("after"); +} + +FIXTURE(fixture_setup_failure) { + pid_t testpid; +}; + +FIXTURE_SETUP(fixture_setup_failure) { + TH_LOG("setup"); + self->testpid = getpid(); + ASSERT_EQ(0, 1); +} + +FIXTURE_TEARDOWN(fixture_setup_failure) { + TH_LOG("teardown same-process=%d", self->testpid == getpid()); +} + +TEST_F(fixture_setup_failure, pass) { + TH_LOG("before"); + ASSERT_EQ(0, 0); + TH_LOG("after"); +} + +int main(int argc, char **argv) +{ + /* + * The harness uses abort() to signal assertion failures, which triggers coredumps. + * This may be useful to debug real failures but not for this selftest, disable them. + */ + struct rlimit rlimit = { + .rlim_cur = 0, + .rlim_max = 0, + }; + + prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); + setrlimit(RLIMIT_CORE, &rlimit); + + return test_harness_run(argc, argv); +} diff --git a/tools/testing/selftests/kselftest_harness/harness-selftest.expected b/tools/testing/selftests/kselftest_harness/harness-selftest.expected new file mode 100644 index 000000000000..97e1418c1c7e --- /dev/null +++ b/tools/testing/selftests/kselftest_harness/harness-selftest.expected @@ -0,0 +1,64 @@ +TAP version 13 +1..9 +# Starting 9 tests from 4 test cases. +# RUN global.standalone_pass ... +# harness-selftest.c:19:standalone_pass:before +# harness-selftest.c:23:standalone_pass:after +# OK global.standalone_pass +ok 1 global.standalone_pass +# RUN global.standalone_fail ... +# harness-selftest.c:27:standalone_fail:before +# harness-selftest.c:29:standalone_fail:Expected 0 (0) == 1 (1) +# harness-selftest.c:30:standalone_fail:Expected 0 (0) == 1 (1) +# standalone_fail: Test terminated by assertion +# FAIL global.standalone_fail +not ok 2 global.standalone_fail +# RUN global.signal_pass ... +# harness-selftest.c:35:signal_pass:before +# harness-selftest.c:37:signal_pass:after +# OK global.signal_pass +ok 3 global.signal_pass +# RUN global.signal_fail ... +# harness-selftest.c:42:signal_fail:before +# harness-selftest.c:43:signal_fail:Expected 0 (0) == 1 (1) +# signal_fail: Test terminated by assertion +# FAIL global.signal_fail +not ok 4 global.signal_fail +# RUN fixture.pass ... +# harness-selftest.c:53:pass:setup +# harness-selftest.c:62:pass:before +# harness-selftest.c:19:pass:before +# harness-selftest.c:23:pass:after +# harness-selftest.c:66:pass:after +# harness-selftest.c:58:pass:teardown same-process=1 +# OK fixture.pass +ok 5 fixture.pass +# RUN fixture.fail ... +# harness-selftest.c:53:fail:setup +# harness-selftest.c:70:fail:before +# harness-selftest.c:71:fail:Expected 0 (0) == 1 (1) +# harness-selftest.c:58:fail:teardown same-process=1 +# fail: Test terminated by assertion +# FAIL fixture.fail +not ok 6 fixture.fail +# RUN fixture.timeout ... +# harness-selftest.c:53:timeout:setup +# harness-selftest.c:77:timeout:before +# timeout: Test terminated by timeout +# FAIL fixture.timeout +not ok 7 fixture.timeout +# RUN fixture_parent.pass ... +# harness-selftest.c:87:pass:setup +# harness-selftest.c:96:pass:before +# harness-selftest.c:98:pass:after +# harness-selftest.c:92:pass:teardown same-process=0 +# OK fixture_parent.pass +ok 8 fixture_parent.pass +# RUN fixture_setup_failure.pass ... +# harness-selftest.c:106:pass:setup +# harness-selftest.c:108:pass:Expected 0 (0) == 1 (1) +# pass: Test terminated by assertion +# FAIL fixture_setup_failure.pass +not ok 9 fixture_setup_failure.pass +# FAILED: 4 / 9 tests passed. +# Totals: pass:4 fail:5 xfail:0 xpass:0 skip:0 error:0 diff --git a/tools/testing/selftests/kselftest_harness/harness-selftest.sh b/tools/testing/selftests/kselftest_harness/harness-selftest.sh new file mode 100755 index 000000000000..fe72d16370fe --- /dev/null +++ b/tools/testing/selftests/kselftest_harness/harness-selftest.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Selftest for kselftest_harness.h +# + +set -e + +DIR="$(dirname $(readlink -f "$0"))" + +"$DIR"/harness-selftest > harness-selftest.seen || true + +diff -u "$DIR"/harness-selftest.expected harness-selftest.seen -- cgit v1.2.3 From 575eca2c8c7d40a1dccb0e3abc58ed13f45c4e8a Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:20 +0200 Subject: selftests: harness: Use C89 comment style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All comments in this file use C89 comment style. Except for this one. Change it to get one step closer to C89 compatibility. Signed-off-by: Thomas Weißschuh Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-2-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 666c9fde76da..bac4327775ea 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -983,7 +983,7 @@ static void __timeout_handler(int sig, siginfo_t *info, void *ucontext) } t->timed_out = true; - // signal process group + /* signal process group */ kill(-(t->pid), SIGKILL); } -- cgit v1.2.3 From 6c409e0d87e340c2ce16fc3a1dd5b625c73fe54b Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:21 +0200 Subject: selftests: harness: Ignore unused variant argument warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For tests without fixtures the variant argument is unused. This is intentional, prevent to compiler from complaining. Example warning: harness-selftest.c: In function 'wrapper_standalone_pass': ../kselftest_harness.h:181:52: error: unused parameter 'variant' [-Werror=unused-parameter] 181 | struct __fixture_variant_metadata *variant) \ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ ../kselftest_harness.h:156:25: note: in expansion of macro '__TEST_IMPL' 156 | #define TEST(test_name) __TEST_IMPL(test_name, -1) | ^~~~~~~~~~~ harness-selftest.c:15:1: note: in expansion of macro 'TEST' 15 | TEST(standalone_pass) { | ^~~~ Signed-off-by: Thomas Weißschuh Reviewed-by: Muhammad Usama Anjum Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-3-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index bac4327775ea..2b350ed60b2b 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -174,7 +174,7 @@ static void test_name(struct __test_metadata *_metadata); \ static inline void wrapper_##test_name( \ struct __test_metadata *_metadata, \ - struct __fixture_variant_metadata *variant) \ + struct __fixture_variant_metadata __attribute__((unused)) *variant) \ { \ _metadata->setup_completed = true; \ if (setjmp(_metadata->env) == 0) \ -- cgit v1.2.3 From c2bcc8e9577a35f9cf4707f8bb0b58bce30991aa Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:22 +0200 Subject: selftests: harness: Mark functions without prototypes static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With -Wmissing-prototypes the compiler will warn about non-static functions which don't have a prototype defined. As they are not used from a different compilation unit they don't need to be defined globally. Avoid the issue by marking the functions static. Signed-off-by: Thomas Weißschuh Reviewed-by: Muhammad Usama Anjum Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-4-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 2b350ed60b2b..5822bc0b86a3 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -258,7 +258,7 @@ * A bare "return;" statement may be used to return early. */ #define FIXTURE_SETUP(fixture_name) \ - void fixture_name##_setup( \ + static void fixture_name##_setup( \ struct __test_metadata __attribute__((unused)) *_metadata, \ FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \ const FIXTURE_VARIANT(fixture_name) \ @@ -307,7 +307,7 @@ __FIXTURE_TEARDOWN(fixture_name) #define __FIXTURE_TEARDOWN(fixture_name) \ - void fixture_name##_teardown( \ + static void fixture_name##_teardown( \ struct __test_metadata __attribute__((unused)) *_metadata, \ FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \ const FIXTURE_VARIANT(fixture_name) \ @@ -987,7 +987,7 @@ static void __timeout_handler(int sig, siginfo_t *info, void *ucontext) kill(-(t->pid), SIGKILL); } -void __wait_for_test(struct __test_metadata *t) +static void __wait_for_test(struct __test_metadata *t) { struct sigaction action = { .sa_sigaction = __timeout_handler, @@ -1205,9 +1205,9 @@ static bool test_enabled(int argc, char **argv, return !has_positive; } -void __run_test(struct __fixture_metadata *f, - struct __fixture_variant_metadata *variant, - struct __test_metadata *t) +static void __run_test(struct __fixture_metadata *f, + struct __fixture_variant_metadata *variant, + struct __test_metadata *t) { struct __test_xfail *xfail; char test_name[1024]; -- cgit v1.2.3 From 5cccec7239c4765f5339951b1aa9063b80cfc29f Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:23 +0200 Subject: selftests: harness: Remove inline qualifier for wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pointers to the wrappers are stored in function pointers, preventing them from actually being inlined. Remove the inline qualifier, aligning these wrappers with the other functions defined through macros. Signed-off-by: Thomas Weißschuh Reviewed-by: Muhammad Usama Anjum Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-5-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 5822bc0b86a3..222a4f51a8d7 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -172,7 +172,7 @@ #define __TEST_IMPL(test_name, _signal) \ static void test_name(struct __test_metadata *_metadata); \ - static inline void wrapper_##test_name( \ + static void wrapper_##test_name( \ struct __test_metadata *_metadata, \ struct __fixture_variant_metadata __attribute__((unused)) *variant) \ { \ @@ -401,7 +401,7 @@ struct __test_metadata *_metadata, \ FIXTURE_DATA(fixture_name) *self, \ const FIXTURE_VARIANT(fixture_name) *variant); \ - static inline void wrapper_##fixture_name##_##test_name( \ + static void wrapper_##fixture_name##_##test_name( \ struct __test_metadata *_metadata, \ struct __fixture_variant_metadata *variant) \ { \ -- cgit v1.2.3 From 67ee52611b4d7a0da38e82409b86607c3a43fe8d Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:24 +0200 Subject: selftests: harness: Remove dependency on libatomic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __sync_bool_compare_and_swap() is deprecated and requires libatomic on GCC. Compiler toolchains don't necessarily have libatomic available, so avoid this requirement by using atomics that don't need libatomic. Signed-off-by: Thomas Weißschuh Reviewed-by: Muhammad Usama Anjum Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-6-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 222a4f51a8d7..7ec4f66d0e3d 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -439,12 +439,12 @@ } \ if (child == 0) { \ if (_metadata->setup_completed && !fixture_name##_teardown_parent && \ - __sync_bool_compare_and_swap(teardown, false, true)) \ + !__atomic_test_and_set(teardown, __ATOMIC_RELAXED)) \ fixture_name##_teardown(_metadata, self, variant->data); \ _exit(0); \ } \ if (_metadata->setup_completed && fixture_name##_teardown_parent && \ - __sync_bool_compare_and_swap(teardown, false, true)) \ + !__atomic_test_and_set(teardown, __ATOMIC_RELAXED)) \ fixture_name##_teardown(_metadata, self, variant->data); \ munmap(teardown, sizeof(*teardown)); \ if (self && fixture_name##_teardown_parent) \ -- cgit v1.2.3 From 73a3cde97677933f292d678fcc84bae5d9ac2651 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:25 +0200 Subject: selftests: harness: Implement test timeouts through pidfd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the kselftest harness compatible with nolibc which does not implement signals by replacing the signal logic with pidfds. The code also becomes simpler. Signed-off-by: Thomas Weißschuh Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-7-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 72 ++++++++++------------------- 1 file changed, 25 insertions(+), 47 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 7ec4f66d0e3d..1e459619fe86 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -56,6 +56,8 @@ #include #include #include +#include +#include #include #include #include @@ -914,7 +916,6 @@ struct __test_metadata { int exit_code; int trigger; /* extra handler after the evaluation */ int timeout; /* seconds to wait for test timeout */ - bool timed_out; /* did this test timeout instead of exiting? */ bool aborted; /* stopped test due to failed ASSERT */ bool setup_completed; /* did setup finish? */ jmp_buf env; /* for exiting out of test early */ @@ -964,75 +965,52 @@ static inline void __test_check_assert(struct __test_metadata *t) abort(); } -struct __test_metadata *__active_test; -static void __timeout_handler(int sig, siginfo_t *info, void *ucontext) -{ - struct __test_metadata *t = __active_test; - - /* Sanity check handler execution environment. */ - if (!t) { - fprintf(TH_LOG_STREAM, - "# no active test in SIGALRM handler!?\n"); - abort(); - } - if (sig != SIGALRM || sig != info->si_signo) { - fprintf(TH_LOG_STREAM, - "# %s: SIGALRM handler caught signal %d!?\n", - t->name, sig != SIGALRM ? sig : info->si_signo); - abort(); - } - - t->timed_out = true; - /* signal process group */ - kill(-(t->pid), SIGKILL); -} - static void __wait_for_test(struct __test_metadata *t) { - struct sigaction action = { - .sa_sigaction = __timeout_handler, - .sa_flags = SA_SIGINFO, - }; - struct sigaction saved_action; /* * Sets status so that WIFEXITED(status) returns true and * WEXITSTATUS(status) returns KSFT_FAIL. This safe default value * should never be evaluated because of the waitpid(2) check and - * SIGALRM handling. + * timeout handling. */ int status = KSFT_FAIL << 8; - int child; + struct pollfd poll_child; + int ret, child, childfd; + bool timed_out = false; - if (sigaction(SIGALRM, &action, &saved_action)) { + childfd = syscall(__NR_pidfd_open, t->pid, 0); + if (childfd == -1) { t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, - "# %s: unable to install SIGALRM handler\n", + "# %s: unable to open pidfd\n", t->name); return; } - __active_test = t; - t->timed_out = false; - alarm(t->timeout); - child = waitpid(t->pid, &status, 0); - if (child == -1 && errno != EINTR) { + + poll_child.fd = childfd; + poll_child.events = POLLIN; + ret = poll(&poll_child, 1, t->timeout * 1000); + if (ret == -1) { t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, - "# %s: Failed to wait for PID %d (errno: %d)\n", - t->name, t->pid, errno); + "# %s: unable to wait on child pidfd\n", + t->name); return; + } else if (ret == 0) { + timed_out = true; + /* signal process group */ + kill(-(t->pid), SIGKILL); } - - alarm(0); - if (sigaction(SIGALRM, &saved_action, NULL)) { + child = waitpid(t->pid, &status, WNOHANG); + if (child == -1 && errno != EINTR) { t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, - "# %s: unable to uninstall SIGALRM handler\n", - t->name); + "# %s: Failed to wait for PID %d (errno: %d)\n", + t->name, t->pid, errno); return; } - __active_test = NULL; - if (t->timed_out) { + if (timed_out) { t->exit_code = KSFT_FAIL; fprintf(TH_LOG_STREAM, "# %s: Test terminated by timeout\n", t->name); -- cgit v1.2.3 From fb25e99bce8d6e72d976c6e9a6a238298936ae94 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:26 +0200 Subject: selftests: harness: Don't set setup_completed for fixtureless tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This field is unused and has no meaning for tests without fixtures. Don't set it for them. Signed-off-by: Thomas Weißschuh Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-8-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 1e459619fe86..905986debbfb 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -178,7 +178,6 @@ struct __test_metadata *_metadata, \ struct __fixture_variant_metadata __attribute__((unused)) *variant) \ { \ - _metadata->setup_completed = true; \ if (setjmp(_metadata->env) == 0) \ test_name(_metadata); \ __test_check_assert(_metadata); \ -- cgit v1.2.3 From 906dbc17d61c3877b93407dafdff443fc6e21d7f Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:27 +0200 Subject: selftests: harness: Move teardown conditional into test metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get rid of setjmp()/longjmp(), the teardown logic needs to be usable from __bail(). To access the atomic teardown conditional from there, move it into the test metadata. This also allows the removal of "setup_completed". Signed-off-by: Thomas Weißschuh Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-9-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 905986debbfb..895821af3e5c 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -411,9 +411,9 @@ pid_t child = 1; \ int status = 0; \ /* Makes sure there is only one teardown, even when child forks again. */ \ - bool *teardown = mmap(NULL, sizeof(*teardown), \ + _metadata->no_teardown = mmap(NULL, sizeof(*_metadata->no_teardown), \ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); \ - *teardown = false; \ + *_metadata->no_teardown = true; \ if (sizeof(*self) > 0) { \ if (fixture_name##_teardown_parent) { \ self = mmap(NULL, sizeof(*self), PROT_READ | PROT_WRITE, \ @@ -431,7 +431,7 @@ /* Let setup failure terminate early. */ \ if (_metadata->exit_code) \ _exit(0); \ - _metadata->setup_completed = true; \ + *_metadata->no_teardown = false; \ fixture_name##_##test_name(_metadata, self, variant->data); \ } else if (child < 0 || child != waitpid(child, &status, 0)) { \ ksft_print_msg("ERROR SPAWNING TEST GRANDCHILD\n"); \ @@ -439,15 +439,16 @@ } \ } \ if (child == 0) { \ - if (_metadata->setup_completed && !fixture_name##_teardown_parent && \ - !__atomic_test_and_set(teardown, __ATOMIC_RELAXED)) \ + if (!fixture_name##_teardown_parent && \ + !__atomic_test_and_set(_metadata->no_teardown, __ATOMIC_RELAXED)) \ fixture_name##_teardown(_metadata, self, variant->data); \ _exit(0); \ } \ - if (_metadata->setup_completed && fixture_name##_teardown_parent && \ - !__atomic_test_and_set(teardown, __ATOMIC_RELAXED)) \ + if (fixture_name##_teardown_parent && \ + !__atomic_test_and_set(_metadata->no_teardown, __ATOMIC_RELAXED)) \ fixture_name##_teardown(_metadata, self, variant->data); \ - munmap(teardown, sizeof(*teardown)); \ + munmap(_metadata->no_teardown, sizeof(*_metadata->no_teardown)); \ + _metadata->no_teardown = NULL; \ if (self && fixture_name##_teardown_parent) \ munmap(self, sizeof(*self)); \ if (WIFEXITED(status)) { \ @@ -916,7 +917,7 @@ struct __test_metadata { int trigger; /* extra handler after the evaluation */ int timeout; /* seconds to wait for test timeout */ bool aborted; /* stopped test due to failed ASSERT */ - bool setup_completed; /* did setup finish? */ + bool *no_teardown; /* fixture needs teardown */ jmp_buf env; /* for exiting out of test early */ struct __test_results *results; struct __test_metadata *prev, *next; @@ -1195,7 +1196,7 @@ static void __run_test(struct __fixture_metadata *f, t->exit_code = KSFT_PASS; t->trigger = 0; t->aborted = false; - t->setup_completed = false; + t->no_teardown = NULL; memset(t->env, 0, sizeof(t->env)); memset(t->results->reason, 0, sizeof(t->results->reason)); -- cgit v1.2.3 From 5f036a2a8e0985e52f7cf63a06f51911b5e8cae2 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:28 +0200 Subject: selftests: harness: Add teardown callback to test metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get rid of setjmp()/longjmp(), the teardown logic needs to be usable from __bail(). Introduce a new callback for it. Signed-off-by: Thomas Weißschuh Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-10-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 895821af3e5c..acb476093b74 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -439,14 +439,10 @@ } \ } \ if (child == 0) { \ - if (!fixture_name##_teardown_parent && \ - !__atomic_test_and_set(_metadata->no_teardown, __ATOMIC_RELAXED)) \ - fixture_name##_teardown(_metadata, self, variant->data); \ + _metadata->teardown_fn(false, _metadata, self, variant->data); \ _exit(0); \ } \ - if (fixture_name##_teardown_parent && \ - !__atomic_test_and_set(_metadata->no_teardown, __ATOMIC_RELAXED)) \ - fixture_name##_teardown(_metadata, self, variant->data); \ + _metadata->teardown_fn(true, _metadata, self, variant->data); \ munmap(_metadata->no_teardown, sizeof(*_metadata->no_teardown)); \ _metadata->no_teardown = NULL; \ if (self && fixture_name##_teardown_parent) \ @@ -460,6 +456,14 @@ } \ __test_check_assert(_metadata); \ } \ + static void wrapper_##fixture_name##_##test_name##_teardown( \ + bool in_parent, struct __test_metadata *_metadata, \ + void *self, const void *variant) \ + { \ + if (fixture_name##_teardown_parent == in_parent && \ + !__atomic_test_and_set(_metadata->no_teardown, __ATOMIC_RELAXED)) \ + fixture_name##_teardown(_metadata, self, variant); \ + } \ static struct __test_metadata *_##fixture_name##_##test_name##_object; \ static void __attribute__((constructor)) \ _register_##fixture_name##_##test_name(void) \ @@ -469,6 +473,7 @@ object->name = #test_name; \ object->fn = &wrapper_##fixture_name##_##test_name; \ object->fixture = &_##fixture_name##_fixture_object; \ + object->teardown_fn = &wrapper_##fixture_name##_##test_name##_teardown; \ object->termsig = signal; \ object->timeout = tmout; \ _##fixture_name##_##test_name##_object = object; \ @@ -912,6 +917,8 @@ struct __test_metadata { struct __fixture_variant_metadata *); pid_t pid; /* pid of test when being run */ struct __fixture_metadata *fixture; + void (*teardown_fn)(bool in_parent, struct __test_metadata *_metadata, + void *self, const void *variant); int termsig; int exit_code; int trigger; /* extra handler after the evaluation */ -- cgit v1.2.3 From f46ddc2cbac34d73f959c798505d81413866ecf0 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:29 +0200 Subject: selftests: harness: Add "variant" and "self" to test metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get rid of setjmp()/longjmp(), the variant and self need to be usable from __bail(). Make them available from the test metadata. Signed-off-by: Thomas Weißschuh Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-11-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index acb476093b74..088c875df91a 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -423,6 +423,8 @@ self = &self_private; \ } \ } \ + _metadata->variant = variant->data; \ + _metadata->self = self; \ if (setjmp(_metadata->env) == 0) { \ /* _metadata and potentially self are shared with all forks. */ \ child = fork(); \ @@ -926,6 +928,8 @@ struct __test_metadata { bool aborted; /* stopped test due to failed ASSERT */ bool *no_teardown; /* fixture needs teardown */ jmp_buf env; /* for exiting out of test early */ + void *self; + const void *variant; struct __test_results *results; struct __test_metadata *prev, *next; }; -- cgit v1.2.3 From 869c788909b93a78ead1ca28c42b95eeb0779215 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 5 May 2025 17:15:30 +0200 Subject: selftests: harness: Stop using setjmp()/longjmp() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usage of longjmp() was added to ensure that teardown is always run in commit 63e6b2a42342 ("selftests/harness: Run TEARDOWN for ASSERT failures") However instead of calling longjmp() to the teardown handler it is easier to just call the teardown handler directly from __bail(). Any potential duplicate teardown invocations are harmless as the actual handler will only ever be executed once since commit fff37bd32c76 ("selftests/harness: Fix fixture teardown"). Additionally this removes a incompatibility with nolibc, which does not support setjmp()/longjmp(). Signed-off-by: Thomas Weißschuh Acked-by: Shuah Khan Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-12-ee4dd5257135@linutronix.de Signed-off-by: Thomas Weißschuh --- tools/testing/selftests/kselftest_harness.h | 45 ++++++++++------------------- 1 file changed, 15 insertions(+), 30 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 088c875df91a..2925e47db995 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -67,7 +67,6 @@ #include #include #include -#include #include "kselftest.h" @@ -178,9 +177,7 @@ struct __test_metadata *_metadata, \ struct __fixture_variant_metadata __attribute__((unused)) *variant) \ { \ - if (setjmp(_metadata->env) == 0) \ - test_name(_metadata); \ - __test_check_assert(_metadata); \ + test_name(_metadata); \ } \ static struct __test_metadata _##test_name##_object = \ { .name = #test_name, \ @@ -425,24 +422,20 @@ } \ _metadata->variant = variant->data; \ _metadata->self = self; \ - if (setjmp(_metadata->env) == 0) { \ - /* _metadata and potentially self are shared with all forks. */ \ - child = fork(); \ - if (child == 0) { \ - fixture_name##_setup(_metadata, self, variant->data); \ - /* Let setup failure terminate early. */ \ - if (_metadata->exit_code) \ - _exit(0); \ - *_metadata->no_teardown = false; \ - fixture_name##_##test_name(_metadata, self, variant->data); \ - } else if (child < 0 || child != waitpid(child, &status, 0)) { \ - ksft_print_msg("ERROR SPAWNING TEST GRANDCHILD\n"); \ - _metadata->exit_code = KSFT_FAIL; \ - } \ - } \ + /* _metadata and potentially self are shared with all forks. */ \ + child = fork(); \ if (child == 0) { \ + fixture_name##_setup(_metadata, self, variant->data); \ + /* Let setup failure terminate early. */ \ + if (_metadata->exit_code) \ + _exit(0); \ + *_metadata->no_teardown = false; \ + fixture_name##_##test_name(_metadata, self, variant->data); \ _metadata->teardown_fn(false, _metadata, self, variant->data); \ _exit(0); \ + } else if (child < 0 || child != waitpid(child, &status, 0)) { \ + ksft_print_msg("ERROR SPAWNING TEST GRANDCHILD\n"); \ + _metadata->exit_code = KSFT_FAIL; \ } \ _metadata->teardown_fn(true, _metadata, self, variant->data); \ munmap(_metadata->no_teardown, sizeof(*_metadata->no_teardown)); \ @@ -456,7 +449,6 @@ /* Forward signal to __wait_for_test(). */ \ kill(getpid(), WTERMSIG(status)); \ } \ - __test_check_assert(_metadata); \ } \ static void wrapper_##fixture_name##_##test_name##_teardown( \ bool in_parent, struct __test_metadata *_metadata, \ @@ -927,7 +919,6 @@ struct __test_metadata { int timeout; /* seconds to wait for test timeout */ bool aborted; /* stopped test due to failed ASSERT */ bool *no_teardown; /* fixture needs teardown */ - jmp_buf env; /* for exiting out of test early */ void *self; const void *variant; struct __test_results *results; @@ -963,19 +954,14 @@ static inline int __bail(int for_realz, struct __test_metadata *t) { /* if this is ASSERT, return immediately. */ if (for_realz) { - t->aborted = true; - longjmp(t->env, 1); + if (t->teardown_fn) + t->teardown_fn(false, t, t->self, t->variant); + abort(); } /* otherwise, end the for loop and continue. */ return 0; } -static inline void __test_check_assert(struct __test_metadata *t) -{ - if (t->aborted) - abort(); -} - static void __wait_for_test(struct __test_metadata *t) { /* @@ -1208,7 +1194,6 @@ static void __run_test(struct __fixture_metadata *f, t->trigger = 0; t->aborted = false; t->no_teardown = NULL; - memset(t->env, 0, sizeof(t->env)); memset(t->results->reason, 0, sizeof(t->results->reason)); snprintf(test_name, sizeof(test_name), "%s%s%s.%s", -- cgit v1.2.3