diff --git a/third_party/lss/DIR_METADATA b/third_party/lss/DIR_METADATA new file mode 100644 index 000000000000..eccfd35fab8f --- /dev/null +++ b/third_party/lss/DIR_METADATA @@ -0,0 +1,12 @@ +# Metadata information for this directory. +# +# For more information on DIR_METADATA files, see: +# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md +# +# For the schema of this file, see Metadata message: +# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto + +os: LINUX +monorail { + project: "linux-syscall-support" +} diff --git a/third_party/lss/LICENSE b/third_party/lss/LICENSE new file mode 100644 index 000000000000..58ab3fba9d4c --- /dev/null +++ b/third_party/lss/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2005-2011, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/lss/OWNERS b/third_party/lss/OWNERS new file mode 100644 index 000000000000..29b02fa1143e --- /dev/null +++ b/third_party/lss/OWNERS @@ -0,0 +1,2 @@ +mseaborn@chromium.org +vapier@chromium.org diff --git a/third_party/lss/README.md b/third_party/lss/README.md index 70cbc85311f9..e25abdd218fe 100644 --- a/third_party/lss/README.md +++ b/third_party/lss/README.md @@ -39,6 +39,7 @@ the header itself as this list might be out of date. * MIPS 32-bit o32 ABI * MIPS 32-bit n32 ABI * MIPS 64-bit n64 ABI +* LOONGARCH 64-bit ABI ## API @@ -130,7 +131,7 @@ It only compiles things (does not execute at all). If you commit a change to LSS, please also commit a Chromium change to update `lss_revision` in -[Chromium's DEPS](https://chromium.googlesource.com/chromium/src/+/master/DEPS) +[Chromium's DEPS](https://chromium.googlesource.com/chromium/src/+/HEAD/DEPS) file. This ensures that the LSS change gets tested, so that people who commit later diff --git a/third_party/lss/linux_syscall_support.h b/third_party/lss/linux_syscall_support.h index e4ac22644c0c..99a4b444918d 100644 --- a/third_party/lss/linux_syscall_support.h +++ b/third_party/lss/linux_syscall_support.h @@ -88,7 +88,8 @@ */ #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \ - defined(__aarch64__) || defined(__s390__)) \ + defined(__aarch64__) || defined(__s390__) || defined(__e2k__) || \ + (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch_lp64)) \ && (defined(__linux) || defined(__ANDROID__)) #ifndef SYS_CPLUSPLUS @@ -266,6 +267,12 @@ struct kernel_timeval { long tv_usec; }; +/* include/linux/time.h */ +struct kernel_itimerval { + struct kernel_timeval it_interval; + struct kernel_timeval it_value; +}; + /* include/linux/resource.h */ struct kernel_rusage { struct kernel_timeval ru_utime; @@ -287,7 +294,8 @@ struct kernel_rusage { }; #if defined(__i386__) || defined(__ARM_EABI__) || defined(__ARM_ARCH_3__) \ - || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) + || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) \ + || defined(__e2k__) /* include/asm-{arm,i386,mips,ppc}/signal.h */ struct kernel_old_sigaction { @@ -301,8 +309,8 @@ struct kernel_old_sigaction { } __attribute__((packed,aligned(4))); #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) #define kernel_old_sigaction kernel_sigaction -#elif defined(__aarch64__) - // No kernel_old_sigaction defined for arm64. +#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) + // No kernel_old_sigaction defined for arm64 riscv and loongarch64. #endif /* Some kernel functions (e.g. sigaction() in 2.6.23) require that the @@ -341,7 +349,9 @@ struct kernel_sigaction { void (*sa_sigaction_)(int, siginfo_t *, void *); }; unsigned long sa_flags; +#if !defined(__riscv) && !defined(__loongarch_lp64) void (*sa_restorer)(void); +#endif struct kernel_sigset_t sa_mask; #endif }; @@ -355,6 +365,16 @@ struct kernel_sockaddr { /* include/asm-{arm,aarch64,i386,mips,ppc,s390}/stat.h */ #ifdef __mips__ #if _MIPS_SIM == _MIPS_SIM_ABI64 +typedef unsigned long long kernel_blkcnt_t; +typedef unsigned kernel_blksize_t; +typedef unsigned kernel_dev_t; +typedef unsigned kernel_gid_t; +typedef unsigned long long kernel_ino_t; +typedef unsigned kernel_mode_t; +typedef unsigned kernel_nlink_t; +typedef long long kernel_off_t; +typedef unsigned kernel_time_t; +typedef unsigned kernel_uid_t; struct kernel_stat { #else struct kernel_stat64 { @@ -401,6 +421,28 @@ struct kernel_stat64 { unsigned long __unused4; unsigned long __unused5; }; +#elif defined(__e2k__) +struct kernel_stat64 { + unsigned long long st_dev; + unsigned long long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long long st_rdev; + long long st_size; + int st_blksize; + int __pad2; + unsigned long long st_blocks; + int st_atime_; + unsigned int st_atime_nsec_; + int st_mtime_; + unsigned int st_mtime_nsec_; + int st_ctime_; + unsigned int st_ctime_nsec_; + unsigned int __unused4; + unsigned int __unused5; +}; #else struct kernel_stat64 { unsigned long long st_dev; @@ -427,165 +469,264 @@ struct kernel_stat64 { /* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/stat.h */ #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) +typedef unsigned kernel_blkcnt_t; +typedef unsigned kernel_blksize_t; +typedef unsigned short kernel_dev_t; +typedef unsigned short kernel_gid_t; +typedef unsigned kernel_ino_t; +typedef unsigned short kernel_mode_t; +typedef unsigned short kernel_nlink_t; +typedef unsigned kernel_off_t; +typedef unsigned kernel_time_t; +typedef unsigned short kernel_uid_t; struct kernel_stat { /* The kernel headers suggest that st_dev and st_rdev should be 32bit * quantities encoding 12bit major and 20bit minor numbers in an interleaved * format. In reality, we do not see useful data in the top bits. So, * we'll leave the padding in here, until we find a better solution. */ - unsigned short st_dev; + kernel_dev_t st_dev; short pad1; - unsigned st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - unsigned short st_rdev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; short pad2; - unsigned st_size; - unsigned st_blksize; - unsigned st_blocks; - unsigned st_atime_; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; unsigned st_atime_nsec_; - unsigned st_mtime_; + kernel_time_t st_mtime_; unsigned st_mtime_nsec_; - unsigned st_ctime_; + kernel_time_t st_ctime_; unsigned st_ctime_nsec_; unsigned __unused4; unsigned __unused5; }; #elif defined(__x86_64__) +typedef int64_t kernel_blkcnt_t; +typedef int64_t kernel_blksize_t; +typedef uint64_t kernel_dev_t; +typedef unsigned kernel_gid_t; +typedef uint64_t kernel_ino_t; +typedef unsigned kernel_mode_t; +typedef uint64_t kernel_nlink_t; +typedef int64_t kernel_off_t; +typedef uint64_t kernel_time_t; +typedef unsigned kernel_uid_t; struct kernel_stat { - uint64_t st_dev; - uint64_t st_ino; - uint64_t st_nlink; - unsigned st_mode; - unsigned st_uid; - unsigned st_gid; + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_nlink_t st_nlink; + kernel_mode_t st_mode; + kernel_uid_t st_uid; + kernel_gid_t st_gid; unsigned __pad0; - uint64_t st_rdev; - int64_t st_size; - int64_t st_blksize; - int64_t st_blocks; - uint64_t st_atime_; + kernel_dev_t st_rdev; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; uint64_t st_atime_nsec_; - uint64_t st_mtime_; + kernel_time_t st_mtime_; uint64_t st_mtime_nsec_; - uint64_t st_ctime_; + kernel_time_t st_ctime_; uint64_t st_ctime_nsec_; int64_t __unused4[3]; }; #elif defined(__PPC__) +typedef unsigned long kernel_blkcnt_t; +typedef unsigned long kernel_blksize_t; +typedef unsigned kernel_dev_t; +typedef unsigned kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned long kernel_mode_t; +typedef unsigned short kernel_nlink_t; +typedef long kernel_off_t; +typedef unsigned long kernel_time_t; +typedef unsigned kernel_uid_t; struct kernel_stat { - unsigned st_dev; - unsigned long st_ino; // ino_t - unsigned long st_mode; // mode_t - unsigned short st_nlink; // nlink_t - unsigned st_uid; // uid_t - unsigned st_gid; // gid_t - unsigned st_rdev; - long st_size; // off_t - unsigned long st_blksize; - unsigned long st_blocks; - unsigned long st_atime_; + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_gid_t st_uid; + kernel_uid_t st_gid; + kernel_dev_t st_rdev; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; unsigned long st_atime_nsec_; - unsigned long st_mtime_; + kernel_time_t st_mtime_; unsigned long st_mtime_nsec_; - unsigned long st_ctime_; + kernel_time_t st_ctime_; unsigned long st_ctime_nsec_; unsigned long __unused4; unsigned long __unused5; }; #elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) +typedef int kernel_blkcnt_t; +typedef int kernel_blksize_t; +typedef unsigned kernel_dev_t; +typedef unsigned kernel_gid_t; +typedef unsigned kernel_ino_t; +typedef unsigned kernel_mode_t; +typedef unsigned kernel_nlink_t; +typedef long kernel_off_t; +typedef long kernel_time_t; +typedef unsigned kernel_uid_t; struct kernel_stat { - unsigned st_dev; + kernel_dev_t st_dev; int st_pad1[3]; - unsigned st_ino; - unsigned st_mode; - unsigned st_nlink; - unsigned st_uid; - unsigned st_gid; - unsigned st_rdev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; int st_pad2[2]; - long st_size; + kernel_off_t st_size; int st_pad3; - long st_atime_; + kernel_time_t st_atime_; long st_atime_nsec_; - long st_mtime_; + kernel_time_t st_mtime_; long st_mtime_nsec_; - long st_ctime_; + kernel_time_t st_ctime_; long st_ctime_nsec_; - int st_blksize; - int st_blocks; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; int st_pad4[14]; }; -#elif defined(__aarch64__) +#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) +typedef long kernel_blkcnt_t; +typedef int kernel_blksize_t; +typedef unsigned long kernel_dev_t; +typedef unsigned int kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned int kernel_mode_t; +typedef unsigned int kernel_nlink_t; +typedef long kernel_off_t; +typedef long kernel_time_t; +typedef unsigned int kernel_uid_t; struct kernel_stat { - unsigned long st_dev; - unsigned long st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - unsigned long st_rdev; + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; unsigned long __pad1; - long st_size; - int st_blksize; + kernel_off_t st_size; + kernel_blksize_t st_blksize; int __pad2; - long st_blocks; - long st_atime_; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; unsigned long st_atime_nsec_; - long st_mtime_; + kernel_time_t st_mtime_; unsigned long st_mtime_nsec_; - long st_ctime_; + kernel_time_t st_ctime_; unsigned long st_ctime_nsec_; unsigned int __unused4; unsigned int __unused5; }; #elif defined(__s390x__) +typedef long kernel_blkcnt_t; +typedef unsigned long kernel_blksize_t; +typedef unsigned long kernel_dev_t; +typedef unsigned int kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned int kernel_mode_t; +typedef unsigned long kernel_nlink_t; +typedef unsigned long kernel_off_t; +typedef unsigned long kernel_time_t; +typedef unsigned int kernel_uid_t; struct kernel_stat { - unsigned long st_dev; - unsigned long st_ino; - unsigned long st_nlink; - unsigned int st_mode; - unsigned int st_uid; - unsigned int st_gid; + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_nlink_t st_nlink; + kernel_mode_t st_mode; + kernel_uid_t st_uid; + kernel_gid_t st_gid; unsigned int __pad1; - unsigned long st_rdev; - unsigned long st_size; - unsigned long st_atime_; + kernel_dev_t st_rdev; + kernel_off_t st_size; + kernel_time_t st_atime_; unsigned long st_atime_nsec_; - unsigned long st_mtime_; + kernel_time_t st_mtime_; unsigned long st_mtime_nsec_; - unsigned long st_ctime_; + kernel_time_t st_ctime_; unsigned long st_ctime_nsec_; - unsigned long st_blksize; - long st_blocks; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; unsigned long __unused[3]; }; #elif defined(__s390__) +typedef unsigned long kernel_blkcnt_t; +typedef unsigned long kernel_blksize_t; +typedef unsigned short kernel_dev_t; +typedef unsigned short kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned short kernel_mode_t; +typedef unsigned short kernel_nlink_t; +typedef unsigned long kernel_off_t; +typedef unsigned long kernel_time_t; +typedef unsigned short kernel_uid_t; struct kernel_stat { - unsigned short st_dev; + kernel_dev_t st_dev; unsigned short __pad1; - unsigned long st_ino; - unsigned short st_mode; - unsigned short st_nlink; - unsigned short st_uid; - unsigned short st_gid; - unsigned short st_rdev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; unsigned short __pad2; - unsigned long st_size; - unsigned long st_blksize; - unsigned long st_blocks; - unsigned long st_atime_; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; unsigned long st_atime_nsec_; - unsigned long st_mtime_; + kernel_time_t st_mtime_; unsigned long st_mtime_nsec_; - unsigned long st_ctime_; + kernel_time_t st_ctime_; unsigned long st_ctime_nsec_; unsigned long __unused4; unsigned long __unused5; }; +#elif defined(__e2k__) +typedef unsigned long kernel_blkcnt_t; +typedef unsigned long kernel_blksize_t; +typedef unsigned long kernel_dev_t; +typedef unsigned int kernel_gid_t; +typedef unsigned long kernel_ino_t; +typedef unsigned int kernel_mode_t; +typedef unsigned long kernel_nlink_t; +typedef unsigned long kernel_off_t; +typedef unsigned long kernel_time_t; +typedef unsigned int kernel_uid_t; +struct kernel_stat { + kernel_dev_t st_dev; + kernel_ino_t st_ino; + kernel_mode_t st_mode; + kernel_nlink_t st_nlink; + kernel_uid_t st_uid; + kernel_gid_t st_gid; + kernel_dev_t st_rdev; + kernel_off_t st_size; + kernel_blksize_t st_blksize; + kernel_blkcnt_t st_blocks; + kernel_time_t st_atime_; + unsigned long st_atime_nsec_; + kernel_time_t st_mtime_; + unsigned long st_mtime_nsec_; + kernel_time_t st_ctime_; + unsigned long st_ctime_nsec_; +}; #endif /* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/statfs.h */ @@ -701,6 +842,37 @@ struct kernel_statfs { }; #endif +struct kernel_statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t __reserved; +}; + +struct kernel_statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t __spare0[1]; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct kernel_statx_timestamp stx_atime; + struct kernel_statx_timestamp stx_btime; + struct kernel_statx_timestamp stx_ctime; + struct kernel_statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t stx_mnt_id; + uint64_t __spare2; + uint64_t __spare3[12]; +}; /* Definitions missing from the standard header files */ #ifndef O_DIRECTORY @@ -737,6 +909,18 @@ struct kernel_statfs { #ifndef AT_REMOVEDIR #define AT_REMOVEDIR 0x200 #endif +#ifndef AT_NO_AUTOMOUNT +#define AT_NO_AUTOMOUNT 0x800 +#endif +#ifndef AT_EMPTY_PATH +#define AT_EMPTY_PATH 0x1000 +#endif +#ifndef STATX_BASIC_STATS +#define STATX_BASIC_STATS 0x000007ffU +#endif +#ifndef AT_STATX_SYNC_AS_STAT +#define AT_STATX_SYNC_AS_STAT 0x0000 +#endif #ifndef MREMAP_FIXED #define MREMAP_FIXED 2 #endif @@ -1055,6 +1239,9 @@ struct kernel_statfs { #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_SYSCALL_BASE + 315) #endif +#ifndef __NR_fstatat64 +#define __NR_fstatat64 (__NR_SYSCALL_BASE + 327) +#endif #ifndef __NR_move_pages #define __NR_move_pages (__NR_SYSCALL_BASE + 344) #endif @@ -1065,7 +1252,7 @@ struct kernel_statfs { #define __NR_getrandom (__NR_SYSCALL_BASE + 384) #endif /* End of ARM 3/EABI definitions */ -#elif defined(__aarch64__) +#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) #ifndef __NR_setxattr #define __NR_setxattr 5 #endif @@ -1121,9 +1308,11 @@ struct kernel_statfs { #ifndef __NR_readlinkat #define __NR_readlinkat 78 #endif +#if !defined(__loongarch_lp64) #ifndef __NR_newfstatat #define __NR_newfstatat 79 #endif +#endif #ifndef __NR_set_tid_address #define __NR_set_tid_address 96 #endif @@ -1164,7 +1353,9 @@ struct kernel_statfs { #ifndef __NR_getrandom #define __NR_getrandom 278 #endif -/* End of aarch64 definitions */ +#ifndef __NR_statx +#define __NR_statx 291 +#endif #elif defined(__x86_64__) #ifndef __NR_pread64 #define __NR_pread64 17 @@ -1440,8 +1631,8 @@ struct kernel_statfs { #ifndef __NR_ioprio_get #define __NR_ioprio_get (__NR_Linux + 274) #endif -#ifndef __NT_getrandom -#define (__NR_Linux + 313) +#ifndef __NR_getrandom +#define __NR_getrandom (__NR_Linux + 313) #endif /* End of MIPS (64bit API) definitions */ #else @@ -1879,15 +2070,16 @@ struct kernel_statfs { #endif #undef LSS_RETURN - #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ - || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__)) + #if defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ + || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__) \ + || defined(__e2k__) || defined(__riscv) || defined(__loongarch_lp64) /* Failing system calls return a negative result in the range of * -1..-4095. These are "errno" values with the sign inverted. */ #define LSS_RETURN(type, res) \ do { \ if ((unsigned long)(res) >= (unsigned long)(-4095)) { \ - LSS_ERRNO = -(res); \ + LSS_ERRNO = (int)(-(res)); \ res = -1; \ } \ return (type) (res); \ @@ -2241,7 +2433,7 @@ struct kernel_statfs { #define _LSS_RETURN(type, res, cast) \ do { \ if ((uint64_t)(res) >= (uint64_t)(-4095)) { \ - LSS_ERRNO = -(res); \ + LSS_ERRNO = (int)(-(res)); \ res = -1; \ } \ return (type)(cast)(res); \ @@ -2790,7 +2982,7 @@ struct kernel_statfs { void *newtls, int *child_tidptr) { int64_t __res; { - register uint64_t __flags __asm__("x0") = flags; + register uint64_t __flags __asm__("x0") = (uint64_t)flags; register void *__stack __asm__("x1") = child_stack; register void *__ptid __asm__("x2") = parent_tidptr; register void *__tls __asm__("x3") = newtls; @@ -3373,6 +3565,503 @@ struct kernel_statfs { } LSS_RETURN(int, __ret); } + #elif defined(__riscv) && __riscv_xlen == 64 + #undef LSS_REG + #define LSS_REG(r,a) register int64_t __r##r __asm__("a"#r) = (int64_t)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register int64_t __res_a0 __asm__("a0"); \ + register int64_t __a7 __asm__("a7") = __NR_##name; \ + int64_t __res; \ + __asm__ __volatile__ ("scall\n" \ + : "=r"(__res_a0) \ + : "r"(__a7) , ## args \ + : "memory"); \ + __res = __res_a0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + int64_t __res; + { + register int64_t __res_a0 __asm__("a0"); + register uint64_t __flags __asm__("a0") = flags; + register void *__stack __asm__("a1") = child_stack; + register void *__ptid __asm__("a2") = parent_tidptr; + register void *__tls __asm__("a3") = newtls; + register int *__ctid __asm__("a4") = child_tidptr; + __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "addi %2,%2,-16\n" + "sd %1, 0(%2)\n" + "sd %4, 8(%2)\n" + + /* %a0 = syscall(%a0 = flags, + * %a1 = child_stack, + * %a2 = parent_tidptr, + * %a3 = newtls, + * %a4 = child_tidptr) + */ + "li a7, %8\n" + "scall\n" + + /* if (%a0 != 0) + * return %a0; + */ + "bnez %0, 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ld a1, 0(sp)\n" + "ld a0, 8(sp)\n" + "jalr a1\n" + + /* Call _exit(%a0). + */ + "li a7, %9\n" + "scall\n" + "1:\n" + : "=r" (__res_a0) + : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "cc", "memory"); + __res = __res_a0; + } + LSS_RETURN(int, __res); + } + #elif defined(__e2k__) + + #undef _LSS_BODY + #define _LSS_BODY(nr, type, name, ...) \ + register unsigned long long __res; \ + __asm__ __volatile__ \ + ( \ + "{\n\t" \ + " sdisp %%ctpr1, 0x3\n\t" \ + " addd, s 0x0, %[sys_num], %%b[0]\n\t" \ + LSS_BODY_ASM##nr \ + "}\n\t" \ + "{\n\t" \ + " call %%ctpr1, wbs = %#\n\t" \ + "}\n\t" \ + "{\n\t" \ + " addd, s 0x0, %%b[0], %[res]\n\t" \ + "}\n\t" \ + : [res] "=r" (__res) \ + : \ + LSS_BODY_ARG##nr(__VA_ARGS__) \ + [sys_num] "ri" (__NR_##name) \ + : "ctpr1", "ctpr2", "ctpr3", \ + "b[0]", "b[1]", "b[2]", "b[3]", \ + "b[4]", "b[5]", "b[6]", "b[7]" \ + ); \ + LSS_RETURN(type, __res); + + #undef LSS_BODY + #define LSS_BODY(nr, type, name, args...) \ + _LSS_BODY(nr, type, name, ## args) + + #undef LSS_BODY_ASM0 + #undef LSS_BODY_ASM1 + #undef LSS_BODY_ASM2 + #undef LSS_BODY_ASM3 + #undef LSS_BODY_ASM4 + #undef LSS_BODY_ASM5 + #undef LSS_BODY_ASM6 + + #define LSS_BODY_ASM0 + #define LSS_BODY_ASM1 LSS_BODY_ASM0 \ + " addd, s 0x0, %[arg1], %%b[1]\n\t" + #define LSS_BODY_ASM2 LSS_BODY_ASM1 \ + " addd, s 0x0, %[arg2], %%b[2]\n\t" + #define LSS_BODY_ASM3 LSS_BODY_ASM2 \ + " addd, s 0x0, %[arg3], %%b[3]\n\t" + #define LSS_BODY_ASM4 LSS_BODY_ASM3 \ + " addd, s 0x0, %[arg4], %%b[4]\n\t" + #define LSS_BODY_ASM5 LSS_BODY_ASM4 \ + " addd, s 0x0, %[arg5], %%b[5]\n\t" + #define LSS_BODY_ASM6 LSS_BODY_ASM5 \ + "}\n\t" \ + "{\n\t" \ + " addd, s 0x0, %[arg6], %%b[6]\n\t" + + #undef LSS_SYSCALL_ARG + #define LSS_SYSCALL_ARG(a) ((unsigned long long)(uintptr_t)(a)) + + #undef LSS_BODY_ARG0 + #undef LSS_BODY_ARG1 + #undef LSS_BODY_ARG2 + #undef LSS_BODY_ARG3 + #undef LSS_BODY_ARG4 + #undef LSS_BODY_ARG5 + #undef LSS_BODY_ARG6 + + #define LSS_BODY_ARG0() + #define LSS_BODY_ARG1(_arg1) \ + [arg1] "ri" LSS_SYSCALL_ARG(_arg1), + #define LSS_BODY_ARG2(_arg1, _arg2) \ + LSS_BODY_ARG1(_arg1) \ + [arg2] "ri" LSS_SYSCALL_ARG(_arg2), + #define LSS_BODY_ARG3(_arg1, _arg2, _arg3) \ + LSS_BODY_ARG2(_arg1, _arg2) \ + [arg3] "ri" LSS_SYSCALL_ARG(_arg3), + #define LSS_BODY_ARG4(_arg1, _arg2, _arg3, _arg4) \ + LSS_BODY_ARG3(_arg1, _arg2, _arg3) \ + [arg4] "ri" LSS_SYSCALL_ARG(_arg4), + #define LSS_BODY_ARG5(_arg1, _arg2, _arg3, _arg4, _arg5) \ + LSS_BODY_ARG4(_arg1, _arg2, _arg3, _arg4) \ + [arg5] "ri" LSS_SYSCALL_ARG(_arg5), + #define LSS_BODY_ARG6(_arg1, _arg2, _arg3, _arg4, _arg5, _arg6) \ + LSS_BODY_ARG5(_arg1, _arg2, _arg3, _arg4, _arg5) \ + [arg6] "ri" LSS_SYSCALL_ARG(_arg6), + + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(0, type, name); \ + } + + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_BODY(1, type, name, arg1) \ + } + + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_BODY(2, type, name, arg1, arg2) \ + } + + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_BODY(3, type, name, arg1, arg2, arg3) \ + } + + #undef _syscall4 + #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_BODY(4, type, name, arg1, arg2, arg3, arg4) \ + } + + #undef _syscall5 + #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5) \ + } + + #undef _syscall6 + #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5, type6, arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6) \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + unsigned long long __res; + + __asm__ __volatile__ ( + "{\n\t" + " addd,s 0x0, %[nr_clone], %%b[0]\n\t" + " addd,s 0x0, %[flags], %%db[1]\n\t" + " addd,s 0x0, %[child_stack], %%db[2]\n\t" + " addd,s 0x0, %[parent_tidptr], %%db[3]\n\t" + " addd,s 0x0, %[child_tidptr], %%db[4]\n\t" + " addd,s 0x0, %[newtls], %%db[5]\n\t" + "}\n\t" + /* if (fn == NULL) + * return -EINVAL; + */ + + "{\n\t" + " disp %%ctpr1, .L1\n\t" + "}\n\t" + "{\n\t" + " cmpesb,s 0x0, %[fn], %%pred0\n\t" + "}\n\t" + "{\n\t" + " ct %%ctpr1 ? %%pred0\n\t" + "}\n\t" + + /* if (child_stack == NULL) + * return -EINVAL; + */ + "{\n\t" + " cmpesb,s 0x0, %%db[2], %%pred0\n\t" + "}\n\t" + "{\n\t" + " ct %%ctpr1 ? %%pred0\n\t" + "}\n\t" + + /* b[0] = syscall(%b[0] = __NR_clone, + * %db[1] = flags, + * %db[2] = child_stack, + * %db[3] = parent_tidptr, + * %db[4] = child_tidptr, + * %db[5] = newtls) + */ + "{\n\t" + " sdisp %%ctpr1, 0x3\n\t" + "}\n\t" + "{\n\t" + " call %%ctpr1, wbs = %#\n\t" + "}\n\t" + + /* if (%[b0] != 0) + * return %b[0]; + */ + "{\n\t" + " disp %%ctpr1, .L2\n\t" + " cmpesb,s 0x0, %%b[0], %%pred0\n\t" + "}\n\t" + "{\n\t" + " ct %%ctpr1 ? ~%%pred0\n\t" + "}\n\t" + /* In the child, now. Call "fn(arg)". + */ + + "{\n\t" + " movtd,s %[fn], %%ctpr1\n\t" + "}\n\t" + "{\n\t" + " addd,s 0x0, %[arg], %%db[0]\n\t" + "}\n\t" + "{\n\t" + " call %%ctpr1, wbs = %#\n\t" + "}\n\t" + /* Call _exit(%b[0]). + */ + + "{\n\t" + " sdisp %%ctpr1, 0x3\n\t" + " addd,s 0x0, %%b[0], %%b[1]\n\t" + "}\n\t" + "{\n\t" + " addd,s 0x0, %[nr_exit], %%b[0]\n\t" + "}\n\t" + "{\n\t" + " call %%ctpr1, wbs = %#\n\t" + "}\n\t" + "{\n\t" + " disp %%ctpr1, .L2\n\t" + " adds,s 0x0, 0x0, %%b[0]\n\t" + "}\n\t" + "{\n\t" + " ct %%ctpr1\n\t" + "}\n\t" + ".L1:\n\t" + "{\n\t" + " addd,s 0x0, %[einval], %%b[0]\n\t" + "}\n\t" + ".L2:\n\t" + "{\n\t" + " addd,s 0x0, %%b[0], %[res]\n\t" + "}\n\t" + : [res] "=r" LSS_SYSCALL_ARG(__res) + : [nr_clone] "ri" LSS_SYSCALL_ARG(__NR_clone) + [arg] "ri" LSS_SYSCALL_ARG(arg) + [nr_exit] "ri" LSS_SYSCALL_ARG(__NR_exit) + [flags] "ri" LSS_SYSCALL_ARG(flags) + [child_stack] "ri" LSS_SYSCALL_ARG(child_stack) + [parent_tidptr] "ri" + LSS_SYSCALL_ARG(parent_tidptr) + [newtls] "ri" LSS_SYSCALL_ARG(newtls) + [child_tidptr] "ri" + LSS_SYSCALL_ARG(child_tidptr) + [fn] "ri" LSS_SYSCALL_ARG(fn) + [einval] "ri" LSS_SYSCALL_ARG(-EINVAL) + : "ctpr1", "b[0]", "b[1]", "b[2]", "b[3]", + "b[4]", "b[5]", "pred0"); + LSS_RETURN(int, __res); + } + #elif defined(__loongarch_lp64) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(ar,a) register int64_t __r##ar __asm__("a"#ar) = (int64_t)a + /* syscall is like subroutine calls, all caller-saved registers may be + * clobbered, we should add them to the |Clobbers| list. + * a0 is not included because it's in the output list. + */ + #define LSS_SYSCALL_CLOBBERS "t0", "t1", "t2", "t3", "t4", "t5", "t6", \ + "t7", "t8", "memory" + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register int64_t __res_a0 __asm__("a0"); \ + int64_t __res; \ + __asm__ __volatile__ ("li.d $a7, %1\n" \ + "syscall 0x0\n" \ + : "=r"(__res_a0) \ + : "i"(__NR_##name) , ## args \ + : LSS_SYSCALL_CLOBBERS); \ + __res = __res_a0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + int64_t __res; + { + register int64_t __res_a0 __asm__("a0"); + register uint64_t __flags __asm__("a0") = flags; + register void *__stack __asm__("a1") = child_stack; + register void *__ptid __asm__("a2") = parent_tidptr; + register void *__tls __asm__("a3") = newtls; + register int *__ctid __asm__("a4") = child_tidptr; + __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "addi.d %2, %2, -16\n" + "st.d %1, %2, 8\n" + "st.d %4, %2, 0\n" + + /* %a0 = syscall(%a0 = flags, + * %a1 = child_stack, + * %a2 = parent_tidptr, + * %a3 = newtls, + * %a4 = child_tidptr) + */ + "li.d $a7, %8\n" + "syscall 0x0\n" + + /* if (%a0 != 0) + * return %a0; + */ + "bnez $a0, 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ld.d $a0, $sp, 0\n" + "ld.d $a1, $sp, 8\n" + "addi.d $sp, $sp, 16\n" + "jirl $ra, $a1, 0\n" + + /* Call _exit(%a0). + */ + "li.d $a7, %9\n" + "syscall 0x0\n" + "1:\n" + : "=r" (__res_a0) + : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : LSS_SYSCALL_CLOBBERS); + __res = __res_a0; + } + LSS_RETURN(int, __res); + } + #endif #define __NR__exit __NR_exit #define __NR__gettid __NR_gettid @@ -3403,8 +4092,10 @@ struct kernel_statfs { // fork is polyfilled below when not available. LSS_INLINE _syscall0(pid_t, fork) #endif + #if defined(__NR_fstat) LSS_INLINE _syscall2(int, fstat, int, f, struct kernel_stat*, b) + #endif LSS_INLINE _syscall2(int, fstatfs, int, f, struct kernel_statfs*, b) #if defined(__x86_64__) @@ -3426,6 +4117,8 @@ struct kernel_statfs { struct kernel_dirent64*, d, int, c) LSS_INLINE _syscall0(gid_t, getegid) LSS_INLINE _syscall0(uid_t, geteuid) + LSS_INLINE _syscall2(int, getitimer, int, w, + struct kernel_itimerval*, c) #if defined(__NR_getpgrp) LSS_INLINE _syscall0(pid_t, getpgrp) #endif @@ -3437,10 +4130,10 @@ struct kernel_statfs { gid_t *, e, gid_t *, s) LSS_INLINE _syscall3(int, getresuid, uid_t *, r, uid_t *, e, uid_t *, s) -#if !defined(__ARM_EABI__) + #if defined(__NR_getrlimit) LSS_INLINE _syscall2(int, getrlimit, int, r, struct kernel_rlimit*, l) -#endif + #endif LSS_INLINE _syscall1(pid_t, getsid, pid_t, p) LSS_INLINE _syscall0(pid_t, _gettid) LSS_INLINE _syscall2(pid_t, gettimeofday, struct kernel_timeval*, t, @@ -3547,6 +4240,9 @@ struct kernel_statfs { LSS_INLINE _syscall1(int, setfsuid, uid_t, u) LSS_INLINE _syscall1(int, setuid, uid_t, u) LSS_INLINE _syscall1(int, setgid, gid_t, g) + LSS_INLINE _syscall3(int, setitimer, int, w, + const struct kernel_itimerval*, n, + struct kernel_itimerval*, o) LSS_INLINE _syscall2(int, setpgid, pid_t, p, pid_t, g) LSS_INLINE _syscall3(int, setpriority, int, a, @@ -3555,8 +4251,10 @@ struct kernel_statfs { gid_t, e, gid_t, s) LSS_INLINE _syscall3(int, setresuid, uid_t, r, uid_t, e, uid_t, s) + #if defined(__NR_setrlimit) LSS_INLINE _syscall2(int, setrlimit, int, r, const struct kernel_rlimit*, l) + #endif LSS_INLINE _syscall0(pid_t, setsid) LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s, const stack_t*, o) @@ -3564,10 +4262,14 @@ struct kernel_statfs { LSS_INLINE _syscall1(int, sigreturn, unsigned long, u) #endif #if defined(__NR_stat) - // stat is polyfilled below when not available. + // stat and lstat are polyfilled below when not available. LSS_INLINE _syscall2(int, stat, const char*, f, struct kernel_stat*, b) #endif + #if defined(__NR_lstat) + LSS_INLINE _syscall2(int, lstat, const char*, f, + struct kernel_stat*, b) + #endif LSS_INLINE _syscall2(int, statfs, const char*, f, struct kernel_statfs*, b) LSS_INLINE _syscall3(int, tgkill, pid_t, p, @@ -3586,23 +4288,6 @@ struct kernel_statfs { LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu, unsigned *, node, void *, unused) #endif - #if defined(__x86_64__) || \ - (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) - LSS_INLINE _syscall3(int, recvmsg, int, s, - struct kernel_msghdr*, m, int, f) - LSS_INLINE _syscall3(int, sendmsg, int, s, - const struct kernel_msghdr*, m, int, f) - LSS_INLINE _syscall6(int, sendto, int, s, - const void*, m, size_t, l, - int, f, - const struct kernel_sockaddr*, a, int, t) - LSS_INLINE _syscall2(int, shutdown, int, s, - int, h) - LSS_INLINE _syscall3(int, socket, int, d, - int, t, int, p) - LSS_INLINE _syscall4(int, socketpair, int, d, - int, t, int, p, int*, s) - #endif #if defined(__NR_fadvise64) #if defined(__x86_64__) /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ @@ -3685,6 +4370,12 @@ struct kernel_statfs { const char *, p, struct kernel_stat*, b, int, f) #endif + #if defined(__NR_statx) + LSS_INLINE _syscall5(int, statx, int, d, + const char *, p, + int, f, int, m, + struct kernel_statx*, b) + #endif #if defined(__x86_64__) || defined(__s390x__) LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, gid_t *egid, @@ -3891,43 +4582,43 @@ struct kernel_statfs { LSS_INLINE int LSS_NAME(sigaddset)(struct kernel_sigset_t *set, int signum) { - if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { - set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] - |= 1UL << ((signum - 1) % (8*sizeof(set->sig[0]))); + set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] + |= 1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0]))); return 0; } } LSS_INLINE int LSS_NAME(sigdelset)(struct kernel_sigset_t *set, int signum) { - if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { - set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] - &= ~(1UL << ((signum - 1) % (8*sizeof(set->sig[0])))); + set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] + &= ~(1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0])))); return 0; } } LSS_INLINE int LSS_NAME(sigismember)(struct kernel_sigset_t *set, int signum) { - if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { LSS_ERRNO = EINVAL; return -1; } else { - return !!(set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] & - (1UL << ((signum - 1) % (8*sizeof(set->sig[0]))))); + return !!(set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] & + (1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0]))))); } } #if defined(__i386__) || \ defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ defined(__PPC__) || \ - (defined(__s390__) && !defined(__s390x__)) + (defined(__s390__) && !defined(__s390x__)) || defined(__e2k__) #define __NR__sigaction __NR_sigaction #define __NR__sigpending __NR_sigpending #define __NR__sigsuspend __NR_sigsuspend @@ -4181,23 +4872,31 @@ struct kernel_statfs { LSS_SC_BODY(4, int, 8, d, type, protocol, sv); } #endif - #if defined(__ARM_EABI__) || defined (__aarch64__) + #if defined(__NR_recvmsg) LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg, int, flags) + #endif + #if defined(__NR_sendmsg) LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*, msg, int, flags) + #endif + #if defined(__NR_sendto) LSS_INLINE _syscall6(ssize_t, sendto, int, s, const void*, buf, size_t,len, int, flags, const struct kernel_sockaddr*, to, unsigned int, tolen) + #endif + #if defined(__NR_shutdown) LSS_INLINE _syscall2(int, shutdown, int, s, int, how) + #endif + #if defined(__NR_socket) LSS_INLINE _syscall3(int, socket, int, domain, int, type, int, protocol) + #endif + #if defined(__NR_socketpair) LSS_INLINE _syscall4(int, socketpair, int, d, int, type, int, protocol, int*, sv) #endif - #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ - (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ - defined(__s390__) - #define __NR__socketcall __NR_socketcall + + #if defined(__NR_socketcall) LSS_INLINE _syscall2(int, _socketcall, int, c, va_list, a) LSS_INLINE int LSS_NAME(socketcall)(int op, ...) { @@ -4209,36 +4908,43 @@ struct kernel_statfs { return rc; } + # if !defined(__NR_recvmsg) LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, int flags){ return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags); } - + # endif + # if !defined(__NR_sendmsg) LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, const struct kernel_msghdr *msg, int flags) { return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags); } - + # endif + # if !defined(__NR_sendto) LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, int flags, const struct kernel_sockaddr *to, unsigned int tolen) { return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen); } - + # endif + # if !defined(__NR_shutdown) LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { return LSS_NAME(socketcall)(13, s, how); } - + # endif + # if !defined(__NR_socket) LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { return LSS_NAME(socketcall)(1, domain, type, protocol); } - + # endif + # if !defined(__NR_socketpair) LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, int sv[2]) { return LSS_NAME(socketcall)(8, d, type, protocol, sv); } + # endif #endif #if defined(__NR_fstatat64) LSS_INLINE _syscall4(int, fstatat64, int, d, @@ -4320,12 +5026,12 @@ struct kernel_statfs { va_start(ap, flags); new_address = va_arg(ap, void *); rc = LSS_NAME(_mremap)(old_address, old_size, new_size, - flags, new_address); + (unsigned long)flags, new_address); va_end(ap); return rc; } - LSS_INLINE int LSS_NAME(ptrace_detach)(pid_t pid) { + LSS_INLINE long LSS_NAME(ptrace_detach)(pid_t pid) { /* PTRACE_DETACH can sometimes forget to wake up the tracee and it * then sends job control signals to the real parent, rather than to * the tracer. We reduce the risk of this happening by starting a @@ -4336,7 +5042,8 @@ struct kernel_statfs { * detached. Large multi threaded apps can take a long time in the kernel * processing SIGCONT. */ - int rc, err; + long rc; + int err; LSS_NAME(sched_yield)(); rc = LSS_NAME(ptrace)(PTRACE_DETACH, pid, (void *)0, (void *)0); err = LSS_ERRNO; @@ -4369,7 +5076,7 @@ struct kernel_statfs { LSS_SYSCALL_ARG(c), (uint64_t)(o)); } - LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, unsigned c) { + LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, size_t c) { LSS_BODY(3, int, readahead, LSS_SYSCALL_ARG(f), (uint64_t)(o), LSS_SYSCALL_ARG(c)); } @@ -4408,7 +5115,7 @@ struct kernel_statfs { unsigned, o2) LSS_INLINE _syscall5(ssize_t, _pwrite64, int, f, const void *, b, size_t, c, unsigned, o1, - long, o2) + unsigned, o2) LSS_INLINE _syscall4(int, _readahead, int, f, unsigned, o1, unsigned, o2, size_t, c) #endif @@ -4429,9 +5136,9 @@ struct kernel_statfs { return LSS_NAME(_pwrite64)(fd, buf, count, LSS_LLARG_PAD o.arg[0], o.arg[1]); } - LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, int len) { + LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, size_t count) { union { loff_t off; unsigned arg[2]; } o = { off }; - return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], len); + return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], count); } #endif #endif @@ -4486,10 +5193,79 @@ struct kernel_statfs { } #endif +#if defined(__NR_statx) + /* copy the contents of kernel_statx to the kernel_stat structure. */ + LSS_INLINE void LSS_NAME(cp_stat_statx)(struct kernel_stat *to, + struct kernel_statx *from) { + memset(to, 0, sizeof(struct kernel_stat)); + to->st_dev = (kernel_dev_t)((from->stx_dev_minor & 0xff) | + ((from->stx_dev_major & 0xfff) << 8) | + ((from->stx_dev_minor & ~0xffu) << 12)); + to->st_rdev = (kernel_dev_t)((from->stx_rdev_minor & 0xff) | + ((from->stx_rdev_major & 0xfff) << 8) | + ((from->stx_rdev_minor & ~0xffu) << 12)); + to->st_ino = (kernel_ino_t)from->stx_ino; + to->st_mode = (kernel_mode_t)from->stx_mode; + to->st_nlink = (kernel_nlink_t)from->stx_nlink; + to->st_uid = (kernel_uid_t)from->stx_uid; + to->st_gid = (kernel_gid_t)from->stx_gid; + to->st_atime_ = (kernel_time_t)(from->stx_atime.tv_sec); + to->st_atime_nsec_ = from->stx_atime.tv_nsec; + to->st_mtime_ = (kernel_time_t)(from->stx_mtime.tv_sec); + to->st_mtime_nsec_ = from->stx_mtime.tv_nsec; + to->st_ctime_ = (kernel_time_t)(from->stx_ctime.tv_sec); + to->st_ctime_nsec_ = from->stx_ctime.tv_nsec; + to->st_size = (kernel_off_t)(from->stx_size); + to->st_blocks = (kernel_blkcnt_t)(from->stx_blocks); + to->st_blksize = (kernel_blksize_t)from->stx_blksize; + } +#endif + +#if !defined(__NR_fstat) + LSS_INLINE int LSS_NAME(fstat)(int fd, + struct kernel_stat *buf) { + #if defined(__NR_newfstatat) + return LSS_NAME(newfstatat)(fd, "", buf, AT_EMPTY_PATH); + #elif defined(__NR_statx) + struct kernel_statx stx; + int flags = AT_NO_AUTOMOUNT | AT_EMPTY_PATH; + int mask = STATX_BASIC_STATS; + int res = LSS_NAME(statx)(fd, "", flags, mask, &stx); + LSS_NAME(cp_stat_statx)(buf, &stx); + return res; + #endif + } +#endif + #if !defined(__NR_stat) LSS_INLINE int LSS_NAME(stat)(const char *pathname, struct kernel_stat *buf) { - return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0); + #if defined(__NR_newfstatat) + return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0); + #elif defined(__NR_statx) + struct kernel_statx stx; + int flags = AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT; + int mask = STATX_BASIC_STATS; + int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx); + LSS_NAME(cp_stat_statx)(buf, &stx); + return res; + #endif + } +#endif + +#if !defined(__NR_lstat) + LSS_INLINE int LSS_NAME(lstat)(const char *pathname, + struct kernel_stat *buf) { + #if defined(__NR_newfstatat) + return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, AT_SYMLINK_NOFOLLOW); + #elif defined(__NR_statx) + struct kernel_statx stx; + int flags = AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; + int mask = STATX_BASIC_STATS; + int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx); + LSS_NAME(cp_stat_statx)(buf, &stx); + return res; + #endif } #endif @@ -4503,7 +5279,7 @@ struct kernel_statfs { // TODO: define this in an arch-independant way instead of inlining the clone // syscall body. -# if defined(__aarch64__) +# if defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) LSS_INLINE pid_t LSS_NAME(fork)(void) { // No fork syscall on aarch64 - implement by means of the clone syscall. // Note that this does not reset glibc's cached view of the PID/TID, so diff --git a/third_party/lss/tests/Makefile b/third_party/lss/tests/Makefile index 60ec06e97db6..554813d8bb69 100644 --- a/third_party/lss/tests/Makefile +++ b/third_party/lss/tests/Makefile @@ -41,9 +41,13 @@ LDFLAGS += -static TESTS = \ fallocate \ - sigaction \ + getitimer \ getrandom \ + lstat \ + setitimer \ + sigaction \ sigtimedwait \ + stat \ unlink \ all: check @@ -51,22 +55,31 @@ all: check %_test: %.c test_skel.h $(top_srcdir)/linux_syscall_support.h $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< +# Force building C as C++ code to improve compile-time coverage. +%_cc_test: %.c test_skel.h $(top_srcdir)/linux_syscall_support.h + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< + %_test: %.cc test_skel.h $(top_srcdir)/linux_syscall_support.h $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< %_run: %_test @t=$(@:_run=_test); \ echo "./$$t"; \ - if ! env -i ./$$t; then \ + env -i ./$$t; \ + exit_status=$$?; \ + if [ $$exit_status = 77 ]; then \ + echo "SKIP: $$t"; \ + elif [ $$exit_status != 0 ]; then \ + echo "FAIL: $$t"; \ env -i strace -f -v ./$$t; \ echo "TRY: gdb -q -ex r -ex bt ./$$t"; \ exit 1; \ fi -ALL_TEST_TARGETS = $(TESTS:=_test) +ALL_TEST_TARGETS = $(TESTS:=_test) $(TESTS:=_cc_test) compile_tests: $(ALL_TEST_TARGETS) -ALL_RUN_TARGETS = $(TESTS:=_run) +ALL_RUN_TARGETS = $(TESTS:=_run) $(TESTS:=_cc_run) check: $(ALL_RUN_TARGETS) # The "tempfile" targets are the names we use with temp files. @@ -107,6 +120,7 @@ cross: "mips64-unknown-linux-gnu-gcc -mabi=n32" \ "s390-ibm-linux-gnu-gcc" \ "s390x-ibm-linux-gnu-gcc" \ + "loongarch64-unknown-linux-gnu-gcc" \ ; do \ cxx=`echo "$$cc" | sed 's:-gcc:-g++:'`; \ $(MAKE) --no-print-directory CC="$$cc" CXX="$$cxx" cross_compile; \ diff --git a/third_party/lss/tests/fallocate.c b/third_party/lss/tests/fallocate.c index c156e58986cb..f6589070f7f0 100644 --- a/third_party/lss/tests/fallocate.c +++ b/third_party/lss/tests/fallocate.c @@ -63,5 +63,7 @@ int main(int argc, char *argv[]) { #endif assert(st.st_size == offset + len); + sys_unlink(filename); + return 0; } diff --git a/third_party/lss/tests/getitimer.c b/third_party/lss/tests/getitimer.c new file mode 100644 index 000000000000..507948fea089 --- /dev/null +++ b/third_party/lss/tests/getitimer.c @@ -0,0 +1,84 @@ +/* Copyright 2022, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test_skel.h" + +int main(int argc, char *argv[]) { + // We need an invalid timer value. The assert()'s below should + // be static asserts but it is not avalible in older C versions. +#define kInvalidTimer 9999 + assert(kInvalidTimer != ITIMER_REAL); + assert(kInvalidTimer != ITIMER_VIRTUAL); + assert(kInvalidTimer != ITIMER_PROF); + + // This should fail with EINVAL. + struct kernel_itimerval curr_itimer; + assert(sys_getitimer(kInvalidTimer, &curr_itimer) == -1); + assert(errno == EINVAL); + + // Create a read-only page. + size_t page_size = getpagesize(); + void* read_only_page = sys_mmap(NULL, page_size, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(read_only_page != MAP_FAILED); + + // This should fail with EFAULT. + assert(sys_getitimer(ITIMER_REAL, + (struct kernel_itimerval*) read_only_page) == -1); + assert(errno == EFAULT); + + // This should complete without an error. + assert(sys_getitimer(ITIMER_REAL, &curr_itimer) == 0); + + // Set up a real time timer with very long interval and value so that + // we do not need to handle SIGALARM in test. + struct kernel_itimerval new_itimer; + const time_t kIntervalSec = 60 * 60 * 24 * 365; // One year. + const long kIntervalUSec = 123; + new_itimer.it_interval.tv_sec = kIntervalSec; + new_itimer.it_interval.tv_usec = kIntervalUSec; + new_itimer.it_value = new_itimer.it_interval; + assert(sys_setitimer(ITIMER_REAL, &new_itimer, NULL) == 0); + + assert(sys_getitimer(ITIMER_REAL, &curr_itimer) == 0); + assert(kernel_timeval_eq(&curr_itimer.it_interval, &new_itimer.it_interval)); + + // Disable timer. + struct kernel_itimerval empty_itimer; + empty_itimer.it_interval.tv_sec = 0; + empty_itimer.it_interval.tv_usec = 0; + empty_itimer.it_value = empty_itimer.it_interval; + assert(sys_setitimer(ITIMER_REAL, &empty_itimer, NULL) == 0); + + // We should read back an empty itimer. + assert(sys_getitimer(ITIMER_REAL, &curr_itimer) == 0); + assert(kernel_itimerval_eq(&curr_itimer, &empty_itimer)); + + return 0; +} diff --git a/third_party/lss/tests/lstat.c b/third_party/lss/tests/lstat.c new file mode 100644 index 000000000000..33848a9817fe --- /dev/null +++ b/third_party/lss/tests/lstat.c @@ -0,0 +1,97 @@ +/* Copyright 2021, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test_skel.h" + +int main(int argc, char *argv[]) { + int exit_status = 0; + + // Get two unique paths to play with. + char foo[] = "tempfile.XXXXXX"; + char bar[] = "tempfile.XXXXXX"; + int fd_foo = mkstemp(foo); + int fd_bar = mkstemp(bar); + assert(fd_foo != -1); + assert(fd_bar != -1); + + // Then delete foo. + assert(sys_unlink(foo) == 0); + + // Now make foo a symlink to bar. + assert(symlink(bar, foo) == 0); + + // Make sure sys_stat() and sys_lstat() implementation return different + // information. + + // We need to check our stat syscalls for EOVERFLOW, as sometimes the integer + // types used in the stat structures are too small to fit the actual value. + // E.g. on some systems st_ino is 32-bit, but some filesystems have 64-bit + // inodes. + + struct kernel_stat lstat_info; + int rc = sys_lstat(foo, &lstat_info); + if (rc < 0 && errno == EOVERFLOW) { + // Bail out since we had an overflow in the stat structure. + exit_status = SKIP_TEST_EXIT_STATUS; + goto cleanup; + } + assert(rc == 0); + + struct kernel_stat stat_info; + rc = sys_stat(foo, &stat_info); + if (rc < 0 && errno == EOVERFLOW) { + // Bail out since we had an overflow in the stat structure. + exit_status = SKIP_TEST_EXIT_STATUS; + goto cleanup; + } + assert(rc == 0); + + struct kernel_stat bar_stat_info; + rc = sys_stat(bar, &bar_stat_info); + if (rc < 0 && errno == EOVERFLOW) { + // Bail out since we had an overflow in the stat structure. + exit_status = SKIP_TEST_EXIT_STATUS; + goto cleanup; + } + assert(rc == 0); + + // lstat should produce information about a symlink. + assert((lstat_info.st_mode & S_IFMT) == S_IFLNK); + + // stat-ing foo and bar should produce the same inode. + assert(stat_info.st_ino == bar_stat_info.st_ino); + + // lstat-ing foo should give a different inode than stat-ing foo. + assert(stat_info.st_ino != lstat_info.st_ino); + +cleanup: + sys_unlink(foo); + sys_unlink(bar); + return exit_status; +} diff --git a/third_party/lss/tests/setitimer.c b/third_party/lss/tests/setitimer.c new file mode 100644 index 000000000000..1bd71141de12 --- /dev/null +++ b/third_party/lss/tests/setitimer.c @@ -0,0 +1,90 @@ +/* Copyright 2022, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test_skel.h" + +int main(int argc, char *argv[]) { + // We need an invalid timer value. The assert()'s below should + // be static asserts but it is not avalible in older C versions. +#define kInvalidTimer 9999 + assert(kInvalidTimer != ITIMER_REAL); + assert(kInvalidTimer != ITIMER_VIRTUAL); + assert(kInvalidTimer != ITIMER_PROF); + + // Invalid timer returns EINVAL. + assert(sys_setitimer(kInvalidTimer, NULL, NULL) == -1); + assert(errno == EINVAL); + + const int kSignal = SIGALRM; + const size_t kSigsetSize = sizeof(struct kernel_sigset_t); + + // Block SIGALRM. + struct kernel_sigset_t sigalarm_only; + struct kernel_sigset_t old_sigset; + assert(sys_sigemptyset(&sigalarm_only) == 0); + assert(sys_sigaddset(&sigalarm_only, kSignal) == 0); + assert(sys_rt_sigprocmask(SIG_BLOCK, &sigalarm_only, &old_sigset, + kSigsetSize) == 0); + + // Set up a real time timer. + struct kernel_itimerval new_itimer = {}; + const long kIntervalUSec = 123; + new_itimer.it_interval.tv_sec = 0; + new_itimer.it_interval.tv_usec = kIntervalUSec; + new_itimer.it_value = new_itimer.it_interval; + assert(sys_setitimer(ITIMER_REAL, &new_itimer, NULL) == 0); + + // Wait for alarm. + struct timespec timeout; + const unsigned long kNanoSecsPerSec = 1000000000; + const unsigned long kNanoSecsPerMicroSec = 1000; + + // Use a timeout 3 times of the timer interval. + unsigned long duration_ns = kIntervalUSec * kNanoSecsPerMicroSec * 3; + timeout.tv_sec = duration_ns / kNanoSecsPerSec ; + timeout.tv_nsec = duration_ns % kNanoSecsPerSec; + + int sig; + do { + sig = sys_sigtimedwait(&sigalarm_only, NULL, &timeout); + } while (sig == -1 && errno == EINTR); + assert(sig == kSignal); + + // Disable timer, check saving of old timer value. + struct kernel_itimerval empty_itimer = {}; + struct kernel_itimerval old_itimer; + empty_itimer.it_interval.tv_sec = 0; + empty_itimer.it_interval.tv_usec = 0; + empty_itimer.it_value = empty_itimer.it_interval; + + assert(sys_setitimer(ITIMER_REAL, &empty_itimer, &old_itimer) == 0); + assert(kernel_timeval_eq(&old_itimer.it_interval, &new_itimer.it_interval)); + + return 0; +} diff --git a/third_party/lss/tests/stat.c b/third_party/lss/tests/stat.c new file mode 100644 index 000000000000..48cac620cbcd --- /dev/null +++ b/third_party/lss/tests/stat.c @@ -0,0 +1,67 @@ +/* Copyright 2021, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test_skel.h" + +int main(int argc, char *argv[]) { + int exit_status = 0; + + // Get two unique paths to play with. + char foo[] = "tempfile.XXXXXX"; + int fd_foo = mkstemp(foo); + assert(fd_foo != -1); + + // Make sure it exists. + assert(access(foo, F_OK) == 0); + + // Make sure sys_stat() and a libc stat() implementation return the same + // information. + struct stat libc_stat; + assert(stat(foo, &libc_stat) == 0); + + struct kernel_stat raw_stat; + // We need to check our stat syscall for EOVERFLOW, as sometimes the integer + // types used in the stat structures are too small to fit the actual value. + // E.g. on some systems st_ino is 32-bit, but some filesystems have 64-bit + // inodes. + int rc = sys_stat(foo, &raw_stat); + if (rc < 0 && errno == EOVERFLOW) { + // Bail out since we had an overflow in the stat structure. + exit_status = SKIP_TEST_EXIT_STATUS; + goto cleanup; + } + assert(rc == 0); + + assert(libc_stat.st_ino == raw_stat.st_ino); + + +cleanup: + sys_unlink(foo); + return exit_status; +} diff --git a/third_party/lss/tests/test_skel.h b/third_party/lss/tests/test_skel.h index 13d8beab90f2..024906cc9b55 100644 --- a/third_party/lss/tests/test_skel.h +++ b/third_party/lss/tests/test_skel.h @@ -54,11 +54,14 @@ #include #include #include +#include #include #include "linux_syscall_support.h" +#define SKIP_TEST_EXIT_STATUS 77 + void assert_buffers_eq_len(const void *buf1, const void *buf2, size_t len) { const uint8_t *u8_1 = (const uint8_t *)buf1; const uint8_t *u8_2 = (const uint8_t *)buf2; @@ -70,3 +73,17 @@ void assert_buffers_eq_len(const void *buf1, const void *buf2, size_t len) { } } #define assert_buffers_eq(obj1, obj2) assert_buffers_eq_len(obj1, obj2, sizeof(*obj1)) + +// Returns true iff pointed timevals are equal. +static inline bool kernel_timeval_eq(const struct kernel_timeval* lhs, + const struct kernel_timeval* rhs) { + return (lhs->tv_sec == rhs->tv_sec) && (lhs->tv_usec == rhs->tv_usec); +} + +// Returns true iff pointed itimervals are equal. +static inline bool kernel_itimerval_eq(const struct kernel_itimerval* lhs, + const struct kernel_itimerval* rhs) { + return kernel_timeval_eq(&lhs->it_interval, &rhs->it_interval) && + kernel_timeval_eq(&lhs->it_value, &rhs->it_value); +} +