summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-10 07:15:14 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-10 07:15:14 +0300
commit861ea34546dcde8600878d5e7f746795f22fc818 (patch)
tree96749c0547e55fbeccd4e8d309ec767788de3cb9
parentd16738a4e79e55b2c3c9ff4fb7b74a4a24723515 (diff)
parenta5f00be9b3b07d92c6689997403851a32e1874cc (diff)
downloadlinux-861ea34546dcde8600878d5e7f746795f22fc818.tar.xz
Merge tag 'nolibc-20260206-for-7.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc
Pull nolibc updates from Thomas Weißschuh: - All time-related functionality uses 64-bit timestamps for y2038 compatibility - fread() and fskeek() support - ptrace() support - Addition of libc-test to the regular kselftests - Smaller cleanups and fixes to the code and build system * tag 'nolibc-20260206-for-7.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/nolibc/linux-nolibc: (25 commits) tools/nolibc: Add a simple test for writing to a FILE and reading it back tools/nolibc: Add fseek() to stdio.h tools/nolibc: Add fread() to stdio.h selftests/nolibc: also test libc-test through regular selftest framework selftests/nolibc: scope custom flags to the nolibc-test target selftests/nolibc: try to read from stdin in readv_zero test selftests/nolibc: always build sparc32 tests with -mcpu=v8 tools/nolibc: align sys_vfork() with sys_fork() selftests/nolibc: drop NOLIBC_SYSROOT=0 logic selftests/nolibc: add static assertions around time types handling tools/nolibc: add __nolibc_static_assert() tools/nolibc: add compiler version detection macros tools/nolibc: remove time conversions selftests/nolibc: test compatibility of nolibc and kernel time types tools/nolibc: always use 64-bit time types tools/nolibc: use custom structs timespec and timeval tools/nolibc/select: avoid libgcc 64-bit multiplications tools/nolibc/gettimeofday: avoid libgcc 64-bit divisions tools/nolibc: prefer explicit 64-bit time-related system calls tools/nolibc/time: drop invocation of gettimeofday system call ...
-rw-r--r--tools/include/nolibc/Makefile6
-rw-r--r--tools/include/nolibc/arch-s390.h11
-rw-r--r--tools/include/nolibc/compiler.h24
-rw-r--r--tools/include/nolibc/nolibc.h1
-rw-r--r--tools/include/nolibc/poll.h14
-rw-r--r--tools/include/nolibc/std.h2
-rw-r--r--tools/include/nolibc/stdio.h53
-rw-r--r--tools/include/nolibc/sys.h18
-rw-r--r--tools/include/nolibc/sys/ptrace.h33
-rw-r--r--tools/include/nolibc/sys/select.h25
-rw-r--r--tools/include/nolibc/sys/time.h6
-rw-r--r--tools/include/nolibc/sys/timerfd.h32
-rw-r--r--tools/include/nolibc/time.h102
-rw-r--r--tools/include/nolibc/types.h17
-rw-r--r--tools/testing/selftests/nolibc/Makefile14
-rw-r--r--tools/testing/selftests/nolibc/Makefile.nolibc8
-rw-r--r--tools/testing/selftests/nolibc/nolibc-test.c86
17 files changed, 299 insertions, 153 deletions
diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile
index 8118e22844f1..1958dda98895 100644
--- a/tools/include/nolibc/Makefile
+++ b/tools/include/nolibc/Makefile
@@ -54,6 +54,7 @@ all_files := \
sys/mman.h \
sys/mount.h \
sys/prctl.h \
+ sys/ptrace.h \
sys/random.h \
sys/reboot.h \
sys/resource.h \
@@ -103,9 +104,12 @@ headers_standalone: headers
$(Q)$(MAKE) -C $(srctree) headers
$(Q)$(MAKE) -C $(srctree) headers_install INSTALL_HDR_PATH=$(OUTPUT)sysroot
+CFLAGS_s390 := -m64
+CFLAGS := $(CFLAGS_$(ARCH))
+
headers_check: headers_standalone
$(Q)for header in $(filter-out crt.h std.h,$(all_files)); do \
- $(CC) $(CLANG_CROSS_FLAGS) -Wall -Werror -nostdinc -fsyntax-only -x c /dev/null \
+ $(CC) $(CFLAGS) $(CLANG_CROSS_FLAGS) -Wall -Werror -nostdinc -fsyntax-only -x c /dev/null \
-I$(or $(objtree),$(srctree))/usr/include -include $$header -include $$header || exit 1; \
done
diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h
index 74125a254ce3..904281e95f99 100644
--- a/tools/include/nolibc/arch-s390.h
+++ b/tools/include/nolibc/arch-s390.h
@@ -5,6 +5,10 @@
#ifndef _NOLIBC_ARCH_S390_H
#define _NOLIBC_ARCH_S390_H
+
+#include "types.h"
+
+#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/unistd.h>
@@ -186,4 +190,11 @@ pid_t sys_fork(void)
}
#define sys_fork sys_fork
+static __attribute__((unused))
+pid_t sys_vfork(void)
+{
+ return my_syscall5(__NR_clone, 0, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0);
+}
+#define sys_vfork sys_vfork
+
#endif /* _NOLIBC_ARCH_S390_H */
diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h
index 87090bbc53e0..a8c7619dcdde 100644
--- a/tools/include/nolibc/compiler.h
+++ b/tools/include/nolibc/compiler.h
@@ -47,4 +47,28 @@
# define __nolibc_fallthrough do { } while (0)
#endif /* __nolibc_has_attribute(fallthrough) */
+#define __nolibc_version(_major, _minor, _patch) ((_major) * 10000 + (_minor) * 100 + (_patch))
+
+#ifdef __GNUC__
+# define __nolibc_gnuc_version \
+ __nolibc_version(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+#else
+# define __nolibc_gnuc_version 0
+#endif /* __GNUC__ */
+
+#ifdef __clang__
+# define __nolibc_clang_version \
+ __nolibc_version(__clang_major__, __clang_minor__, __clang_patchlevel__)
+#else
+# define __nolibc_clang_version 0
+#endif /* __clang__ */
+
+#if __STDC_VERSION__ >= 201112L || \
+ __nolibc_gnuc_version >= __nolibc_version(4, 6, 0) || \
+ __nolibc_clang_version >= __nolibc_version(3, 0, 0)
+# define __nolibc_static_assert(_t) _Static_assert(_t, "")
+#else
+# define __nolibc_static_assert(_t)
+#endif
+
#endif /* _NOLIBC_COMPILER_H */
diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
index 272dfc961158..9c7f43b9218b 100644
--- a/tools/include/nolibc/nolibc.h
+++ b/tools/include/nolibc/nolibc.h
@@ -101,6 +101,7 @@
#include "sys/mman.h"
#include "sys/mount.h"
#include "sys/prctl.h"
+#include "sys/ptrace.h"
#include "sys/random.h"
#include "sys/reboot.h"
#include "sys/resource.h"
diff --git a/tools/include/nolibc/poll.h b/tools/include/nolibc/poll.h
index 0d053f93ea99..e854c94647b1 100644
--- a/tools/include/nolibc/poll.h
+++ b/tools/include/nolibc/poll.h
@@ -23,24 +23,22 @@
static __attribute__((unused))
int sys_poll(struct pollfd *fds, int nfds, int timeout)
{
-#if defined(__NR_ppoll)
- struct timespec t;
+#if defined(__NR_ppoll_time64)
+ struct __kernel_timespec t;
if (timeout >= 0) {
t.tv_sec = timeout / 1000;
t.tv_nsec = (timeout % 1000) * 1000000;
}
- return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
-#elif defined(__NR_ppoll_time64)
- struct __kernel_timespec t;
+ return my_syscall5(__NR_ppoll_time64, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
+#else
+ struct __kernel_old_timespec t;
if (timeout >= 0) {
t.tv_sec = timeout / 1000;
t.tv_nsec = (timeout % 1000) * 1000000;
}
- return my_syscall5(__NR_ppoll_time64, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
-#else
- return my_syscall3(__NR_poll, fds, nfds, timeout);
+ return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0);
#endif
}
diff --git a/tools/include/nolibc/std.h b/tools/include/nolibc/std.h
index 392f4dd94158..b9a116123902 100644
--- a/tools/include/nolibc/std.h
+++ b/tools/include/nolibc/std.h
@@ -29,6 +29,6 @@ typedef unsigned long nlink_t;
typedef int64_t off_t;
typedef signed long blksize_t;
typedef signed long blkcnt_t;
-typedef __kernel_time_t time_t;
+typedef __kernel_time64_t time_t;
#endif /* _NOLIBC_STD_H */
diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
index 1f16dab2ac88..233318b0d0f0 100644
--- a/tools/include/nolibc/stdio.h
+++ b/tools/include/nolibc/stdio.h
@@ -170,7 +170,7 @@ int putchar(int c)
}
-/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
+/* fwrite(), fread(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
/* internal fwrite()-like function which only takes a size and returns 0 on
* success or EOF on error. It automatically retries on short writes.
@@ -204,6 +204,38 @@ size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
return written;
}
+/* internal fread()-like function which only takes a size and returns 0 on
+ * success or EOF on error. It automatically retries on short reads.
+ */
+static __attribute__((unused))
+int _fread(void *buf, size_t size, FILE *stream)
+{
+ int fd = fileno(stream);
+ ssize_t ret;
+
+ while (size) {
+ ret = read(fd, buf, size);
+ if (ret <= 0)
+ return EOF;
+ size -= ret;
+ buf += ret;
+ }
+ return 0;
+}
+
+static __attribute__((unused))
+size_t fread(void *s, size_t size, size_t nmemb, FILE *stream)
+{
+ size_t nread;
+
+ for (nread = 0; nread < nmemb; nread++) {
+ if (_fread(s, size, stream) != 0)
+ break;
+ s += size;
+ }
+ return nread;
+}
+
static __attribute__((unused))
int fputs(const char *s, FILE *stream)
{
@@ -240,6 +272,25 @@ char *fgets(char *s, int size, FILE *stream)
}
+/* fseek */
+static __attribute__((unused))
+int fseek(FILE *stream, long offset, int whence)
+{
+ int fd = fileno(stream);
+ off_t ret;
+
+ ret = lseek(fd, offset, whence);
+
+ /* lseek() and fseek() differ in that lseek returns the new
+ * position or -1, fseek() returns either 0 or -1.
+ */
+ if (ret >= 0)
+ return 0;
+
+ return -1;
+}
+
+
/* minimal printf(). It supports the following formats:
* - %[l*]{d,u,c,x,p}
* - %s
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 847af1ccbdc9..403ee9ce8389 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -22,7 +22,7 @@
#include <linux/time.h>
#include <linux/auxvec.h>
#include <linux/fcntl.h> /* for O_* and AT_* */
-#include <linux/sched.h> /* for clone_args */
+#include <linux/sched.h> /* for CLONE_* */
#include <linux/stat.h> /* for statx() */
#include "errno.h"
@@ -363,19 +363,11 @@ pid_t fork(void)
static __attribute__((unused))
pid_t sys_vfork(void)
{
-#if defined(__NR_vfork)
+#if defined(__NR_clone)
+ /* See the note in sys_fork(). */
+ return my_syscall5(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0, 0);
+#elif defined(__NR_vfork)
return my_syscall0(__NR_vfork);
-#else
- /*
- * clone() could be used but has different argument orders per
- * architecture.
- */
- struct clone_args args = {
- .flags = CLONE_VM | CLONE_VFORK,
- .exit_signal = SIGCHLD,
- };
-
- return my_syscall2(__NR_clone3, &args, sizeof(args));
#endif
}
#endif
diff --git a/tools/include/nolibc/sys/ptrace.h b/tools/include/nolibc/sys/ptrace.h
new file mode 100644
index 000000000000..72ca28541633
--- /dev/null
+++ b/tools/include/nolibc/sys/ptrace.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * ptrace for NOLIBC
+ * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
+ * Copyright (C) 2025 Intel Corporation
+ */
+
+/* make sure to include all global symbols */
+#include "../nolibc.h"
+
+#ifndef _NOLIBC_SYS_PTRACE_H
+#define _NOLIBC_SYS_PTRACE_H
+
+#include "../sys.h"
+
+#include <linux/ptrace.h>
+
+/*
+ * long ptrace(int op, pid_t pid, void *addr, void *data);
+ */
+static __attribute__((unused))
+long sys_ptrace(int op, pid_t pid, void *addr, void *data)
+{
+ return my_syscall4(__NR_ptrace, op, pid, addr, data);
+}
+
+static __attribute__((unused))
+ssize_t ptrace(int op, pid_t pid, void *addr, void *data)
+{
+ return __sysret(sys_ptrace(op, pid, addr, data));
+}
+
+#endif /* _NOLIBC_SYS_PTRACE_H */
diff --git a/tools/include/nolibc/sys/select.h b/tools/include/nolibc/sys/select.h
index 2a5619c01277..80cb3755ba18 100644
--- a/tools/include/nolibc/sys/select.h
+++ b/tools/include/nolibc/sys/select.h
@@ -63,33 +63,22 @@ typedef struct {
static __attribute__((unused))
int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
{
-#if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect)
- struct sel_arg_struct {
- unsigned long n;
- fd_set *r, *w, *e;
- struct timeval *t;
- } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout };
- return my_syscall1(__NR_select, &arg);
-#elif defined(__NR__newselect)
- return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout);
-#elif defined(__NR_select)
- return my_syscall5(__NR_select, nfds, rfds, wfds, efds, timeout);
-#elif defined(__NR_pselect6)
- struct timespec t;
+#if defined(__NR_pselect6_time64)
+ struct __kernel_timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
- t.tv_nsec = timeout->tv_usec * 1000;
+ t.tv_nsec = (uint32_t)timeout->tv_usec * 1000;
}
- return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
+ return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
#else
- struct __kernel_timespec t;
+ struct __kernel_old_timespec t;
if (timeout) {
t.tv_sec = timeout->tv_sec;
- t.tv_nsec = timeout->tv_usec * 1000;
+ t.tv_nsec = (uint32_t)timeout->tv_usec * 1000;
}
- return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
+ return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
#endif
}
diff --git a/tools/include/nolibc/sys/time.h b/tools/include/nolibc/sys/time.h
index 33782a19aae9..afdb7e326df1 100644
--- a/tools/include/nolibc/sys/time.h
+++ b/tools/include/nolibc/sys/time.h
@@ -22,9 +22,6 @@ static int sys_clock_gettime(clockid_t clockid, struct timespec *tp);
static __attribute__((unused))
int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
{
-#ifdef __NR_gettimeofday
- return my_syscall2(__NR_gettimeofday, tv, tz);
-#else
(void) tz; /* Non-NULL tz is undefined behaviour */
struct timespec tp;
@@ -33,11 +30,10 @@ int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
ret = sys_clock_gettime(CLOCK_REALTIME, &tp);
if (!ret && tv) {
tv->tv_sec = tp.tv_sec;
- tv->tv_usec = tp.tv_nsec / 1000;
+ tv->tv_usec = (uint32_t)tp.tv_nsec / 1000;
}
return ret;
-#endif
}
static __attribute__((unused))
diff --git a/tools/include/nolibc/sys/timerfd.h b/tools/include/nolibc/sys/timerfd.h
index 5dd61030c991..29fd92bd47d2 100644
--- a/tools/include/nolibc/sys/timerfd.h
+++ b/tools/include/nolibc/sys/timerfd.h
@@ -32,16 +32,12 @@ int timerfd_create(int clockid, int 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);
+#if defined(__NR_timerfd_gettime64)
+ __nolibc_assert_time64_type(curr_value->it_value.tv_sec);
+ return my_syscall2(__NR_timerfd_gettime64, fd, curr_value);
#else
- 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;
+ __nolibc_assert_native_time64();
+ return my_syscall2(__NR_timerfd_gettime, fd, curr_value);
#endif
}
@@ -56,20 +52,12 @@ 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);
+#if defined(__NR_timerfd_settime64)
+ __nolibc_assert_time64_type(new_value->it_value.tv_sec);
+ return my_syscall4(__NR_timerfd_settime64, fd, flags, new_value, old_value);
#else
- 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;
+ __nolibc_assert_native_time64();
+ return my_syscall4(__NR_timerfd_settime, fd, flags, new_value, old_value);
#endif
}
diff --git a/tools/include/nolibc/time.h b/tools/include/nolibc/time.h
index 48e78f8becf9..f9257d6a7878 100644
--- a/tools/include/nolibc/time.h
+++ b/tools/include/nolibc/time.h
@@ -18,19 +18,11 @@
#include <linux/signal.h>
#include <linux/time.h>
-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;
-}
+#define __nolibc_assert_time64_type(t) \
+ __nolibc_static_assert(sizeof(t) == 8)
-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;
-}
+#define __nolibc_assert_native_time64() \
+ __nolibc_assert_time64_type(__kernel_old_time_t)
/*
* int clock_getres(clockid_t clockid, struct timespec *res);
@@ -43,16 +35,12 @@ void __nolibc_timespec_kernel_to_user(const struct __kernel_timespec *kts, struc
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);
+#if defined(__NR_clock_getres_time64)
+ __nolibc_assert_time64_type(res->tv_sec);
+ return my_syscall2(__NR_clock_getres_time64, clockid, res);
#else
- 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;
+ __nolibc_assert_native_time64();
+ return my_syscall2(__NR_clock_getres, clockid, res);
#endif
}
@@ -65,16 +53,12 @@ int clock_getres(clockid_t clockid, struct timespec *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);
+#if defined(__NR_clock_gettime64)
+ __nolibc_assert_time64_type(tp->tv_sec);
+ return my_syscall2(__NR_clock_gettime64, clockid, tp);
#else
- 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;
+ __nolibc_assert_native_time64();
+ return my_syscall2(__NR_clock_gettime, clockid, tp);
#endif
}
@@ -87,13 +71,12 @@ int clock_gettime(clockid_t clockid, struct timespec *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);
+#if defined(__NR_clock_settime64)
+ __nolibc_assert_time64_type(tp->tv_sec);
+ return my_syscall2(__NR_clock_settime64, clockid, tp);
#else
- struct __kernel_timespec ktp;
-
- __nolibc_timespec_user_to_kernel(tp, &ktp);
- return my_syscall2(__NR_clock_settime64, clockid, &ktp);
+ __nolibc_assert_native_time64();
+ return my_syscall2(__NR_clock_settime, clockid, tp);
#endif
}
@@ -107,17 +90,12 @@ static __attribute__((unused))
int sys_clock_nanosleep(clockid_t clockid, int flags, const struct timespec *rqtp,
struct timespec *rmtp)
{
-#if defined(__NR_clock_nanosleep)
- return my_syscall4(__NR_clock_nanosleep, clockid, flags, rqtp, rmtp);
+#if defined(__NR_clock_nanosleep_time64)
+ __nolibc_assert_time64_type(rqtp->tv_sec);
+ return my_syscall4(__NR_clock_nanosleep_time64, clockid, flags, rqtp, rmtp);
#else
- struct __kernel_timespec krqtp, krmtp;
- int ret;
-
- __nolibc_timespec_user_to_kernel(rqtp, &krqtp);
- ret = my_syscall4(__NR_clock_nanosleep_time64, clockid, flags, &krqtp, &krmtp);
- if (rmtp)
- __nolibc_timespec_kernel_to_user(&krmtp, rmtp);
- return ret;
+ __nolibc_assert_native_time64();
+ return my_syscall4(__NR_clock_nanosleep, clockid, flags, rqtp, rmtp);
#endif
}
@@ -189,16 +167,12 @@ int timer_delete(timer_t 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);
+#if defined(__NR_timer_gettime64)
+ __nolibc_assert_time64_type(curr_value->it_value.tv_sec);
+ return my_syscall2(__NR_timer_gettime64, timerid, curr_value);
#else
- 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;
+ __nolibc_assert_native_time64();
+ return my_syscall2(__NR_timer_gettime, timerid, curr_value);
#endif
}
@@ -212,20 +186,12 @@ 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);
+#if defined(__NR_timer_settime64)
+ __nolibc_assert_time64_type(new_value->it_value.tv_sec);
+ return my_syscall4(__NR_timer_settime64, timerid, flags, new_value, old_value);
#else
- 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;
+ __nolibc_assert_native_time64();
+ return my_syscall4(__NR_timer_settime, timerid, flags, new_value, old_value);
#endif
}
diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h
index 470a5f77bc0f..8f3cb18df7f1 100644
--- a/tools/include/nolibc/types.h
+++ b/tools/include/nolibc/types.h
@@ -13,9 +13,24 @@
#include "std.h"
#include <linux/mman.h>
#include <linux/stat.h>
-#include <linux/time.h>
+#include <linux/time_types.h>
#include <linux/wait.h>
+struct timespec {
+ time_t tv_sec;
+ int64_t tv_nsec;
+};
+#define _STRUCT_TIMESPEC
+
+/* Never use with system calls */
+struct timeval {
+ time_t tv_sec;
+ int64_t tv_usec;
+};
+
+#define timeval __nolibc_kernel_timeval
+#include <linux/time.h>
+#undef timeval
/* Only the generic macros and types may be defined here. The arch-specific
* ones such as the O_RDONLY and related macros used by fcntl() and open()
diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile
index 40f5c2908dda..0370489d938b 100644
--- a/tools/testing/selftests/nolibc/Makefile
+++ b/tools/testing/selftests/nolibc/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-TEST_GEN_PROGS := nolibc-test
+TEST_GEN_PROGS := nolibc-test libc-test
include ../lib.mk
include $(top_srcdir)/scripts/Makefile.compiler
@@ -9,16 +9,16 @@ cc-option = $(call __cc-option, $(CC),,$(1),$(2))
include Makefile.include
-CFLAGS = -nostdlib -nostdinc -static \
+$(OUTPUT)/nolibc-test: CFLAGS = -nostdlib -nostdinc -static \
-isystem $(top_srcdir)/tools/include/nolibc -isystem $(top_srcdir)/usr/include \
$(CFLAGS_NOLIBC_TEST)
-
-ifeq ($(LLVM),)
-LDLIBS := -lgcc
-endif
-
+$(OUTPUT)/nolibc-test: LDLIBS = $(if $(LLVM),,-lgcc)
$(OUTPUT)/nolibc-test: nolibc-test.c nolibc-test-linkage.c | headers
+$(OUTPUT)/libc-test: nolibc-test.c nolibc-test-linkage.c
+ $(call msg,CC,,$@)
+ $(Q)$(LINK.c) $^ -o $@
+
help:
@echo "For the custom nolibc testsuite use '$(MAKE) -f Makefile.nolibc'; available targets:"
@$(MAKE) -f Makefile.nolibc help
diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc
index f9d43cbdc894..f5704193038f 100644
--- a/tools/testing/selftests/nolibc/Makefile.nolibc
+++ b/tools/testing/selftests/nolibc/Makefile.nolibc
@@ -226,7 +226,7 @@ CFLAGS_mipsn32be = -EB -mabi=n32 -march=mips64r6
CFLAGS_mips64le = -EL -mabi=64 -march=mips64r6
CFLAGS_mips64be = -EB -mabi=64 -march=mips64r2
CFLAGS_loongarch = $(if $(LLVM),-fuse-ld=lld)
-CFLAGS_sparc32 = $(call cc-option,-m32)
+CFLAGS_sparc32 = $(call cc-option,-m32) -mcpu=v8
CFLAGS_sh4 = -ml -m4
ifeq ($(origin XARCH),command line)
CFLAGS_XARCH = $(CFLAGS_$(XARCH))
@@ -302,15 +302,9 @@ sysroot/$(ARCH)/include:
$(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)
nolibc-test: nolibc-test.c nolibc-test-linkage.c sysroot/$(ARCH)/include
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
-nostdlib -nostdinc -static -Isysroot/$(ARCH)/include nolibc-test.c nolibc-test-linkage.c $(LIBGCC)
-else
-nolibc-test: nolibc-test.c nolibc-test-linkage.c
- $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
- -nostdlib -static -include $(srctree)/tools/include/nolibc/nolibc.h nolibc-test.c nolibc-test-linkage.c $(LIBGCC)
-endif
libc-test: nolibc-test.c nolibc-test-linkage.c
$(QUIET_CC)$(HOSTCC) -o $@ nolibc-test.c nolibc-test-linkage.c
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 3c5a226dad3a..1b9d3b2e2491 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -17,6 +17,7 @@
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/prctl.h>
+#include <sys/ptrace.h>
#include <sys/random.h>
#include <sys/reboot.h>
#include <sys/resource.h>
@@ -877,6 +878,58 @@ int test_file_stream(void)
return 0;
}
+int test_file_stream_wsr(void)
+{
+ const char dataout[] = "foo";
+ const size_t datasz = sizeof(dataout);
+ char datain[datasz];
+ int fd, r;
+ FILE *f;
+
+ fd = open("/tmp", O_TMPFILE | O_RDWR, 0644);
+ if (fd == -1)
+ return -1;
+
+ f = fdopen(fd, "w+");
+ if (!f)
+ return -1;
+
+ errno = 0;
+ r = fwrite(dataout, 1, datasz, f);
+ if (r != datasz)
+ return -1;
+
+ /* Attempt to read from the file without rewinding,
+ * we should read 0 items.
+ */
+ r = fread(datain, 1, datasz, f);
+ if (r)
+ return -1;
+
+ /* Rewind the file to the start */
+ r = fseek(f, 0, SEEK_SET);
+ if (r)
+ return -1;
+
+ /* Attempt to read back more than was written to
+ * make sure we handle short reads properly.
+ * fread() should return the number of complete items.
+ */
+ r = fread(datain, 1, datasz + 1, f);
+ if (r != datasz)
+ return -1;
+
+ /* Data we read should match the data we just wrote */
+ if (memcmp(datain, dataout, datasz) != 0)
+ return -1;
+
+ r = fclose(f);
+ if (r)
+ return -1;
+
+ return 0;
+}
+
enum fork_type {
FORK_STANDARD,
FORK_VFORK,
@@ -1351,6 +1404,7 @@ int run_syscall(int min, int max)
CASE_TEST(fchdir_stdin); EXPECT_SYSER(1, fchdir(STDIN_FILENO), -1, ENOTDIR); break;
CASE_TEST(fchdir_badfd); EXPECT_SYSER(1, fchdir(-1), -1, EBADF); break;
CASE_TEST(file_stream); EXPECT_SYSZR(1, test_file_stream()); break;
+ CASE_TEST(file_stream_wsr); EXPECT_SYSZR(1, test_file_stream_wsr()); break;
CASE_TEST(fork); EXPECT_SYSZR(1, test_fork(FORK_STANDARD)); 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;
@@ -1403,9 +1457,10 @@ int run_syscall(int min, int max)
CASE_TEST(write_badf); EXPECT_SYSER(1, write(-1, &tmp, 1), -1, EBADF); break;
CASE_TEST(write_zero); EXPECT_SYSZR(1, write(1, &tmp, 0)); break;
CASE_TEST(readv_badf); EXPECT_SYSER(1, readv(-1, &iov_one, 1), -1, EBADF); break;
- CASE_TEST(readv_zero); EXPECT_SYSZR(1, readv(1, NULL, 0)); break;
+ CASE_TEST(readv_zero); EXPECT_SYSZR(1, readv(0, NULL, 0)); break;
CASE_TEST(writev_badf); EXPECT_SYSER(1, writev(-1, &iov_one, 1), -1, EBADF); break;
CASE_TEST(writev_zero); EXPECT_SYSZR(1, writev(1, NULL, 0)); break;
+ CASE_TEST(ptrace); EXPECT_SYSER(1, ptrace(PTRACE_CONT, getpid(), NULL, NULL), -1, ESRCH); 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;
@@ -1428,6 +1483,34 @@ int test_difftime(void)
return 0;
}
+int test_time_types(void)
+{
+#ifdef NOLIBC
+ struct __kernel_timespec kts;
+ struct timespec ts;
+
+ if (!__builtin_types_compatible_p(time_t, __kernel_time64_t))
+ return 1;
+
+ if (sizeof(ts) != sizeof(kts))
+ return 1;
+
+ if (!__builtin_types_compatible_p(__typeof__(ts.tv_sec), __typeof__(kts.tv_sec)))
+ return 1;
+
+ if (!__builtin_types_compatible_p(__typeof__(ts.tv_nsec), __typeof__(kts.tv_nsec)))
+ return 1;
+
+ if (offsetof(__typeof__(ts), tv_sec) != offsetof(__typeof__(kts), tv_sec))
+ return 1;
+
+ if (offsetof(__typeof__(ts), tv_nsec) != offsetof(__typeof__(kts), tv_nsec))
+ return 1;
+#endif /* NOLIBC */
+
+ return 0;
+}
+
int run_stdlib(int min, int max)
{
int test;
@@ -1553,6 +1636,7 @@ int run_stdlib(int min, int max)
CASE_TEST(difftime); EXPECT_ZR(1, test_difftime()); break;
CASE_TEST(memchr_foobar6_o); EXPECT_STREQ(1, memchr("foobar", 'o', 6), "oobar"); break;
CASE_TEST(memchr_foobar3_b); EXPECT_STRZR(1, memchr("foobar", 'b', 3)); break;
+ CASE_TEST(time_types); EXPECT_ZR(is_nolibc, test_time_types()); break;
case __LINE__:
return ret; /* must be last */