diff options
52 files changed, 3344 insertions, 412 deletions
@@ -33,16 +33,47 @@ download: SUPPORTED_ARCHES =\ + ALPHA_LE\ + ALPHA_BE\ AMD64\ AMD64_X32\ + IA64_LE\ + IA64_BE\ + IA64_P32_LE\ + IA64_P32_BE\ M68K\ + MICROBLAZE_32_LE\ + MICROBLAZE_32_BE\ + MICROBLAZE_64_LE\ + MICROBLAZE_64_BE\ + MIPS_O32_LE\ + MIPS_O32_BE\ + MIPS_N32_LE\ + MIPS_N32_BE\ + MIPS_N64_LE\ + MIPS_N64_BE\ PARISC_32\ PARISC_64\ + POWERPC_32_LE\ + POWERPC_32_BE\ + POWERPC_64_LE\ + POWERPC_64_BE\ + POWERPC_NOSPU_LE\ + POWERPC_NOSPU_BE\ + POWERPC_SPU_LE\ + POWERPC_SPU_BE\ + S390_32\ + S390_64\ + SH_LE\ + SH_BE\ SPARC_32\ - I386 -# Excluded because of missing support in libsyscalls_get_datatype_description.c: -# ALPHA ARM_OABI ARM_EABI IA64 MICROBLAZE MIPS_O32 MIPS_N32 MIPS_N64 POWERPC_32 -# POWERPC_64 POWERPC_NOSPU POWERPC_SPU S390_32 S390_64 SH SPARC_64 XTENSA + SPARC_64_LE\ + SPARC_64_BE\ + I386\ + XTENSA_LE\ + XTENSA_BE +# Excluded because of incomplete support (see LIST_ARCH_SPECS in common.h): +# ARM_OABI_LE ARM_OABI_BE ARM_EABI_LE ARM_EABI_BE include $(CONFIGFILE) # Reloading the user's config in case it limits supported architectures @@ -70,13 +101,20 @@ OBJ =\ libsyscalls_get_datatype_description.o\ libsyscalls_get_integer_alignment.o\ libsyscalls_get_signals.o\ + libsyscalls_get_struct_description.o\ libsyscalls_get_syscall.o\ libsyscalls_get_syscall_display_info.o\ libsyscalls_get_syscall_errors.o\ libsyscalls_get_syscall_range.o\ + libsyscalls_make_signed_integer.o\ + libsyscalls_parse_signed_integer.o\ libsyscalls_perror.o\ + libsyscalls_section_value.o\ libsyscalls_strerror.o\ - libsyscalls_syscalls_tables_.o + libsyscalls_syscalls_tables_.o\ + libsyscalls_to_tracee_endian.o\ + libsyscalls_to_tracer_endian.o\ + libsyscalls_unsection_value.o #extended for each support operating system HDR =\ @@ -106,10 +144,16 @@ TESTUTILS =\ testutil/is-section-quarter.tu\ testutil/is-datatype-struct.tu\ testutil/list-errors.tu\ + testutil/make-signed.tu\ + testutil/parse-signed.tu\ testutil/perror-all.tu\ testutil/perror-bad.tu\ + testutil/section-value.tu\ testutil/strerror-all.tu\ - testutil/strerror-bad.tu + testutil/strerror-bad.tu\ + testutil/to-tracee-endian.tu\ + testutil/to-tracer-endian.tu\ + testutil/unsection-value.tu @@ -153,9 +197,12 @@ libsyscalls.$(LIBEXT): $(LOBJ) check: $(TESTUTILS) env CPP="$(CPP)" $(TEST_ENV) ./test - @if grep '^alias t=:' < ./test >/dev/null; then \ + @if grep '^t=:' < ./test >/dev/null; then \ printf '\033[1;33m%s\033[m\n' 'Warning! tests have been disabled' >&2; \ fi + @if grep '^alias p=' < ./test >/dev/null; then \ + printf '\033[1;33m%s\033[m\n' 'Warning! tests are running synchronously' >&2; \ + fi install: libsyscalls.a libsyscalls.$(LIBEXT) @@ -186,7 +233,7 @@ buildclean: semiclean -rm -rf -- generated/ $(OPERATING_SYSTEMS:=-src/*/) semiclean: - -rm -f -- *.o *.lo *.su *.gch *.gcov *.gcno *.gcda .*.tmp + -rm -f -- *.o *.lo *.su *.gch *.gcov *.gcno *.gcda .*.tmp .*.tmp.c -rm -f -- */*.o */*.lo */*.su */*.gch */*.gcov */*.gcno */*.gcda -rm -f -- *.a *.so *.so.* *.dll *.dylib *.$(LIBEXT) */*.tu -rm -f -- libsyscalls/short-enums.h @@ -1,5 +1,4 @@ Add calling convention -Add value decoding -Add value encoding Add man pages and README The syscall table is too big and should be compressed +Do not require user to download OS sources @@ -1,23 +1,68 @@ /* See LICENSE file for copyright and license details. */ #ifdef REQUIRE_FLEXABLE_OR_NPARAMS -# if defined(__clang__) || defined(__GNUC__) +# if defined(__clang__) # define LIBSYSCALLS_FLEXABLE_OR_NPARAMS_ +# pragma clang diagnostic ignored "-Wgnu-flexible-array-initializer" +# elif defined(__GNUC__) +# define LIBSYSCALLS_FLEXABLE_OR_NPARAMS_ +# pragma GCC diagnostic ignored "-Wpedantic" # else # define LIBSYSCALLS_FLEXABLE_OR_NPARAMS_ NPARAMS # warning Setting LIBSYSCALLS_FLEXABLE_OR_NPARAMS_ to NPARAMS as it is not known that the compiler supports static allocation of structs with flexible arrays # endif #endif +#ifdef REQUIRE_FLEXABLE_OR_NFIELDS +# if defined(__clang__) +# define LIBSYSCALLS_FLEXABLE_OR_NFIELDS_ +# pragma clang diagnostic ignored "-Wgnu-flexible-array-initializer" +# elif defined(__GNUC__) +# define LIBSYSCALLS_FLEXABLE_OR_NFIELDS_ +# pragma GCC diagnostic ignored "-Wpedantic" +# else +# define LIBSYSCALLS_FLEXABLE_OR_NFIELDS_ NFIELDS +# warning Setting LIBSYSCALLS_FLEXABLE_OR_NFIELDS_ to NFIELDS as it is not known that the compiler supports static allocation of structs with flexible arrays +# endif +#endif #include "libsyscalls.h" +#include <stdalign.h> #include <stddef.h> #include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#if defined(__clang__) +/* We expect the user to use -Weverything */ +# pragma clang diagnostic ignored "-Wimplicit-fallthrough" /* we use GCC's fall though comments */ +# pragma clang diagnostic ignored "-Wcovered-switch-default" /* the user may input something invalid due to version differences */ +# pragma clang diagnostic ignored "-Wc++98-compat" /* don't care about C++, especially not for internal code */ +# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" /* TODO how does that make sense in C23? */ +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* clang doesn't know what it is doing */ +# pragma clang diagnostic ignored "-Wvla" /* we prefer VLA over alloca (easier to support), and we are careful */ +#elif defined(__GNUC__) +/* We expect the user to use -Wall -Wextra mand maybe some other flags */ +# pragma GCC diagnostic ignored "-Wnonnull-compare" /* why should I trust that the user is using the same compiler? */ +# pragma GCC diagnostic ignored "-Winline" /* it's just a preference, up to the compiler to decide */ +#endif -#define COMMA , + +#if defined(__GNUC__) +# define PURE_FUNCTION __attribute__((__pure__)) +#else +# define PURE_FUNCTION +#endif +#define COMMA , + #define MISALIGNMENT(ADDR, ALIGN) (((ADDR) - ((ADDR) % (uintptr_t)(ALIGN))) % (uintptr_t)(ALIGN)) #define ALIGN_BUF(BUF, ALIGN) (&(BUF)[(size_t)MISALIGNMENT((uintptr_t)(char *)(BUF), (ALIGN))]) #define ELEMSOF(ARR) (sizeof(ARR) / sizeof *(ARR)) +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define LOWEST_BIT(X) ((X) & ~((X) - 1)) +#define POST_HIGHEST_OF_CONSECUTIVELY_BITS(X) ((X) + LOWEST_BIT(X)) struct libsyscalls_symbol_printer_data { @@ -26,6 +71,61 @@ struct libsyscalls_symbol_printer_data { char buf[]; }; +enum endian { + Big, + Little +}; + + +#define LIST_ARCH_SPECS(X, D) /* byte intptr size_t endian sign */\ + X(LIBSYSCALLS_ARCH_ALPHA_LE, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ALPHA_BE, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_AMD64, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_AMD64_X32, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + /* + X(LIBSYSCALLS_ARCH_ARM_OABI_LE, 8, TODO, TODO, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ARM_OABI_BE, 8, TODO, TODO, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ARM_EABI_LE, 8, TODO, TODO, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ARM_EABI_BE, 8, TODO, TODO, Big, TWOS_COMPLEMENT) D\ + */\ + X(LIBSYSCALLS_ARCH_IA64_LE, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_IA64_BE, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_IA64_P32_LE, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_IA64_P32_BE, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_M68K, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MICROBLAZE_32_LE, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MICROBLAZE_32_BE, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MICROBLAZE_64_LE, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MICROBLAZE_64_BE, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_O32_LE, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_O32_BE, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_N32_LE, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_N32_BE, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_N64_LE, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_N64_BE, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_PARISC_32, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_PARISC_64, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_32_LE, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_32_BE, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_64_LE, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_64_BE, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_NOSPU_LE, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_NOSPU_BE, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_SPU_LE, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_SPU_BE, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_S390_32, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_S390_64, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SH_LE, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SH_BE, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SPARC_32, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SPARC_64_LE, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SPARC_64_BE, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_I386, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_XTENSA_LE, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_XTENSA_BE, 8, 32, 32, Big, TWOS_COMPLEMENT) + /* Don't forget to update SUPPORTED_ARCHES in Makefile */ + /* TODO (alignment) means that it is missing in libsyscalls_get_integer_alignment.c and must also be added thither */ + #include "generated/oses.h" #include "generated/arches.h" @@ -47,9 +147,14 @@ LIST_OSES(X,) #endif +#define COUNT_LIST_(...) 1 +#define COUNT_LIST(LIST_MACRO) (LIST_MACRO(COUNT_LIST_,, +,)) + +#define COUNT_ARGS(...) (0 __VA_OPT__(+ COUNT_ARGS_1(__VA_ARGS__))) #define COUNT_ARG_PAIRS(...) (0 __VA_OPT__(+ COUNT_ARG_PAIRS_1(__VA_ARGS__))) -/* mk/generate.mk reads these two lines, do not format them as multiline macros! */ +/* mk/generate.mk reads these three lines, do not format them as multiline macros! */ +#define COUNT_ARGS_1(x, ...) 1 __VA_OPT__(+ COUNT_ARGS_2(__VA_ARGS__)) #define COUNT_ARG_PAIRS_1(x1, x2, ...) 1 __VA_OPT__(+ COUNT_ARG_PAIRS_2(__VA_ARGS__)) #define PARAMS_BUILD_TYPES_1(x, A, ...) LIBSYSCALLS_TYPE_##A __VA_OPT__(, PARAMS_BUILD_TYPES_2(__VA_ARGS__)) diff --git a/config-figure-this-out-for-me.mk b/config-figure-this-out-for-me.mk index 60a24de..0ba409e 100644 --- a/config-figure-this-out-for-me.mk +++ b/config-figure-this-out-for-me.mk @@ -12,7 +12,7 @@ BASECONFIG !=\ if test "$$testscript" = "util/what-architecture-am-i-using"; then \ continue; \ fi; \ - os="$$(printf '%s\n' "$$testscript" | cut -d / -f 1 | tr '[a-z]' '[A-Z]')"; \ + os="$$(dirname -- "$$testscript" | tr '[a-z]' '[A-Z]')"; \ support="$${os}_SUPPORT"; \ q=\'; \ printf '%s_ != test -z "$$(%s_)" || printf %s%%s\\n%s "$$(%s)"\n' \ @@ -30,13 +30,33 @@ BASECONFIG !=\ printf '\t\tif test $$$$? -lt 2; then printf %syes\\n%s; else printf %sno\\n%s; fi; \\\n' \ $$q $$q $$q $$q; \ printf '\tfi\n'; \ - done \ + done; \ ) > .config.mk.tmp; \ printf '%s\n' .config.mk.tmp; \ fi; include $(BASECONFIG) +HAVE_BUILTIN_FFSLL !=\ + testmk=.a-$$$$.tmp; \ + testbin=.b-$$$$.tmp; \ + testsrc=.c-$$$$.tmp.c; \ + printf 'int main() {return !(1' > $$testsrc; \ + printf ' && __builtin_ffsll(%s) == %s' 0 0 1 1 2 2 4 3 0x58 4 >> $$testsrc; \ + printf ');}\n' >> $$testsrc; \ + (set -e; \ + printf '.POSIX:\n'; \ + cat -- $(BASECONFIG); \ + printf '\nall:\n'; \ + printf '\t$$(CC) -o %s %s\n' "$$testbin" "$$testsrc"; \ + ) > $$testmk; \ + if (make -f $$testmk all && ./$$testbin) 2>/dev/null >/dev/null; then \ + printf '%s\n' -DHAVE_BUILTIN_FFSLL; \ + fi; \ + rm -f -- $$testmk $$testbin $$testsrc; + +CPPFLAGS += $(HAVE_BUILTIN_FFSLL) + DOWNLOAD !=\ if test -n "$(DOWNLOAD)"; then printf '%s\n' "$(DOWNLOAD)"; \ elif curl --version >/dev/null 2>&1; then printf 'curl --\n'; \ @@ -19,6 +19,10 @@ LDFLAGS = # system call description, but only references to them, not their # instantiations (which have static storage), for that it it relies # on compiler optimisation.) +# If you know that the compiler has __builtin_ffsll([unsigned] long long int) +# which returns the index, plus 1, of the least significant set bit +# or 0 for 0, you can add -DHAVE_BUILTIN_FFSLL to CPPFLAGS; if you +# are using GCC>=3.4 or clang>=5, this is added automatically. DOWNLOAD = curl -- diff --git a/libsyscalls.h b/libsyscalls.h index caf4a4b..382022b 100644 --- a/libsyscalls.h +++ b/libsyscalls.h @@ -31,7 +31,8 @@ X(LIBSYSCALLS_E_NOMEM, "Failed to allocate required memory") D\ X(LIBSYSCALLS_E_INVAL, "Invalid arguments passed to function") D\ X(LIBSYSCALLS_E_NOSUCHTYPE, "Type does not exist on the selected operating system or architecture") D\ - X(LIBSYSCALLS_E_ISSTRUCT, "Type is a structure or union") + X(LIBSYSCALLS_E_ISSTRUCT, "Type is a structure or union") D\ + X(LIBSYSCALLS_E_ISNOTSTRUCT, "Type is not a structure or union") /** * libsyscall error numbers @@ -51,30 +52,49 @@ enum libsyscalls_os { * Architectures */ enum libsyscalls_arch { - LIBSYSCALLS_ARCH_ALPHA, + LIBSYSCALLS_ARCH_ALPHA_LE, + LIBSYSCALLS_ARCH_ALPHA_BE, LIBSYSCALLS_ARCH_AMD64, - LIBSYSCALLS_ARCH_AMD64_X32, /* 32-bit ABI, not traditional 32-bit x86 ISA */ - LIBSYSCALLS_ARCH_ARM_OABI, - LIBSYSCALLS_ARCH_ARM_EABI, - LIBSYSCALLS_ARCH_IA64, + LIBSYSCALLS_ARCH_AMD64_X32, /* 32-bit ABI on 64-bit ISA */ + LIBSYSCALLS_ARCH_ARM_OABI_LE, + LIBSYSCALLS_ARCH_ARM_OABI_BE, + LIBSYSCALLS_ARCH_ARM_EABI_LE, + LIBSYSCALLS_ARCH_ARM_EABI_BE, + LIBSYSCALLS_ARCH_IA64_LE, /* 64-bit pointers */ + LIBSYSCALLS_ARCH_IA64_BE, /* 64-bit pointers */ + LIBSYSCALLS_ARCH_IA64_P32_LE, /* 32-bit pointers */ + LIBSYSCALLS_ARCH_IA64_P32_BE, /* 32-bit pointers */ LIBSYSCALLS_ARCH_M68K, - LIBSYSCALLS_ARCH_MICROBLAZE, - LIBSYSCALLS_ARCH_MIPS_O32, - LIBSYSCALLS_ARCH_MIPS_N32, - LIBSYSCALLS_ARCH_MIPS_N64, + LIBSYSCALLS_ARCH_MICROBLAZE_32_LE, + LIBSYSCALLS_ARCH_MICROBLAZE_32_BE, + LIBSYSCALLS_ARCH_MICROBLAZE_64_LE, + LIBSYSCALLS_ARCH_MICROBLAZE_64_BE, + LIBSYSCALLS_ARCH_MIPS_O32_LE, + LIBSYSCALLS_ARCH_MIPS_O32_BE, + LIBSYSCALLS_ARCH_MIPS_N32_LE, /* 32-bit ABI on 64-bit ISA */ + LIBSYSCALLS_ARCH_MIPS_N32_BE, /* 32-bit ABI on 64-bit ISA */ + LIBSYSCALLS_ARCH_MIPS_N64_LE, + LIBSYSCALLS_ARCH_MIPS_N64_BE, LIBSYSCALLS_ARCH_PARISC_32, LIBSYSCALLS_ARCH_PARISC_64, - LIBSYSCALLS_ARCH_POWERPC_32, - LIBSYSCALLS_ARCH_POWERPC_64, - LIBSYSCALLS_ARCH_POWERPC_NOSPU, - LIBSYSCALLS_ARCH_POWERPC_SPU, + LIBSYSCALLS_ARCH_POWERPC_32_LE, + LIBSYSCALLS_ARCH_POWERPC_32_BE, + LIBSYSCALLS_ARCH_POWERPC_64_LE, + LIBSYSCALLS_ARCH_POWERPC_64_BE, + LIBSYSCALLS_ARCH_POWERPC_NOSPU_LE, + LIBSYSCALLS_ARCH_POWERPC_NOSPU_BE, + LIBSYSCALLS_ARCH_POWERPC_SPU_LE, + LIBSYSCALLS_ARCH_POWERPC_SPU_BE, LIBSYSCALLS_ARCH_S390_32, LIBSYSCALLS_ARCH_S390_64, - LIBSYSCALLS_ARCH_SH, + LIBSYSCALLS_ARCH_SH_LE, /* does not cover SH-5 */ + LIBSYSCALLS_ARCH_SH_BE, /* does not cover SH-5 */ LIBSYSCALLS_ARCH_SPARC_32, - LIBSYSCALLS_ARCH_SPARC_64, + LIBSYSCALLS_ARCH_SPARC_64_LE, + LIBSYSCALLS_ARCH_SPARC_64_BE, LIBSYSCALLS_ARCH_I386, - LIBSYSCALLS_ARCH_XTENSA + LIBSYSCALLS_ARCH_XTENSA_LE, + LIBSYSCALLS_ARCH_XTENSA_BE }; /** @@ -174,18 +194,23 @@ enum libsyscalls_datatype { #define LIBSYSCALLS_LIST_STRUCTS_AND_UNIONS(X, SUFFIX, D, FIRST)\ X(LIBSYSCALLS_TYPE_STRUCT_AIO_SIGSET ## SUFFIX, FIRST, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_COMPAT_AIO_SIGSET ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_CACHESTAT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_CACHESTAT_RANGE ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_CLONE_ARGS ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_EPOLL_EVENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OABI_EPOLL_EVENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_FILE_HANDLE ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_FUTEX_WAITV ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_IOB ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_IOVEC ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_IO_EVENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_IO_URING_PARAMS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_ITIMERVAL ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_ITIMERSPEC ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_ITIMERSPEC64 ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_KEXEC_SEGMENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_COMPAT_KEXEC_SEGMENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_LANDLOCK_RULESET_ATTR ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_LINUX_DIRENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_LINUX_DIRENT64 ## SUFFIX,, "struct") D\ @@ -214,6 +239,7 @@ enum libsyscalls_datatype { X(LIBSYSCALLS_TYPE_STRUCT_POLLFD ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_RLIMIT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_RLIMIT64 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_COMPAT_RLIMIT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_ROBUST_LIST_HEAD ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_RSEQ ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_RUSAGE ## SUFFIX,, "struct") D\ @@ -227,7 +253,7 @@ enum libsyscalls_datatype { X(LIBSYSCALLS_TYPE_STRUCT_SIGALTSTACK ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_SIGEVENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_SIGINFO ## SUFFIX,, "struct") D\ - X(LIBSYSCALLS_TYPE_STRUCT_SOCKADDR ## SUFFIX,, "struct") D /* size is always in the next argument */\ + X(LIBSYSCALLS_TYPE_STRUCT_SOCKADDR ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_STAT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_STAT64 ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_STATFS ## SUFFIX,, "struct") D\ @@ -235,6 +261,8 @@ enum libsyscalls_datatype { X(LIBSYSCALLS_TYPE_STRUCT_STATX ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_SYSINFO ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_TIMESPEC ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_TIMESPEC64 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_TIMEVAL ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_TIMEX ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_TIMEZONE ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_TMS ## SUFFIX,, "struct") D\ @@ -246,7 +274,9 @@ enum libsyscalls_datatype { X(LIBSYSCALLS_TYPE_2_INTS ## SUFFIX, FIRST, "int[2]") D\ X(LIBSYSCALLS_TYPE_2_INTS_FD ## SUFFIX,, "int[2]") D\ X(LIBSYSCALLS_TYPE_2_UINT32S ## SUFFIX,, "uint32[2]") D\ - X(LIBSYSCALLS_TYPE_FD_SET ## SUFFIX,, "unsigned long[]") /* size depends on OS, (1024 / CHAR_BIT / sizeof(long)) in Linux */ + X(LIBSYSCALLS_TYPE_FD_SET ## SUFFIX,, "unsigned long[]") /* size depends on OS, (1024/CHAR_BIT/sizeof(long)) in Linux */ D\ + X(LIBSYSCALLS_TYPE_BUFFER_9 ## SUFFIX,, "char[9]") D\ + X(LIBSYSCALLS_TYPE_BUFFER_65 ## SUFFIX,, "char[65]") /* these don't have any suffix */ LIBSYSCALLS_MAKE_SPECIAL_TYPES_(), @@ -256,7 +286,7 @@ enum libsyscalls_datatype { LIBSYSCALLS_MAKE_ANNOTATED_NUMERICALS_(), LIBSYSCALLS_MAKE_STRUCTS_AND_UNIONS_(), - /* the following are always pointers unless returned */ + /* the following are always pointers if used as a parameter */ /* size in next parameter (or the previous parameter if there is no next parameter), * updated with fill if possible, otherwise returned (these use the suffix _ARRAY) */ @@ -2074,7 +2104,7 @@ struct libsyscalls_datatype_description { * guaranteed to be split otherwise) and this value is just * the number of bits stored in the register or struct field * - * It is possible for the datatype to contain unused dummy + * It is possible for the data type to contain unused dummy * bits in order to make it a power of 2 or a multiple of * a smaller data type. For example, on x86, `long double` * uses 128 bits, even though the value only uses 80 bits. @@ -2194,7 +2224,9 @@ struct libsyscalls_datatype_description { * `sizeof(x.byteorder) / sizeof(*x.byteorder)` * elements are read (where x is the instance of the * structure) (you should definitely have your own - * macro for that one) + * macro for that one). As an alternative to + * `LIBSYSCALLS_IS_BYTEORDER_END`, you may use the + * LIBSYSCALLS_IS_BYTEORDER_END_AT macro */ unsigned char byteorder[32]; @@ -2214,6 +2246,14 @@ struct libsyscalls_datatype_description { # define LIBSYSCALLS_IS_BYTEORDER_END(SHIFT)\ (!~((SHIFT) | ~LIBSYSCALLS_FIELD_MASK_(1ULL, struct libsyscalls_datatype_description, byteorder[0]))) #endif + + /** + * Test whether `DESC->byteorder[INDEX]` is + * the (post-last) end of `DESC->byteorder` + */ +#define LIBSYSCALLS_IS_BYTEORDER_END_AT(DESC, INDEX)\ + ((size_t)(INDEX) == sizeof((DESC)->byteorder) / sizeof(*(DESC)->byteorder) || \ + LIBSYSCALLS_IS_BYTEORDER_END((DESC)->byteorder[INDEX])) }; /** @@ -2262,6 +2302,51 @@ struct libsyscalls_structure_field { unsigned short int symbolic_field : 1; /** + * Only used with .input_field set to 1 + * + * If 1, it is probably not an error if the + * field is partially initialised as long as all + * its memory is allocated + * + * In the case that a field is split using for + * example one field with the type + * LIBSYSCALLS_TYPE_UINT64_FRONT_32 and another + * field with the type + * LIBSYSCALLS_TYPE_UINT64_BACK_32 (these two + * (for some split types, their may be more than + * two fields) fields will have the same name), + * it is one is partially initialised and the + * other completely uninitialised. Generally, + * as long as at least one of the parts are + * partially initialised, the application should + * not, unless it has more detailed knowledge + * about the system call, assume that there is + * an error. This happens because kernel's version + * of the library uses a scalar field, where as + * the userspace version (usually libc's version) + * uses a union of differently sized field. It + * is not necessarily the case that it can be + * known which field in the union is used: for + * example in epoll_ctl(2), it is completely up + * to the application, and the application has + * no way of telling the kernel which is used, + * and the kernel will in epoll_wait(2) simply + * return the union's value as it was set, meaning + * that some bits may be effectively uninitialised. + * Even if the field is complete uninitialised, + * it may still be the case that this is not an + * error, however, it probably is an error; for + * example in the case of epoll(7), it is completely + * possible, albeit unlikely (because it's silly), + * that the user calls epoll_ctl(2) without the + * `.data` field set, because it doesn't look at + * in when epoll_wait(2) returns, but insteads + * just does unblocking I/O one each file + * descriptor it has added to the epoll(7). + */ + unsigned short int partial_init_ok : 1; + + /** * If 1, the field is a pointer that the reads from * * Note that there are types that fundamentally are @@ -2281,7 +2366,16 @@ struct libsyscalls_structure_field { */ unsigned short int output_pointer : 1; - unsigned short int padding1__ : 16 - (6*1); + /** + * If 1, it has been determined that the field is + * not being used (usually because that it's not + * the active field in a `union` or because a + * flag somewhere in the `struct` is either set or + * cleared) + */ + unsigned short int unused : 1; + + unsigned short int padding1__ : 16 - (8*1); #if LIBSYSCALLS_IS_PADDING_REQUIRED_(3, 16, LIBSYSCALLS_POINTER_BIT_) # if !LIBSYSCALLS_CAN_ALIGN_(3, 16, CHAR_BIT) @@ -2289,6 +2383,30 @@ struct libsyscalls_structure_field { # endif char padding2__[LIBSYSCALLS_PAD_(sizeof(void *)/sizeof(char), (3*16)/CHAR_BIT)]; #endif + + /** + * Data type description + * + * The application is free to make changes, however, + * however the pointers themselves must not be touched + */ + union { + /** + * Description to use if `.type` refers to a + * `struct` or `union`; that is, if + * `(.type & ~LIBSYSCALLS_TYPEBITSMASK) >= + * LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS` + */ + struct libsyscalls_structure_description *structure; + + /** + * Description to use if `.type` does not refer + * to a `struct` or `union`; that is, if + * `(.type & ~LIBSYSCALLS_TYPEBITSMASK) < + * LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS` + */ + struct libsyscalls_datatype_description *nonstructure; + } type_description; }; /** @@ -2320,6 +2438,12 @@ struct libsyscalls_structure_description { unsigned short int num_fields : 14; /** + * If 1, the data type is a `union`, + * if 0, the data type is a `struct` + */ + unsigned short int is_union : 1; + + /** * Only used if .array_size is 0 * * Assuming the kernel writes into the array, if 1, the number @@ -2333,18 +2457,12 @@ struct libsyscalls_structure_description { unsigned short int fill_is_known : 1; /** - * If 1, the data type is a `union`, - * if 0, the data type is a `struct` - */ - unsigned short int is_union : 1; - - /** * The size (in number of elements) of the array the data type * is used in, or 1 if the data type was not an array or * 0 if the array size is determined by another parameter/field * * If 1, .relative_position_of_size will be set to 0, - * and .absolute_position_of_size -1, hoever if that is not + * and .absolute_position_of_size -1, however if that is not * the case and this field is set to 1, then .size (which may * or may not be 0 at this point) is determined by the indicated * parameter @@ -2441,7 +2559,7 @@ libsyscalls_perror(const char *, enum libsyscalls_error); * (not [*min_out, *max_out - 1]) but there may still be numbers within * this range that does not correspond to a system call */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 3), __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_syscall_range(enum libsyscalls_os, enum libsyscalls_arch, long long int *, long long int *); @@ -2468,7 +2586,7 @@ libsyscalls_get_syscall_range(enum libsyscalls_os, enum libsyscalls_arch, long l * of operating system (`os`) and architecture (`arch`) is * unsupported */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_syscall(enum libsyscalls_os, enum libsyscalls_arch, long long int, const struct libsyscalls_syscall **); @@ -2498,6 +2616,7 @@ libsyscalls_get_syscall(enum libsyscalls_os, enum libsyscalls_arch, long long in * is not supported, however it may be successful even if the * architecture (`arch`) not supported */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 3), __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_syscall_errors(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_named_number **, size_t *); @@ -2527,6 +2646,7 @@ libsyscalls_get_syscall_errors(enum libsyscalls_os, enum libsyscalls_arch, const * is not supported, however it may be successful even if the * architecture (`arch`) not supported */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 3), __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_signals(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_named_number **, size_t *); @@ -2542,7 +2662,11 @@ libsyscalls_get_signals(enum libsyscalls_os, enum libsyscalls_arch, const struct * @param syscall_arguments The values store in register (as upon system call entry) * the used for the system call, in the order the registers * are used as system call arguments - * @param info_out Output parameter for the additional system call information + * @param info_out Output parameter for the additional system call information; + * the caller responsible for deallocating the `*info_out` + * with free(3) when it is no longer needed. Be aware that + * `*info_out` will only be set when LIBSYSCALLS_E_OK is + * returned. * @return LIBSYSCALLS_E_OK - On success * LIBSYSCALLS_E_OSNOSUP - The library is not compiled with support for * the selected operating system (`os`) @@ -2552,17 +2676,23 @@ libsyscalls_get_signals(enum libsyscalls_os, enum libsyscalls_arch, const struct * LIBSYSCALLS_E_NOMEM - Failed to allocate memory for `*info_out` * LIBSYSCALLS_E_INVAL - One of the arguments was NULL */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __nonnull__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __nonnull__, __access__(__read_only__, 3), __access__(__write_only__, 6)) enum libsyscalls_error libsyscalls_get_syscall_display_info(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_syscall_abi *, - long long int, unsigned long long int *, struct libsyscalls_syscall_display_info **); + long long int, const unsigned long long int *, struct libsyscalls_syscall_display_info **); /** - * Get information on how an instance of data type is to be parsed + * Get information on how an instance of non-struct, non-union + * data type is to be parsed + * + * Do not use for data types inside structures, + * instead, use `.type_description.nonstructure` + * in the structure's field, as it may contain + * important adjustments * * @param os The operating system the data type is used on * @param arch The architecture the data type is used on - * @param datatype The datatype, `LIBSYSCALLS_TYPE_DYNAMIC` can + * @param datatype The data type, `LIBSYSCALLS_TYPE_DYNAMIC` can * be used to get the size of the registers used * as system call parameters * @param description_out Output parameter for the type description @@ -2575,13 +2705,14 @@ libsyscalls_get_syscall_display_info(enum libsyscalls_os, enum libsyscalls_arch, * LIBSYSCALLS_E_INVAL - `datatype` is not a valid data type * LIBSYSCALLS_E_NOSUCHTYPE - `datatype` does not exist on the selected * operating system (`os`) or architecture (`arch`) - * LIBSYSCALLS_E_ISSTRUCT - `datatype` represents a structure + * LIBSYSCALLS_E_ISSTRUCT - `datatype` represents a structure or union, + * or an array of a structure or union * * The function may complete successfully for some data * types even if it for other data types would return * LIBSYSCALLS_E_OSNOSUP or LIBSYSCALLS_E_ARCHNOSUP */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_datatype_description(enum libsyscalls_os, enum libsyscalls_arch, enum libsyscalls_datatype, struct libsyscalls_datatype_description *); @@ -2625,11 +2756,167 @@ libsyscalls_get_datatype_description(enum libsyscalls_os, enum libsyscalls_arch, * return LIBSYSCALLS_E_ARCHNOSUP, in such cases, the result * is indeed reliable */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_integer_alignment(enum libsyscalls_os, enum libsyscalls_arch, unsigned, unsigned *); -/* TODO add libsyscalls_get_struct_description */ +/** + * Parse a string of bits as a signed integer + * + * In case `representation` is LIBSYSCALLS_SIGN_UNDETERMINED, + * the bits are parsed as an unsigned integer + * + * @param value_in The bits to parse as a signed integer + * @param representation The sign representation used on the interger + * @param bits The number of bits in the integer + * @param value_out Output parameter for the absolute value of the signed integer (may be NULL) + * @param negative_out Output parameter for whether the signed integer is negative (may be NULL) + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - `representation` is not recognised by the library + * LIBSYSCALLS_E_INVAL - `bits` is 0 + * LIBSYSCALLS_E_INVAL - `bits` is greater than `sizeof(long long int) * CHAR_BIT` + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 4), __access__(__write_only__, 5)) +enum libsyscalls_error +libsyscalls_parse_signed_integer(unsigned long long int, enum libsyscalls_datatype_sign_representation, + size_t, unsigned long long int *, int *); + +/** + * Create a string of bits representing a signed integer + * + * In case `representation` is LIBSYSCALLS_SIGN_UNDETERMINED, + * the bit string will represent an unsigned integer + * + * @param value_in The absolute value if the signed integer + * @param negative Whether the signed integer is negative + * @param representation The sign representation used on the interger + * @param bits The number of bits in the integer + * @param value_out Output parameter for the bit string (may be NULL) + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - `representation` is not recognised by the library + * LIBSYSCALLS_E_INVAL - `bits` is 0 + * LIBSYSCALLS_E_INVAL - `bits` is greater than `sizeof(long long int) * CHAR_BIT` + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 5)) +enum libsyscalls_error +libsyscalls_make_signed_integer(unsigned long long int, int, enum libsyscalls_datatype_sign_representation, + size_t, unsigned long long int *); + +/** + * Take bits from a section of a split value + * and shift its bit into place, so that the OR + * of the result for each section creates the + * original unsplit value + * + * If `section` is LIBSYSCALLS_SECTION_UNDETERMINED, + * no changes will be made + * + * @param value_in The contiguous bits in the section of the value + * @param bits The number of bits in the section of the value + * @param section The section of the value + * @param value_out Output parameter for the value with its bits shifted into place (may be NULL) + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - `representation` is not recognised by the library + * LIBSYSCALLS_E_INVAL - `bits` is invalid for `section` + * LIBSYSCALLS_E_INVAL - `bits` is greater than `sizeof(long long int) * CHAR_BIT` + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 4)) +enum libsyscalls_error +libsyscalls_unsection_value(unsigned long long int, size_t, enum libsyscalls_datatype_section, unsigned long long int *); + +/** + * Create a split section from a value + * + * If `section` is LIBSYSCALLS_SECTION_UNDETERMINED, + * no changes will be made + * + * @param value_in The whole value + * @param bits The number of bits in the whole value + * @param section The section of the value to return + * @param value_out Output parameter for bits in the section value shifted into contiguity (may be NULL) + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - `representation` is not recognised by the library + * LIBSYSCALLS_E_INVAL - `bits` is invalid for `section` + * LIBSYSCALLS_E_INVAL - `bits` is greater than `sizeof(long long int) * CHAR_BIT` + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 4)) +enum libsyscalls_error +libsyscalls_section_value(unsigned long long int, size_t, enum libsyscalls_datatype_section, unsigned long long int *); + +/** + * Converts a value from the tracee's endian to the tracer's endian + * + * @param value_in Buffer containing the value to convert (does not need to be aligned) + * @param offset_in Offset in `value_in`, in bits + * @param type Details about the data type + * @param value_out Output parameter for the value in the tracer's endian + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - Either parameter is NULL + * LIBSYSCALLS_E_INVAL - The data type is too wide + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__nonnull__, __access__(__read_only__, 1), __access__(__read_only__, 3), __access__(__write_only__, 4)) +enum libsyscalls_error +libsyscalls_to_tracer_endian(const void *, size_t, const struct libsyscalls_datatype_description *, unsigned long long int *); + +/** + * Converts a value from the tracer's endian to the tracee's endian + * + * @param value_in Buffer containing the value to convert + * @param type Details about the data type + * @param value_out Output parameter for the value in the tracee's + * endian (does not need to be aligned); preexisting + * bits that do not overlap with the position of the + * value will be retained + * @param out_offset Offset in `value_out`, in bits + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - Either parameter is NULL + * LIBSYSCALLS_E_INVAL - The data type is too wide + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__nonnull__, __access__(__read_only__, 2), __access__(__read_write__, 3)) +enum libsyscalls_error +libsyscalls_to_tracee_endian(unsigned long long int, const struct libsyscalls_datatype_description *, void *, size_t); + +/** + * Get information on how an instance of struct or union is to be parsed + * + * Do not use for structures inside other structures, + * instead, use `.type_description.structure` in the + * structure's field, as it may contain important + * adjustments + * + * @param os The operating system the data type is used on + * @param arch The architecture the data type is used on + * @param datatype The data type + * @param data The data that is to be parsed (may be `NULL` if `data_size` is 0) + * @param data_size The number of bytes available in `data`, may be short or in excess + * @param description_out Output parameter for the type description; + * the caller responsible for deallocating the `*info_out` + * with free(3) when it is no longer needed. Be aware that + * `*info_out` will only be set when LIBSYSCALLS_E_OK is + * returned. + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_OSNOSUP - The library is not compiled with support for + * the selected operating system (`os`) + * LIBSYSCALLS_E_ARCHNOSUP - The library is not compiled with support for + * the selected architecture (`arch`) on the + * selected operating system (`os`) + * LIBSYSCALLS_E_INVAL - `datatype` is not a valid data type + * LIBSYSCALLS_E_NOSUCHTYPE - `datatype` does not exist on the selected + * operating system (`os`) or architecture (`arch`) + * LIBSYSCALLS_E_ISNOTSTRUCT - `datatype` does not represent a structure or + * union, nor an array of structure or union + * + * The function may complete successfully for some data + * types even if it for other data types would return + * LIBSYSCALLS_E_ARCHNOSUP + */ +#if 0 /* work in progress */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__read_only__, 4, 5), __access__(__write_only__, 6)) +enum libsyscalls_error +libsyscalls_get_struct_description(enum libsyscalls_os, enum libsyscalls_arch, enum libsyscalls_datatype, + const void *, size_t, struct libsyscalls_structure_description **); +#endif + /* TODO add libsyscalls_get_struct_display_info */ diff --git a/libsyscalls/internal-begin.h b/libsyscalls/internal-begin.h index 0d89bb7..56faadf 100644 --- a/libsyscalls/internal-begin.h +++ b/libsyscalls/internal-begin.h @@ -8,6 +8,13 @@ #include <stddef.h> +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdocumentation" +# pragma clang diagnostic ignored "-Wunknown-attributes" +#endif + + /** * Opaque type for symbol printer function identification */ diff --git a/libsyscalls/internal-end.h b/libsyscalls/internal-end.h index 2aeb2f0..e75a5ce 100644 --- a/libsyscalls/internal-end.h +++ b/libsyscalls/internal-end.h @@ -22,3 +22,8 @@ #undef LIBSYSCALLS_MAKE_ANNOTATED_NUMERICALS_ #undef LIBSYSCALLS_MAKE_STRUCTS_AND_UNIONS_ #undef LIBSYSCALLS_MAKE_FIXED_ARRAYS_ + + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif diff --git a/libsyscalls_get_datatype_description.c b/libsyscalls_get_datatype_description.c index 71a2170..a418eb3 100644 --- a/libsyscalls_get_datatype_description.c +++ b/libsyscalls_get_datatype_description.c @@ -1,56 +1,5 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -#include <stdlib.h> -#include <string.h> - - -#define COUNT_(...) 1 -#define COUNT(LIST_MACRO) (LIST_MACRO(COUNT_,, +,)) - -enum endian { - Big, - Little, -}; - -#define LIST_ARCH_SPECS(X, D) /* byte intptr size_t endian sign */\ - /* - X(LIBSYSCALLS_ARCH_ALPHA, 8, 64, 64, TODO(bi), TWOS_COMPLEMENT) D\ - */\ - X(LIBSYSCALLS_ARCH_AMD64, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ - X(LIBSYSCALLS_ARCH_AMD64_X32, 8, 32, 32, Little, TWOS_COMPLEMENT) D /* amd64, 32-bit convesion */\ - /* - X(LIBSYSCALLS_ARCH_ARM_OABI, 8, TODO, TODO, TODO(bi), TWOS_COMPLEMENT) D / * TODO (alignment) * / \ - X(LIBSYSCALLS_ARCH_ARM_EABI, 8, TODO, TODO, TODO(bi), TWOS_COMPLEMENT) D / * TODO (alignment) * /\ - X(LIBSYSCALLS_ARCH_IA64, 8, 64, 64, TODO, TWOS_COMPLEMENT) D\ - */\ - X(LIBSYSCALLS_ARCH_M68K, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ - /* - X(LIBSYSCALLS_ARCH_MICROBLAZE, 8, TODO, TODO, TODO, TODO) D / * TODO (alignment) * /\ - X(LIBSYSCALLS_ARCH_MIPS_O32, 8, 32, 32, TODO(bi), TWOS_COMPLEMENT) D / * mips32 * /\ - X(LIBSYSCALLS_ARCH_MIPS_N32, 8, 32, 32, TODO(bi), TWOS_COMPLEMENT) D / * TODO (alignment) * / / * mips64, 32-bit convention * /\ - X(LIBSYSCALLS_ARCH_MIPS_N64, 8, 64, 64, TODO(bi), TWOS_COMPLEMENT) D / * TODO (alignment) * / / * mips64 * /\ - */\ - X(LIBSYSCALLS_ARCH_PARISC_32, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ - X(LIBSYSCALLS_ARCH_PARISC_64, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ - /* - X(LIBSYSCALLS_ARCH_POWERPC_32, 8, 32, 32, TODO(bi), TODO) D\ - X(LIBSYSCALLS_ARCH_POWERPC_64, 8, 64, 64, TODO(bi), TODO) D / * TODO (alignment) * /\ - X(LIBSYSCALLS_ARCH_POWERPC_NOSPU, 8, 64, 64, TODO(bi), TODO) D / * TODO (alignment) * /\ - X(LIBSYSCALLS_ARCH_POWERPC_SPU, 8, 64, 64, TODO(bi), TODO) D / * TODO (alignment) * /\ - X(LIBSYSCALLS_ARCH_S390_32, 8, 32, 32, Big, TODO) D / * TODO (alignment) * /\ - X(LIBSYSCALLS_ARCH_S390_64, 8, 64, 64, Big, TODO) D / * TODO (alignment) * /\ - X(LIBSYSCALLS_ARCH_SH, 8, 32, 32, TODO(bi), TODO) D / * TODO (alignment) * / / * not sh-5 * /\ - */\ - X(LIBSYSCALLS_ARCH_SPARC_32, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ - /* - X(LIBSYSCALLS_ARCH_SPARC_64, 8, 64, 64, TODO(bi), TWOS_COMPLEMENT) D\ - */\ - X(LIBSYSCALLS_ARCH_I386, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ - /* - X(LIBSYSCALLS_ARCH_XTENSA, 8, 32, 32, TODO, TODO) - */ - /* Don't forget to update SUPPORTED_ARCHES in Makefile */ - /* TODO (alignment) means that it is missing in libsyscalls_get_integer_alignment.c and must also be added thither */ #include "generated/types.c" @@ -154,6 +103,14 @@ libsyscalls_get_datatype_description(enum libsyscalls_os os, enum libsyscalls_ar datatype = LIBSYSCALLS_TYPE_UINT32; description_out->array_size = 2; break; + case LIBSYSCALLS_TYPE_BUFFER_9: + datatype = LIBSYSCALLS_TYPE_CHAR; + description_out->array_size = 9; + break; + case LIBSYSCALLS_TYPE_BUFFER_65: + datatype = LIBSYSCALLS_TYPE_CHAR; + description_out->array_size = 65; + break; case LIBSYSCALLS_TYPE_FD_SET: goto os_dependent; default: @@ -190,7 +147,7 @@ libsyscalls_get_datatype_description(enum libsyscalls_os os, enum libsyscalls_ar } else if (datatype >= LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS) { unannotated: - if (datatype - LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS >= COUNT(LIBSYSCALLS_LIST_UNANNOTATED_NUMERICALS)) { + if (datatype - LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS >= COUNT_LIST(LIBSYSCALLS_LIST_UNANNOTATED_NUMERICALS)) { return LIBSYSCALLS_E_INVAL; } else if (datatype == LIBSYSCALLS_TYPE_MEMORY_ADDRESS) { datatype = LIBSYSCALLS_TYPE_INTPTR; @@ -206,7 +163,7 @@ libsyscalls_get_datatype_description(enum libsyscalls_os os, enum libsyscalls_ar } else if (datatype >= LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES) { if (class != LIBSYSCALLS_TYPEBITS_SCALAR) return LIBSYSCALLS_E_INVAL; - if (datatype - LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES >= COUNT(LIBSYSCALLS_LIST_COMPOSITE_PRIMITIVES)) + if (datatype - LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES >= COUNT_LIST(LIBSYSCALLS_LIST_COMPOSITE_PRIMITIVES)) return LIBSYSCALLS_E_INVAL; datatype = LIBSYSCALLS_TYPE_MEMORY_ADDRESS; goto unannotated; @@ -376,8 +333,6 @@ not_os_dependent: #if defined(__clang__) # pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" -# pragma clang diagnostic push # pragma clang diagnostic ignored "-Wimplicit-int-conversion" /* we don't want to hardcode the type here */ #elif defined(__GNUC__) # pragma GCC diagnostic push @@ -406,23 +361,20 @@ not_os_dependent: if (half) { unsigned long long int bytemask, coverage = 0; unsigned long long int remmask; - unsigned char bytebits = UCHAR_MAX; + unsigned long long int bytebits; - for (i = 0; !LIBSYSCALLS_IS_BYTEORDER_END(larger_type.byteorder[i]); i++) - if (larger_type.byteorder[i] && larger_type.byteorder[i] < bytebits) - bytebits = larger_type.byteorder[i]; + bytebits = (unsigned long long int)larger_type.width_in_bits; + for (i = 0; !LIBSYSCALLS_IS_BYTEORDER_END_AT(&larger_type, i); i++) + if (larger_type.byteorder[i] && (unsigned long long int)larger_type.byteorder[i] < bytebits) + bytebits = (unsigned long long int)larger_type.byteorder[i]; bytemask = (1ULL << bytebits) - 1ULL; remmask = 0xFFFFFFFFULL; /* we known from the code above that we are working with 32-bit sections */ - for (i = 0; !LIBSYSCALLS_IS_BYTEORDER_END(larger_type.byteorder[i]); i++) { + for (i = 0; !LIBSYSCALLS_IS_BYTEORDER_END_AT(&larger_type, i); i++) { coverage |= (remmask & bytemask) << larger_type.byteorder[i]; remmask >>= bytebits; } -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - /* we known from the code above that we are working with split 64-bit integers */ if (half == +1) coverage ^= 0xFFFFFFFFFFFFFFFFull; diff --git a/libsyscalls_get_integer_alignment.c b/libsyscalls_get_integer_alignment.c index 7802a06..1c2d10e 100644 --- a/libsyscalls_get_integer_alignment.c +++ b/libsyscalls_get_integer_alignment.c @@ -19,20 +19,50 @@ libsyscalls_get_integer_alignment(enum libsyscalls_os os, enum libsyscalls_arch break; case LIBSYSCALLS_ARCH_I386: + case LIBSYSCALLS_ARCH_ARM_OABI_LE: /* https://wiki.debian.org/ArmEabiPort#A64-bit_data_type_alignment */ + case LIBSYSCALLS_ARCH_ARM_OABI_BE: + case LIBSYSCALLS_ARCH_SH_LE: /* https://www.st.com/resource/en/reference_manual/rm0197-sh4-generic-and-c-specific-application-binary-interface-stmicroelectronics.pdf (page 12) */ + case LIBSYSCALLS_ARCH_SH_BE: + case LIBSYSCALLS_ARCH_MICROBLAZE_32_LE: /* https://www.ecb.torontomu.ca/~courses/ee8205/Data-Sheets/sopc/MicroBlaze_DataSheet.pdf */ + case LIBSYSCALLS_ARCH_MICROBLAZE_32_BE: maxalign = 32; break; case LIBSYSCALLS_ARCH_AMD64: case LIBSYSCALLS_ARCH_AMD64_X32: - case LIBSYSCALLS_ARCH_ALPHA: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ - case LIBSYSCALLS_ARCH_IA64: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ - case LIBSYSCALLS_ARCH_MIPS_O32: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ + case LIBSYSCALLS_ARCH_ARM_EABI_LE: /* https://wiki.debian.org/ArmEabiPort#A64-bit_data_type_alignment */ + case LIBSYSCALLS_ARCH_ARM_EABI_BE: + case LIBSYSCALLS_ARCH_ALPHA_LE: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ + case LIBSYSCALLS_ARCH_ALPHA_BE: + case LIBSYSCALLS_ARCH_IA64_LE: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ + case LIBSYSCALLS_ARCH_IA64_BE: + case LIBSYSCALLS_ARCH_IA64_P32_LE: + case LIBSYSCALLS_ARCH_IA64_P32_BE: + case LIBSYSCALLS_ARCH_MIPS_O32_LE: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ + case LIBSYSCALLS_ARCH_MIPS_O32_BE: + case LIBSYSCALLS_ARCH_MIPS_N32_LE: /* https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00083-2B-MIPS64INT-AFP-05.04.pdf (page 40) */ + case LIBSYSCALLS_ARCH_MIPS_N32_BE: + case LIBSYSCALLS_ARCH_MIPS_N64_LE: + case LIBSYSCALLS_ARCH_MIPS_N64_BE: case LIBSYSCALLS_ARCH_PARISC_32: /* https://www.ece.lsu.edu/ee4720/doc/pa1.1.pdf (page 26) */ case LIBSYSCALLS_ARCH_PARISC_64: - case LIBSYSCALLS_ARCH_POWERPC_32: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ + case LIBSYSCALLS_ARCH_POWERPC_32_LE: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ + case LIBSYSCALLS_ARCH_POWERPC_32_BE: + case LIBSYSCALLS_ARCH_POWERPC_64_LE: /* https://www.slac.stanford.edu/exp/npa/software/eabi_app.pdf */ + case LIBSYSCALLS_ARCH_POWERPC_64_BE: + case LIBSYSCALLS_ARCH_POWERPC_NOSPU_LE: + case LIBSYSCALLS_ARCH_POWERPC_NOSPU_BE: + case LIBSYSCALLS_ARCH_POWERPC_SPU_LE: + case LIBSYSCALLS_ARCH_POWERPC_SPU_BE: + case LIBSYSCALLS_ARCH_S390_32: /* https://refspecs.linuxbase.org/ELF/zSeries/lzsabi0_s390.html */ + case LIBSYSCALLS_ARCH_S390_64: case LIBSYSCALLS_ARCH_SPARC_32: /* https://www.gaisler.com/doc/sparcv8.pdf (page 46) */ - case LIBSYSCALLS_ARCH_SPARC_64: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ - case LIBSYSCALLS_ARCH_XTENSA: /* https://loboris.eu/ESP32/Xtensa_lx%20Overview%20handbook.pdf (page 97) */ + case LIBSYSCALLS_ARCH_SPARC_64_LE: /* https://static.lwn.net/images/pdf/LDD3/ch11.pdf */ + case LIBSYSCALLS_ARCH_SPARC_64_BE: + case LIBSYSCALLS_ARCH_XTENSA_LE: /* https://loboris.eu/ESP32/Xtensa_lx%20Overview%20handbook.pdf (page 97) */ + case LIBSYSCALLS_ARCH_XTENSA_BE: + case LIBSYSCALLS_ARCH_MICROBLAZE_64_LE: /* https://www.amd.com/content/dam/xilinx/support/documents/sw_manuals/xilinx2021_2/ug984-vivado-microblaze-ref.pdf */ + case LIBSYSCALLS_ARCH_MICROBLAZE_64_BE: maxalign = 64; break; diff --git a/libsyscalls_get_struct_description.c b/libsyscalls_get_struct_description.c new file mode 100644 index 0000000..4d9ce68 --- /dev/null +++ b/libsyscalls_get_struct_description.c @@ -0,0 +1,656 @@ +/* See LICENSE file for copyright and license details. */ +#define REQUIRE_FLEXABLE_OR_NFIELDS +#include "common.h" + + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-macros" +#endif + +#define IN .input_field = 1 +#define OUT .output_field = 1 +#define ERR .error_field = 1 +#define SYM .symbolic_field = 1 +#define PARTIAL .partial_init_ok = 1 +#define INPTR .input_pointer = 1 +#define OUTPTR .output_pointer = 1 + +#define BITFIELD(N) .bitlength = (N) +#define FIELD(NAME, TYPE, ...)\ + {.name = NAME,\ + .type = LIBSYSCALLS_TYPE_##TYPE\ + __VA_OPT__(, __VA_ARGS__)} +#define STRUCT(PRINTER, ...) STRUCT_OR_UNION_(0, PRINTER __VA_OPT__(, __VA_ARGS__)) +#define UNION(PRINTER, ...) STRUCT_OR_UNION_(1, PRINTER __VA_OPT__(, __VA_ARGS__)) +#define STRUCT_OR_UNION_(IS_UNION, PRINTER, ...)\ + {.is_union = (IS_UNION),\ + .symbol_printer = (PRINTER),\ + .num_fields = COUNT_ARGS(__VA_ARGS__)\ + __VA_OPT__(, .fields = {__VA_ARGS__})} + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + + +struct padding { + unsigned short int size; + unsigned short int after; +}; + + +static enum libsyscalls_error +get_struct_description(enum libsyscalls_os os, enum libsyscalls_arch arch, enum libsyscalls_datatype datatype, const void *data, + size_t data_size, struct libsyscalls_structure_description **description_out, size_t *extra_sizep); + + +static struct libsyscalls_structure_description * +copy_struct(const struct libsyscalls_structure_description *prototype) +{ + struct libsyscalls_structure_description *ret; + size_t size = offsetof(struct libsyscalls_structure_description, fields); + size += prototype->num_fields * sizeof(*prototype->fields); + ret = malloc(size); + if (!ret) + return NULL; + memcpy(ret, prototype, size); + return ret; +} + + +static struct libsyscalls_datatype_description * +create_pad_description(enum libsyscalls_os os, enum libsyscalls_arch arch, unsigned short int size) +{ + struct libsyscalls_datatype_description *ret; + ret = calloc(1, sizeof(*ret)); + if (!ret) + return NULL; + if (libsyscalls_get_datatype_description(os, arch, LIBSYSCALLS_TYPE_CHAR, ret)) + abort(); + ret->width_in_bits = size; + return ret; +} + + +static enum libsyscalls_error +shift_fields(enum libsyscalls_os os, enum libsyscalls_arch arch, struct libsyscalls_structure_description *description, + const struct padding *paddings, size_t npaddings) +{ + signed short int shift, map[description->num_fields], abs, rel; + unsigned short int i, j, k; + int is_struct; + + /* Adjust field references */ + for (i = 0; i < description->num_fields; i++) + map[i] = (signed short int)i; + shift = 0; + i = j = 0; + while (i < (unsigned short int)npaddings && j < description->num_fields) { + if (j > paddings[i].after) + shift += 1; + map[j] += shift; + } + for (; j < description->num_fields; j++) + map[j] += shift; + for (i = 0; i < description->num_fields; i++) { + is_struct = (description->fields[i].type & ~LIBSYSCALLS_TYPEBITSMASK) >= LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS; + + if (is_struct) { + abs = description->fields[i].type_description.structure->absolute_position_of_size; + rel = description->fields[i].type_description.structure->relative_position_of_size; + } else { + abs = description->fields[i].type_description.nonstructure->absolute_position_of_array_size; + rel = description->fields[i].type_description.nonstructure->relative_position_of_array_size; + } + + if (abs >= 0) { + if ((unsigned short int)abs > description->num_fields) + abort(); + abs = map[abs]; + } + if (rel != 0) { + if (rel + (signed short int)i < 0) + abort(); + if ((unsigned short int)(rel + (signed short int)i) > description->num_fields) + abort(); + rel = map[rel + (signed short int)i]; + rel -= (signed short int)i; + } + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +#endif + if (is_struct) { + description->fields[i].type_description.structure->absolute_position_of_size = abs; + description->fields[i].type_description.structure->relative_position_of_size = rel; + } else { + description->fields[i].type_description.nonstructure->absolute_position_of_array_size = abs; + description->fields[i].type_description.nonstructure->relative_position_of_array_size = rel; + } +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + } + + /* Insert padding fields */ + i = description->num_fields; + j = i + (unsigned short int)shift; + k = (unsigned short int)(npaddings - 1); + while (i) { + memcpy(&description->fields[--j], &description->fields[--i], sizeof(*description->fields)); + while (i <= paddings[k].after) { + j--; + description->size += paddings[k].size; + memset(&description->fields[j], 0, sizeof(*description->fields)); + description->fields[j].name = NULL; + description->fields[j].type = LIBSYSCALLS_TYPE_VOID; + description->fields[j].unused = 1; + description->fields[j].type_description.nonstructure = create_pad_description(os, arch, paddings[k].size); + if (!description->fields[j].type_description.structure) + return LIBSYSCALLS_E_NOMEM; + if (!k--) + return LIBSYSCALLS_E_OK; + } + } + + return LIBSYSCALLS_E_OK; +} + + +static void +free_subdescriptions(struct libsyscalls_structure_description *description) +{ + unsigned short int i; + for (i = 0; i < description->num_fields; i++) { + if ((description->fields[i].type & ~LIBSYSCALLS_TYPEBITSMASK) >= LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS) + free_subdescriptions(description->fields[i].type_description.structure); + free(description->fields[i].type_description.structure); + } +} + + +static void +move_in_subdescriptions(char *buffer, size_t *offsetp, struct libsyscalls_structure_description *description, + int include_nonstructures, int include_structures) +{ + unsigned short int i; + size_t size; + for (i = 0; i < description->num_fields; i++) { + if ((description->fields[i].type & ~LIBSYSCALLS_TYPEBITSMASK) >= LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS) { + move_in_subdescriptions(buffer, offsetp, description->fields[i].type_description.structure, + include_nonstructures, include_structures); + if (!include_structures) + continue; + size = (size_t)description->fields[i].type_description.structure->num_fields; + size *= sizeof(*description->fields[i].type_description.structure->fields); + size += offsetof(struct libsyscalls_structure_description, fields); + } else { + if (!include_nonstructures) + continue; + size = sizeof(struct libsyscalls_datatype_description); + } + memcpy(&buffer[*offsetp], description->fields[i].type_description.structure, size); + free(description->fields[i].type_description.structure); + description->fields[i].type_description.structure = (void *)&buffer[*offsetp]; + *offsetp += size; + } +} + + +static unsigned long long int +read_field(const void *data, size_t data_size, const size_t *field_offsets, + const struct libsyscalls_structure_description *description, unsigned short int i, int *undetermined_out) +{ + size_t offset, width, bits = 0; + enum libsyscalls_datatype type = description->fields[i].type; + const struct libsyscalls_datatype_description *type_description = description->fields[i].type_description.nonstructure; + unsigned splits, expected_splits, end; + unsigned long long int result = 0, subresult; + signed long long int sresult; + int is_negative; + + if ((type & LIBSYSCALLS_TYPEBITSMASK) != LIBSYSCALLS_TYPEBITS_SCALAR) + abort(); + type ^= LIBSYSCALLS_TYPEBITS_SCALAR; + if (type >= LIBSYSCALLS_TYPEOFFSET_SPLIT_PRIMITIVES && type < LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES) + splits = LIBSYSCALLS_GET_SECTION_FRACTION(type_description->section); + else if (type >= LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS && type < LIBSYSCALLS_TYPEOFFSET_FIXED_ARRAYS) + splits = 1; + else + abort(); + + expected_splits = splits; + end = i + splits; + goto start; + + for (; i < end; i++) { + if ((type & LIBSYSCALLS_TYPEBITSMASK) != LIBSYSCALLS_TYPEBITS_SCALAR) + abort(); + type ^= LIBSYSCALLS_TYPEBITS_SCALAR; + if (type >= LIBSYSCALLS_TYPEOFFSET_SPLIT_PRIMITIVES && type < LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES) + splits = LIBSYSCALLS_GET_SECTION_FRACTION(type_description->section); + else if (type >= LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS && type < LIBSYSCALLS_TYPEOFFSET_FIXED_ARRAYS) + splits = 1; + else + abort(); + + if (splits != expected_splits) + abort(); + + start: + offset = field_offsets[i]; + width = (size_t)type_description->width_in_bits; + bits += width; + + if (offset > data_size || width > data_size - offset) + goto undetermined; + + if (libsyscalls_to_tracer_endian(&((const char *)data)[offset / CHAR_BIT], offset % CHAR_BIT, + type_description, &subresult)) + abort(); + + if (libsyscalls_unsection_value(subresult, width, type_description->section, &subresult)) + abort(); + + result |= subresult; + } + + if (type_description->is_signed) { + if (libsyscalls_parse_signed_integer(result, type_description->sign_representation, bits, &result, &is_negative)) + abort(); + if (is_negative) { +#if LLONG_MIN == -LLONG_MAX + if (result >> (bits - 1)) + goto undetermined; +#endif + sresult = (signed long long int)result; + sresult = -sresult; + } + result = *(unsigned long long int *)&sresult; + } + + return result; + +undetermined: + *undetermined_out = 1; + return 0; +} + + +static enum libsyscalls_error +pad_structure_into_alignment(struct padding **paddingsp, size_t *npaddingsp, size_t *paddings_sizep, + const struct libsyscalls_structure_description *description) +{ + unsigned short int alignment_mask, misalignment; + void *new; + + alignment_mask = (unsigned short int)(description->alignment - 1U); + misalignment = (unsigned short int)(description->size & alignment_mask); + if (misalignment) { + if (*npaddingsp == *paddings_sizep) { + *paddings_sizep += 16; + new = realloc(*paddingsp, *paddings_sizep * sizeof(**paddingsp)); + if (!new) + return LIBSYSCALLS_E_NOMEM; + *paddingsp = new; + } + (*paddingsp)[*npaddingsp].size = (unsigned short int)(description->alignment - misalignment); + (*paddingsp)[*npaddingsp].after = description->num_fields; + *npaddingsp += 1; + } + + return LIBSYSCALLS_E_OK; +} + + +static enum libsyscalls_error +pad_field_into_alignment(struct padding **paddingsp, size_t *npaddingsp, size_t *paddings_sizep, + const struct libsyscalls_structure_description *description, + unsigned short int i, unsigned subalign, size_t *field_offsetp) +{ + unsigned short int misalignment, alignment_mask, padding; + void *new; + + alignment_mask = (unsigned short int)(subalign - 1U); + misalignment = (unsigned short int)(description->size & alignment_mask); + + if (misalignment) { + if (i == 0) + abort(); + padding = (unsigned short int)(subalign - (unsigned)misalignment); + if (*npaddingsp == *paddings_sizep) { + *paddings_sizep += 16; + new = realloc(*paddingsp, *paddings_sizep * sizeof(**paddingsp)); + if (!new) + return LIBSYSCALLS_E_NOMEM; + *paddingsp = new; + } + *field_offsetp += (size_t)padding; + (*paddingsp)[*npaddingsp].size = (unsigned short int)padding; + (*paddingsp)[*npaddingsp].after = (unsigned short int)(i - 1U); + *npaddingsp += 1; + } + + return LIBSYSCALLS_E_OK; +} + + +static enum libsyscalls_error +apply_padding(enum libsyscalls_os os, enum libsyscalls_arch arch, struct padding *paddings, + size_t npaddings, struct libsyscalls_structure_description **descriptionp) +{ + struct libsyscalls_structure_description *description = *descriptionp; + enum libsyscalls_error r; + size_t size; + + if (npaddings && description->alignment > 1) { + size = offsetof(struct libsyscalls_structure_description, fields); + size += (size_t)(description->num_fields + npaddings) * sizeof(*description->fields); + description = realloc(description, size); + if (!description) + return LIBSYSCALLS_E_NOMEM; + *descriptionp = description; + + r = shift_fields(os, arch, description, paddings, npaddings); + if (r) + return r; + } + + return LIBSYSCALLS_E_OK; +} + + +static enum libsyscalls_error +adjust_for_nonstruct(enum libsyscalls_os os, enum libsyscalls_arch arch, + const struct libsyscalls_datatype_description *int_description, + struct libsyscalls_structure_description *description, unsigned short int i, + unsigned *subsizep, unsigned *subalignp, size_t *extra_sizep) +{ + enum libsyscalls_error r; + + *subsizep = int_description->width_in_bits; + /* TODO deal with array_size, keep in mind that it can be 0 because we have (type[]) or (type *); be aware of padding */ + r = libsyscalls_get_integer_alignment(os, arch, *subsizep, subalignp); + if (r) + return r; + + description->fields[i].type_description.nonstructure = malloc(sizeof(*int_description)); + if (!description->fields[i].type_description.nonstructure) + return LIBSYSCALLS_E_NOMEM; + memcpy(description->fields[i].type_description.nonstructure, int_description, sizeof(*int_description)); + *extra_sizep += sizeof(*int_description); + + return LIBSYSCALLS_E_OK; +} + + +static enum libsyscalls_error +adjust_for_struct(enum libsyscalls_os os, enum libsyscalls_arch arch, const void *data, size_t data_size, + struct libsyscalls_structure_description *description, unsigned short int i, size_t *field_offsets, + unsigned *subsizep, unsigned *subalignp, size_t *extra_sizep, int *undetermined_sizep) +{ + struct libsyscalls_structure_description *struct_description; + size_t misalignment, subextra_size; + unsigned long long int uvalue; + unsigned short int field; + enum libsyscalls_error r; + + r = get_struct_description(os, arch, description->fields[i].type, &((const char *)data)[field_offsets[i]], + data_size < field_offsets[i] ? 0 : data_size - field_offsets[i], + &struct_description, extra_sizep); + if (r) + return r; + + *subsizep = struct_description->size * struct_description->array_size; + *subalignp = struct_description->alignment; + if (struct_description->array_size <= 1) { + if (struct_description->relative_position_of_size != 0) { + if (struct_description->relative_position_of_size > 1) + abort(); + if ((unsigned short int)-struct_description->relative_position_of_size > i) + abort(); + field = (unsigned short int)((ssize_t)i + (ssize_t)struct_description->relative_position_of_size); + goto set_subsize; + } else if (struct_description->absolute_position_of_size != -1) { + field = (unsigned short int)struct_description->absolute_position_of_size; + if (field > i) + abort(); + set_subsize: + uvalue = read_field(data, data_size, field_offsets, description, i, undetermined_sizep); + /* TODO set `*subsizep` to `uvalue` (may overflow) */ + } + if (!struct_description->array_size) + *subsizep *= struct_description->size; + } + if (!*subsizep) + *undetermined_sizep = 1; + + description->fields[i].type_description.structure = struct_description; + subextra_size = offsetof(struct libsyscalls_structure_description, fields); + subextra_size += (size_t)struct_description->num_fields * sizeof(*struct_description->fields); + misalignment = subextra_size % alignof(struct libsyscalls_structure_description); + misalignment = alignof(struct libsyscalls_structure_description) - misalignment; + misalignment %= alignof(struct libsyscalls_structure_description); + subextra_size += misalignment; + *extra_sizep += subextra_size; + + return LIBSYSCALLS_E_OK; +} + + +static enum libsyscalls_error +adjust_for_fields(enum libsyscalls_os os, enum libsyscalls_arch arch, const void *data, size_t data_size, + struct padding **paddingsp, size_t *npaddingsp, size_t *paddings_sizep, + struct libsyscalls_structure_description *description, int dont_align_fields, size_t *extra_sizep) +{ + size_t field_offsets[description->num_fields]; + struct libsyscalls_datatype_description int_description; + int undetermined_size = 0; + size_t field_offset = 0; + unsigned short int i; + unsigned subalign, subsize; + enum libsyscalls_error r; + + /* TODO deal with pointer fields */ + for (i = 0; i < description->num_fields && !undetermined_size; i++) { + field_offsets[i] = field_offset; + r = libsyscalls_get_datatype_description(os, arch, description->fields[i].type, &int_description); + if (r == LIBSYSCALLS_E_OK) + r = adjust_for_nonstruct(os, arch, &int_description, description, i, + &subsize, &subalign, extra_sizep); + else if (r == LIBSYSCALLS_E_ISSTRUCT) + r = adjust_for_struct(os, arch, data, data_size, description, i, field_offsets, + &subsize, &subalign, extra_sizep, &undetermined_size); + else + return r; + if (r) + return r; + + /* TODO deal with bitlength */ + + if (!dont_align_fields) { + r = pad_field_into_alignment(paddingsp, npaddingsp, paddings_sizep, + description, i, subalign, &field_offset); + if (r) + return r; + } + + field_offset += subsize; + description->size += (unsigned short int)subsize; + if (!dont_align_fields) + description->alignment = (unsigned short int)MAX(description->alignment, subalign); + } + + if (undetermined_size) + description->size = 0; + + return LIBSYSCALLS_E_OK; +} + + +#include "generated/structs.c" + + +static enum libsyscalls_error +get_struct_description(enum libsyscalls_os os, enum libsyscalls_arch arch, enum libsyscalls_datatype datatype, const void *data, + size_t data_size, struct libsyscalls_structure_description **description_out, size_t *extra_sizep) +{ + unsigned char fill_is_known; + unsigned short int array_size; + signed short int relative_position_of_size; + signed short int absolute_position_of_size; + struct libsyscalls_structure_description *description = NULL; + enum libsyscalls_error r; + unsigned class; + int dont_align_fields = 0; + size_t npaddings = 0, paddings_size = 0; + struct padding *paddings = NULL; + + if ((unsigned)datatype & ~(LIBSYSCALLS_TYPEBITSMASK | (LIBSYSCALLS_TYPEBITSMASK - 1U))) + return LIBSYSCALLS_E_INVAL; + + datatype ^= class = datatype & LIBSYSCALLS_TYPEBITSMASK; + + if (class == LIBSYSCALLS_TYPEBITS_SCALAR) { + fill_is_known = 1; + array_size = 1; + relative_position_of_size = 0; + absolute_position_of_size = -1; + + } else if (class == LIBSYSCALLS_TYPEBITS_ARRAY) { + fill_is_known = 1; + array_size = 0; + relative_position_of_size = +1; + absolute_position_of_size = -1; + + } else if (class == LIBSYSCALLS_TYPEBITS_ARRAY_UNKNOWN_FILL) { + fill_is_known = 0; + array_size = 0; + relative_position_of_size = +1; + absolute_position_of_size = -1; + + } else { + return LIBSYSCALLS_E_INVAL; + } + + if (datatype < LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS) + return LIBSYSCALLS_E_ISNOTSTRUCT; + +#define CASE(UPPERCASE, LOWERCASE)\ + case LIBSYSCALLS_OS_##UPPERCASE:\ + r = get_##LOWERCASE##_struct_description(arch, datatype, class, data, data_size,\ + &description, &dont_align_fields);\ + break + + switch ((int)os) { + LIST_OSES(CASE, ;); + default: + r = LIBSYSCALLS_E_OSNOSUP; + goto fail; + } + if (r) + goto fail; + +#undef CASE + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +#endif + + description->fill_is_known = fill_is_known; + description->array_size = array_size; + description->relative_position_of_size = relative_position_of_size; + description->absolute_position_of_size = absolute_position_of_size; + description->alignment = MAX(description->alignment, 1); + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + + r = adjust_for_fields(os, arch, data, data_size, &paddings, &npaddings, &paddings_size, + description, dont_align_fields, extra_sizep); + if (r) + goto fail; + +#define CASE(UPPERCASE, LOWERCASE)\ + case LIBSYSCALLS_OS_##UPPERCASE:\ + r = fix_##LOWERCASE##_struct_description(arch, datatype, class, data, data_size, description);\ + break + + switch ((int)os) { + LIST_OSES(CASE, ;); + default: + abort(); + } + if (r) + goto fail; + +#undef CASE + + r = pad_structure_into_alignment(&paddings, &npaddings, &paddings_size, description); + if (r) + goto fail; + + r = apply_padding(os, arch, paddings, npaddings, &description); + if (r) + goto fail; + + free(paddings); + *description_out = description; + return LIBSYSCALLS_E_OK; + +fail: + if (description) { + free_subdescriptions(description); + free(description); + } + free(paddings); + return r; +} + + +enum libsyscalls_error +libsyscalls_get_struct_description(enum libsyscalls_os os, enum libsyscalls_arch arch, enum libsyscalls_datatype datatype, + const void *data, size_t data_size, struct libsyscalls_structure_description **description_out) +{ + struct libsyscalls_structure_description *description, *new; + size_t extra_size = 0, size, nalign, salign, align; + enum libsyscalls_error r; + + if (!description_out) + return LIBSYSCALLS_E_INVAL; + + r = get_struct_description(os, arch, datatype, data, data_size, &description, &extra_size); + if (r) + return r; + if (!extra_size) { + *description_out = description; + return LIBSYSCALLS_E_OK; + } + + nalign = alignof(struct libsyscalls_datatype_description); + salign = alignof(struct libsyscalls_structure_description); + align = MAX(nalign, salign); + + size = offsetof(struct libsyscalls_structure_description, fields); + size += (size_t)description->num_fields * sizeof(*description->fields); + size += (align - (size & (align - 1))) & (align - 1); + + new = realloc(description, size + extra_size); + if (!new) { + free_subdescriptions(description); + free(description); + return LIBSYSCALLS_E_NOMEM; + } + description = new; + + move_in_subdescriptions((void *)description, &size, description, nalign == align, salign == align); + if (nalign != align || salign != align) + move_in_subdescriptions((void *)description, &size, description, nalign != align, salign != align); + + *description_out = description; + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_get_syscall.c b/libsyscalls_get_syscall.c index aea4d2f..e025e18 100644 --- a/libsyscalls_get_syscall.c +++ b/libsyscalls_get_syscall.c @@ -18,17 +18,8 @@ libsyscalls_get_syscall(enum libsyscalls_os os, enum libsyscalls_arch arch, long return LIBSYSCALLS_E_NOSUCHSYSCALL; /* buffer access is validated by libsyscalls_get_syscall_range() */ -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" -#endif - syscalldesc = libsyscalls_syscalls_tables_[os][arch][syscallnr - min]; -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - if (!syscalldesc) return LIBSYSCALLS_E_NOSUCHSYSCALL; if (syscall_out) diff --git a/libsyscalls_get_syscall_display_info.c b/libsyscalls_get_syscall_display_info.c index f9bbf1a..60bbe8a 100644 --- a/libsyscalls_get_syscall_display_info.c +++ b/libsyscalls_get_syscall_display_info.c @@ -1,30 +1,53 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -#include <stdalign.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#if defined(__GNUC__) -# pragma GCC diagnostic ignored "-Winline" + +static inline signed char +trailing_zeroes(unsigned long long int x) +{ +#ifndef HAVE_BUILTIN_FFSLL +# if defined(__HAVE_BUILTIN_FFSLL) +# define HAVE_BUILTIN_FFSLL +# elif defined(__clang__) +# if __clang_major__ >= 5 +# define HAVE_BUILTIN_FFSLL +# endif +# elif defined(__GNUC__) +# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# define HAVE_BUILTIN_FFSLL +# endif +# endif #endif +#ifdef HAVE_BUILTIN_FFSLL +# if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsign-conversion" +# endif -#define LOWEST_BIT(X) ((X) & ~((X) - 1)) -#define POST_HIGHEST_OF_CONSECUTIVELY_BITS(X) ((X) + LOWEST_BIT(X)) + return (signed char)(__builtin_ffsll(x) - 1); /* the type for x has changed over time */ +# if defined(__GNUC__) +# pragma GCC diagnostic pop +# endif +#else -static inline signed char -trailing_zeroes(unsigned long long int x) { /* TODO use builtin function if available */ int r = 0; if (x == 0) return -1; for (; (x & 1) == 0; x >>= 1) r += 1; return (signed char)r; + +#endif } +#define USE_INTERPOLATION_SEARCH /* TODO validate; should be configurable and (if good) default on systems with intrinsic divsion */ +#ifndef USE_INTERPOLATION_SEARCH + + +PURE_FUNCTION static int signed_named_number_cmp(const void *a_, const void *b_) { @@ -33,6 +56,7 @@ signed_named_number_cmp(const void *a_, const void *b_) } +PURE_FUNCTION static int unsigned_named_number_cmp(const void *a_, const void *b_) { @@ -41,6 +65,106 @@ unsigned_named_number_cmp(const void *a_, const void *b_) } +#else + + +/* convertion to unsigned is a modulo (unsigned maximum + 1) operation */ +#define DIFF(TYPE, A, B) ((unsigned TYPE)(A) - (unsigned TYPE)(B)) + +#define INTERPOL_SEARCH(KEY, BASE, N, READ)\ + do {\ + double guess_d;\ + unsigned long long int guess;\ + size_t h = (N);\ + \ + if (!h--)\ + return NULL;\ + \ + if ((KEY) <= READ((BASE), 0))\ + return (KEY) == READ((BASE), 0) ? (BASE) : NULL;\ + if ((KEY) >= READ((BASE), h))\ + return (KEY) == READ((BASE), h) ? (BASE) : NULL;\ + if (READ((BASE), 0) == READ((BASE), h))\ + return NULL;\ + \ + guess = DIFF(long long int, (KEY), READ((BASE), 0));\ + if (h > ULLONG_MAX / guess)\ + goto use_double;\ + \ + for (;;) {\ + guess = DIFF(long long int, (KEY), READ((BASE), 0));\ + guess *= (unsigned long long int)h;\ + guess /= DIFF(long long int, READ((BASE), h), READ((BASE), 0));\ + \ + if (READ((BASE), guess) < (KEY)) {\ + h -= guess += 1;\ + (BASE) = &(BASE)[guess];\ + } else if (READ((BASE), guess) > (KEY)) {\ + h -= guess -= 1;\ + } else {\ + return &(BASE)[guess];\ + }\ + \ + if (READ((BASE), 0) == READ((BASE), h))\ + return (KEY) == READ((BASE), 0) ? (BASE) : NULL;\ + if ((KEY) < READ((BASE), 0))\ + return NULL;\ + if ((KEY) > READ((BASE), h))\ + return NULL;\ + }\ + \ + use_double:\ + for (;;) {\ + guess = DIFF(long long int, (KEY), READ((BASE), 0));\ + guess_d = (double)guess * (double)h;\ + guess = DIFF(long long int, READ((BASE), h), READ((BASE), 0));\ + guess_d /= (double)guess;\ + guess = (unsigned long long int)guess_d;\ + \ + if (READ((BASE), guess) < (KEY)) {\ + h -= guess += 1;\ + (BASE) = &(BASE)[guess];\ + } else if (READ((BASE), guess) > (KEY)) {\ + h -= guess -= 1;\ + } else {\ + return &(BASE)[guess];\ + }\ + \ + if (READ((BASE), 0) == READ((BASE), h))\ + return (KEY) == READ((BASE), 0) ? (BASE) : NULL;\ + if ((KEY) < READ((BASE), 0))\ + return NULL;\ + if ((KEY) > READ((BASE), h))\ + return NULL;\ + }\ + } while (0) + + +PURE_FUNCTION +static const struct libsyscalls_named_number * +interpol_search_signed_named_number(signed long long int key, const struct libsyscalls_named_number *base, size_t n) +{ +#define X(ARR, I) ((ARR)[I].number.s) + INTERPOL_SEARCH(key, base, n, X); +#undef X +} + + +PURE_FUNCTION +static const struct libsyscalls_named_number * +interpol_search_unsigned_named_number(unsigned long long int key, const struct libsyscalls_named_number *base, size_t n) +{ +#define X(ARR, I) ((ARR)[I].number.u) + INTERPOL_SEARCH(key, base, n, X); +#undef X +} + +#undef DIFF + + +#endif + + static const char * extract_signal(enum libsyscalls_os os, enum libsyscalls_arch arch, unsigned long long int *valuep, char *fallback_out, int is_signed) @@ -52,23 +176,23 @@ extract_signal(enum libsyscalls_os os, enum libsyscalls_arch arch, if (libsyscalls_get_signals(os, arch, &signals, &nsignals)) return NULL; - found = bsearch(&key, signals, nsignals, sizeof(key), /* TODO interpolation search may be better */ +#ifndef USE_INTERPOLATION_SEARCH + found = bsearch(&key, signals, nsignals, sizeof(key), is_signed ? &signed_named_number_cmp : &unsigned_named_number_cmp); +#else + found = is_signed ? interpol_search_signed_named_number(key.number.s, signals, nsignals) + : interpol_search_unsigned_named_number(key.number.u, signals, nsignals); +#endif if (!found) return NULL; - (void)fallback_out; + (void) fallback_out; *valuep = 0; return found->name; } -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" -#endif - static struct libsyscalls_syscall_display_info * build_syscall_display_info(void *data, size_t data_size, size_t data_align, libsyscalls_symbol_printer_function **funcs, @@ -123,24 +247,15 @@ build_syscall_display_info(void *data, size_t data_size, size_t data_align, return ret; } -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - #include "generated/symbols.c" - -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic ignored "-Wnonnull-compare" /* Why should I trust that the user is using the same compiler? */ -#endif - enum libsyscalls_error libsyscalls_get_syscall_display_info(enum libsyscalls_os os, enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall, long long int syscall_number, - unsigned long long int *syscall_arguments, + const unsigned long long int *syscall_arguments, struct libsyscalls_syscall_display_info **info_out) { struct libsyscalls_syscall_display_info *info; diff --git a/libsyscalls_make_signed_integer.c b/libsyscalls_make_signed_integer.c new file mode 100644 index 0000000..b4142dc --- /dev/null +++ b/libsyscalls_make_signed_integer.c @@ -0,0 +1,56 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +enum libsyscalls_error +libsyscalls_make_signed_integer(unsigned long long int value_in, int negative, + enum libsyscalls_datatype_sign_representation representation, + size_t bits, unsigned long long int *value_out) +{ + unsigned long long int value = value_in, mask, highbit; + + if (!bits || bits > sizeof(value) / sizeof(char) * CHAR_BIT) + return LIBSYSCALLS_E_INVAL; + + switch (representation) { + case LIBSYSCALLS_SIGN_UNDETERMINED: + break; + + case LIBSYSCALLS_SIGN_TWOS_COMPLEMENT: + if (negative && value) { + highbit = 1ULL << (bits - 1U); + mask = highbit - 1ULL; + value = ~(value - 1) & mask; + value |= highbit; + } + break; + + case LIBSYSCALLS_SIGN_ONES_COMPLEMENT: + if (negative) { + highbit = 1ULL << (bits - 1U); + mask = highbit - 1ULL; + value = ~value & mask; + value |= highbit; + } + break; + + case LIBSYSCALLS_SIGN_SIGN_MAGNITUDE: + if (negative) + value ^= 1ULL << (bits - 1); + break; + + case LIBSYSCALLS_SIGN_EXCESS_HALF: + if (!negative) + value ^= 1ULL << (bits - 1); + else + value = (1ULL << (bits - 1)) - value; + break; + + default: + return LIBSYSCALLS_E_INVAL; + } + + if (value_out) + *value_out = value; + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_parse_signed_integer.c b/libsyscalls_parse_signed_integer.c new file mode 100644 index 0000000..da6f078 --- /dev/null +++ b/libsyscalls_parse_signed_integer.c @@ -0,0 +1,61 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +enum libsyscalls_error +libsyscalls_parse_signed_integer(unsigned long long int value_in, enum libsyscalls_datatype_sign_representation representation, + size_t bits, unsigned long long int *value_out, int *negative_out) +{ + unsigned long long int value = value_in, mask; + int negative = 0; + + if (!bits || bits > sizeof(value) / sizeof(char) * CHAR_BIT) + return LIBSYSCALLS_E_INVAL; + + switch (representation) { + case LIBSYSCALLS_SIGN_UNDETERMINED: + break; + + case LIBSYSCALLS_SIGN_TWOS_COMPLEMENT: + if (value >> (bits - 1U)) { + mask = (1ULL << (bits - 1U)) - 1ULL; + value = ~value & mask; + value += 1ULL; + negative = 1; + } + break; + + case LIBSYSCALLS_SIGN_ONES_COMPLEMENT: + if (value >> (bits - 1U)) { + mask = (1ULL << (bits - 1U)) - 1ULL; + value = ~value & mask; + negative = 1; + } + break; + + case LIBSYSCALLS_SIGN_SIGN_MAGNITUDE: + if (value >> (bits - 1U)) { + value ^= 1ULL << (bits - 1U); + negative = 1; + } + break; + + case LIBSYSCALLS_SIGN_EXCESS_HALF: + if (value >> (bits - 1U)) { + value ^= 1ULL << (bits - 1U); + } else { + value = (1ULL << (bits - 1U)) - value; + negative = 1; + } + break; + + default: + return LIBSYSCALLS_E_INVAL; + } + + if (value_out) + *value_out = value; + if (negative_out) + *negative_out = negative; + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_perror.c b/libsyscalls_perror.c index 4b110c7..f4f3a0c 100644 --- a/libsyscalls_perror.c +++ b/libsyscalls_perror.c @@ -1,8 +1,6 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -#include <stdio.h> - void libsyscalls_perror(const char *prefix, enum libsyscalls_error error) diff --git a/libsyscalls_section_value.c b/libsyscalls_section_value.c new file mode 100644 index 0000000..dc86cca --- /dev/null +++ b/libsyscalls_section_value.c @@ -0,0 +1,74 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +enum libsyscalls_error +libsyscalls_section_value(unsigned long long int value_in, size_t bits, + enum libsyscalls_datatype_section section, unsigned long long int *value_out) +{ + unsigned long long int value = value_in, mask, shift; + + if (bits > sizeof(value) / sizeof(char) * CHAR_BIT || + bits & (size_t)(LIBSYSCALLS_GET_SECTION_FRACTION(section) - 1U)) + return LIBSYSCALLS_E_INVAL; + + bits /= (size_t)LIBSYSCALLS_GET_SECTION_FRACTION(section); + if (bits == sizeof(mask) / sizeof(char) * CHAR_BIT) + mask = ~0ULL; + else + mask = (1ULL << bits) - 1ULL; + + switch (section) { + case LIBSYSCALLS_SECTION_UNDETERMINED: + case LIBSYSCALLS_SECTION_WHOLE: /* 0xFFFFFFFFFFFFFFFF */ + case LIBSYSCALLS_SECTION_LOWER_HALF: /* 0x00000000FFFFFFFF */ + case LIBSYSCALLS_SECTION_LOWER_QUARTER: /* 0x000000000000FFFF */ + break; + + case LIBSYSCALLS_SECTION_UPPER_HALF: /* 0xFFFFFFFF00000000 */ + case LIBSYSCALLS_SECTION_LOWER_MID_QUARTER: /* 0x00000000FFFF0000 */ + value >>= bits; + break; + + case LIBSYSCALLS_SECTION_INNER_HALF: /* 0x0000FFFFFFFF0000 */ + value >>= bits / 2; + break; + + case LIBSYSCALLS_SECTION_UPPER_MID_QUARTER: /* 0x0000FFFF00000000 */ + value >>= bits * 2; + break; + + case LIBSYSCALLS_SECTION_UPPER_QUARTER: /* 0xFFFF000000000000 */ + value >>= bits * 3; + break; + + case LIBSYSCALLS_SECTION_OUTER_HALF: /* 0xFFFF00000000FFFF */ + value = ((value & (mask << (bits + bits / 2))) >> bits) | (value & (mask >> (bits / 2))); + break; + + case LIBSYSCALLS_SECTION_ODD_QUARTERS_AS_HALF: /* 0xFFFF0000FFFF0000 */ + value >>= bits / 2; + /* fall through */ + case LIBSYSCALLS_SECTION_EVEN_QUARTERS_AS_HALF: /* 0x0000FFFF0000FFFF */ + value = ((value & (mask << (bits / 2)) & ~mask) >> (bits / 2)) | (value & (mask >> (bits / 2))); + break; + + case LIBSYSCALLS_SECTION_ODD_BYTES_AS_HALF: /* 0xFF00FF00FF00FF00 */ + value_in >>= 8; + /* fall through */ + case LIBSYSCALLS_SECTION_EVEN_BYTES_AS_HALF: /* 0x00FF00FF00FF00FF */ + value = 0; + for (shift = 0; value_in; value_in >>= 16, shift += 8) + value |= (value_in & 0x00FFU) << shift; + break; + + default: + return LIBSYSCALLS_E_INVAL; + } + + value &= mask; +masked: + if (value_out) + *value_out = value; + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_to_tracee_endian.c b/libsyscalls_to_tracee_endian.c new file mode 100644 index 0000000..94c44eb --- /dev/null +++ b/libsyscalls_to_tracee_endian.c @@ -0,0 +1,60 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/* XXX be smarter if using the same byteorder */ +enum libsyscalls_error +libsyscalls_to_tracee_endian(unsigned long long int value_in, + const struct libsyscalls_datatype_description *type, + void *value_out, size_t out_offset) +{ + const unsigned long long int limit = sizeof(long long int) / sizeof(char) * CHAR_BIT; + unsigned long long int bytebits, bytemask, byte, remmask, valmask; + unsigned long long int offset, offset_byte, offset_bit; + unsigned char *out = value_out; + size_t i; + + if (!type || !value_out || (unsigned long long int)type->width_in_bits > limit) + return LIBSYSCALLS_E_INVAL; + + bytebits = (unsigned long long int)type->width_in_bits; + for (i = 0; !LIBSYSCALLS_IS_BYTEORDER_END_AT(type, i); i++) + if (type->byteorder[i] && (unsigned long long int)type->byteorder[i] < bytebits) + bytebits = (unsigned long long int)type->byteorder[i]; + + if (bytebits > limit) + return LIBSYSCALLS_E_INVAL; + else if (bytebits == limit) + bytemask = ~0ULL; + else + bytemask = (1ULL << bytebits) - 1ULL; + + if ((unsigned long long int)type->width_in_bits == limit) + valmask = ~0ULL; + else + valmask = (1ULL << (unsigned long long int)type->width_in_bits) - 1ULL; + + for (i = 0; !LIBSYSCALLS_IS_BYTEORDER_END_AT(type, i); i++) { + offset = out_offset; + offset_byte = offset / CHAR_BIT; + offset_bit = offset % CHAR_BIT; + out_offset += bytebits; + + byte = value_in >> type->byteorder[i]; + byte &= remmask = bytemask & (valmask >> type->byteorder[i]); + + out[offset_byte] &= (unsigned char)~(remmask << offset_bit); + out[offset_byte] |= (unsigned char)(byte << offset_bit); + if (bytebits != limit && (remmask >>= CHAR_BIT - offset_bit)) { + byte >>= CHAR_BIT - offset_bit; + do { + offset_byte += 1; + out[offset_byte] &= (unsigned char)~remmask; + out[offset_byte] |= (unsigned char)byte; + byte >>= CHAR_BIT; + } while (remmask >>= CHAR_BIT); + } + } + + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_to_tracer_endian.c b/libsyscalls_to_tracer_endian.c new file mode 100644 index 0000000..ad3b8a4 --- /dev/null +++ b/libsyscalls_to_tracer_endian.c @@ -0,0 +1,59 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/* XXX be smarter if using the same byteorder */ +enum libsyscalls_error +libsyscalls_to_tracer_endian(const void *value_in, size_t in_offset, + const struct libsyscalls_datatype_description *type, + unsigned long long int *value_out) +{ + const unsigned long long int limit = sizeof(long long int) / sizeof(char) * CHAR_BIT; + unsigned long long int bytebits, bytemask, byte, value, remmask, valmask; + unsigned long long int offset = in_offset, offset_byte, offset_bit, off; + const unsigned char *in = value_in; + size_t i; + + if (!type || !value_in || !value_out || (unsigned long long int)type->width_in_bits > limit) + return LIBSYSCALLS_E_INVAL; + + bytebits = (unsigned long long int)type->width_in_bits; + for (i = 0; !LIBSYSCALLS_IS_BYTEORDER_END_AT(type, i); i++) + if (type->byteorder[i] && (unsigned long long int)type->byteorder[i] < bytebits) + bytebits = (unsigned long long int)type->byteorder[i]; + + if (bytebits > limit) + return LIBSYSCALLS_E_INVAL; + else if (bytebits == limit) + bytemask = ~0ULL; + else + bytemask = (1ULL << bytebits) - 1ULL; + + if ((unsigned long long int)type->width_in_bits == limit) + valmask = ~0ULL; + else + valmask = (1ULL << (unsigned long long int)type->width_in_bits) - 1ULL; + + value = 0; + for (i = 0; !LIBSYSCALLS_IS_BYTEORDER_END_AT(type, i); i++) { + offset_byte = offset / CHAR_BIT; + offset_bit = offset % CHAR_BIT; + offset += bytebits; + + byte = (unsigned long long int)in[offset_byte] >> offset_bit; + remmask = bytemask & (valmask >> type->byteorder[i]); + + off = CHAR_BIT - offset_bit; + if (remmask >>= off) { + do { + byte |= (unsigned long long int)in[++offset_byte] << off; + off += CHAR_BIT; + } while (remmask >>= CHAR_BIT); + } + byte &= bytemask & (valmask >> type->byteorder[i]); + value |= byte << type->byteorder[i]; + } + + *value_out = value; + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_unsection_value.c b/libsyscalls_unsection_value.c new file mode 100644 index 0000000..6cd797e --- /dev/null +++ b/libsyscalls_unsection_value.c @@ -0,0 +1,76 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +enum libsyscalls_error +libsyscalls_unsection_value(unsigned long long int value_in, size_t bits, + enum libsyscalls_datatype_section section, unsigned long long int *value_out) +{ + unsigned long long int value = value_in, mask, shift; + + if (bits > sizeof(value) / sizeof(char) * CHAR_BIT || + bits & (size_t)(LIBSYSCALLS_GET_SECTION_FRACTION(section) - 1U)) + return LIBSYSCALLS_E_INVAL; + + switch (section) { + case LIBSYSCALLS_SECTION_UNDETERMINED: + case LIBSYSCALLS_SECTION_WHOLE: /* 0xFFFFFFFFFFFFFFFF */ + break; + + case LIBSYSCALLS_SECTION_LOWER_HALF: /* 0x00000000FFFFFFFF */ + case LIBSYSCALLS_SECTION_LOWER_QUARTER: /* 0x000000000000FFFF */ + break; + + case LIBSYSCALLS_SECTION_UPPER_HALF: /* 0xFFFFFFFF00000000 */ + case LIBSYSCALLS_SECTION_LOWER_MID_QUARTER: /* 0x00000000FFFF0000 */ + value <<= bits; + break; + + case LIBSYSCALLS_SECTION_INNER_HALF: /* 0x0000FFFFFFFF0000 */ + value <<= bits / 2; + break; + + case LIBSYSCALLS_SECTION_UPPER_MID_QUARTER: /* 0x0000FFFF00000000 */ + value <<= bits * 2; + break; + + case LIBSYSCALLS_SECTION_UPPER_QUARTER: /* 0xFFFF000000000000 */ + value <<= bits * 3; + break; + + case LIBSYSCALLS_SECTION_OUTER_HALF: /* 0xFFFF00000000FFFF */ + mask = (1ULL << (bits / 2)) - 1ULL; + value = ((value & ~mask) << bits) | (value & mask); + break; + + case LIBSYSCALLS_SECTION_EVEN_QUARTERS_AS_HALF: /* 0x0000FFFF0000FFFF */ + mask = (1ULL << (bits / 2)) - 1ULL; + value = ((value & ~mask) << (bits / 2)) | (value & mask); + break; + + case LIBSYSCALLS_SECTION_ODD_QUARTERS_AS_HALF: /* 0xFFFF0000FFFF0000 */ + mask = (1ULL << (bits / 2)) - 1ULL; + value = ((value & ~mask) << (bits / 2)) | (value & mask); + value <<= bits / 2; + break; + + case LIBSYSCALLS_SECTION_EVEN_BYTES_AS_HALF: /* 0x00FF00FF00FF00FF */ + value = 0; + for (shift = 0; value_in; value_in >>= 8, shift += 16) + value |= (value_in & 0xFFU) << shift; + break; + + case LIBSYSCALLS_SECTION_ODD_BYTES_AS_HALF: /* 0xFF00FF00FF00FF00 */ + value = 0; + for (shift = 8; value_in; value_in >>= 8, shift += 16) + value |= (value_in & 0xFFU) << shift; + break; + + default: + return LIBSYSCALLS_E_INVAL; + } + + if (value_out) + *value_out = value; + return LIBSYSCALLS_E_OK; +} diff --git a/linux/errors.c b/linux/errors.c index 94c3cd2..0b1c2ea 100644 --- a/linux/errors.c +++ b/linux/errors.c @@ -14,7 +14,8 @@ get_linux_syscall_errors(enum libsyscalls_arch arch, const struct libsyscalls_na goto out switch ((int)arch) { - case LIBSYSCALLS_ARCH_ALPHA: + case LIBSYSCALLS_ARCH_ALPHA_LE: + case LIBSYSCALLS_ARCH_ALPHA_BE: #ifdef LIST_LINUX_ERRORS_FOR_ALPHA CASE(alpha); #else @@ -30,15 +31,18 @@ get_linux_syscall_errors(enum libsyscalls_arch arch, const struct libsyscalls_na break; #endif - case LIBSYSCALLS_ARCH_ARM_OABI: - case LIBSYSCALLS_ARCH_ARM_EABI: + case LIBSYSCALLS_ARCH_ARM_OABI_LE: + case LIBSYSCALLS_ARCH_ARM_OABI_BE: + case LIBSYSCALLS_ARCH_ARM_EABI_LE: + case LIBSYSCALLS_ARCH_ARM_EABI_BE: #ifdef LIST_LINUX_ERRORS_FOR_ARM CASE(arm); #else break; #endif - case LIBSYSCALLS_ARCH_IA64: + case LIBSYSCALLS_ARCH_IA64_LE: + case LIBSYSCALLS_ARCH_IA64_BE: #ifdef LIST_LINUX_ERRORS_FOR_IA64 CASE(ia64); #else @@ -52,16 +56,20 @@ get_linux_syscall_errors(enum libsyscalls_arch arch, const struct libsyscalls_na break; #endif - case LIBSYSCALLS_ARCH_MICROBLAZE: -#ifdef LIST_LINUX_ERRORS_FOR_MICROBLAZE + case LIBSYSCALLS_ARCH_MICROBLAZE_32_LE: + case LIBSYSCALLS_ARCH_MICROBLAZE_32_BE: +#ifdef LIST_LINUX_ERRORS_FOR_MICROBLAZE_32 CASE(microblaze); #else break; #endif - case LIBSYSCALLS_ARCH_MIPS_O32: - case LIBSYSCALLS_ARCH_MIPS_N32: - case LIBSYSCALLS_ARCH_MIPS_N64: + case LIBSYSCALLS_ARCH_MIPS_O32_LE: + case LIBSYSCALLS_ARCH_MIPS_O32_BE: + case LIBSYSCALLS_ARCH_MIPS_N32_LE: + case LIBSYSCALLS_ARCH_MIPS_N32_BE: + case LIBSYSCALLS_ARCH_MIPS_N64_LE: + case LIBSYSCALLS_ARCH_MIPS_N64_BE: #ifdef LIST_LINUX_ERRORS_FOR_MIPS CASE(mips); #else @@ -76,10 +84,14 @@ get_linux_syscall_errors(enum libsyscalls_arch arch, const struct libsyscalls_na break; #endif - case LIBSYSCALLS_ARCH_POWERPC_32: - case LIBSYSCALLS_ARCH_POWERPC_64: - case LIBSYSCALLS_ARCH_POWERPC_NOSPU: - case LIBSYSCALLS_ARCH_POWERPC_SPU: + case LIBSYSCALLS_ARCH_POWERPC_32_LE: + case LIBSYSCALLS_ARCH_POWERPC_32_BE: + case LIBSYSCALLS_ARCH_POWERPC_64_LE: + case LIBSYSCALLS_ARCH_POWERPC_64_BE: + case LIBSYSCALLS_ARCH_POWERPC_NOSPU_LE: + case LIBSYSCALLS_ARCH_POWERPC_NOSPU_BE: + case LIBSYSCALLS_ARCH_POWERPC_SPU_LE: + case LIBSYSCALLS_ARCH_POWERPC_SPU_BE: #ifdef LIST_LINUX_ERRORS_FOR_POWERPC CASE(powerpc); #else @@ -94,7 +106,8 @@ get_linux_syscall_errors(enum libsyscalls_arch arch, const struct libsyscalls_na break; #endif - case LIBSYSCALLS_ARCH_SH: + case LIBSYSCALLS_ARCH_SH_LE: + case LIBSYSCALLS_ARCH_SH_BE: #ifdef LIST_LINUX_ERRORS_FOR_SH CASE(sh); #else @@ -102,14 +115,16 @@ get_linux_syscall_errors(enum libsyscalls_arch arch, const struct libsyscalls_na #endif case LIBSYSCALLS_ARCH_SPARC_32: - case LIBSYSCALLS_ARCH_SPARC_64: + case LIBSYSCALLS_ARCH_SPARC_64_LE: + case LIBSYSCALLS_ARCH_SPARC_64_BE: #ifdef LIST_LINUX_ERRORS_FOR_SPARC CASE(sparc); #else break; #endif - case LIBSYSCALLS_ARCH_XTENSA: + case LIBSYSCALLS_ARCH_XTENSA_LE: + case LIBSYSCALLS_ARCH_XTENSA_BE: #ifdef LIST_LINUX_ERRORS_FOR_XTENSA CASE(xtensa); #else diff --git a/linux/linux-support.mk b/linux/linux-support.mk index c4a3f94..6756e87 100644 --- a/linux/linux-support.mk +++ b/linux/linux-support.mk @@ -6,30 +6,45 @@ LINUX_VERSION = 6.6 # works afterwards SUPPORTED_LINUX_ARCHES =\ - ALPHA\ + ALPHA_LE\ + ALPHA_BE\ AMD64\ AMD64_X32\ - ARM_OABI\ - ARM_EABI\ - IA64\ + ARM_OABI_LE\ + ARM_OABI_BE\ + ARM_EABI_LE\ + ARM_EABI_BE\ + IA64_LE\ + IA64_BE\ M68K\ - MICROBLAZE\ - MIPS_O32\ - MIPS_N32\ - MIPS_N64\ + MICROBLAZE_32_LE\ + MICROBLAZE_32_BE\ + MIPS_O32_LE\ + MIPS_O32_BE\ + MIPS_N32_LE\ + MIPS_N32_BE\ + MIPS_N64_LE\ + MIPS_N64_BE\ PARISC_32\ PARISC_64\ - POWERPC_32\ - POWERPC_64\ - POWERPC_NOSPU\ - POWERPC_SPU\ + POWERPC_32_LE\ + POWERPC_32_BE\ + POWERPC_64_LE\ + POWERPC_64_BE\ + POWERPC_NOSPU_LE\ + POWERPC_NOSPU_BE\ + POWERPC_SPU_LE\ + POWERPC_SPU_BE\ S390_32\ S390_64\ - SH\ + SH_LE\ + SH_BE\ SPARC_32\ - SPARC_64\ + SPARC_64_LE\ + SPARC_64_BE\ I386\ - XTENSA + XTENSA_LE\ + XTENSA_BE OPERATING_SYSTEMS += linux NPARAMS += 8 @@ -45,6 +60,7 @@ include linux/download.mk include linux/errors.mk include linux/integers.mk include linux/signals.mk +include linux/structs.mk include linux/syscalls.mk include linux/syscall-table.mk include linux/symbols.mk @@ -57,4 +73,16 @@ generated/linux-arches.h: linux/linux-support.mk mkdir -p -- generated (printf '\43define LIST_LINUX_ARCHES(X, D)\\\n' && \ printf '\tX(%s) D\\\n' $(SUPPORTED_LINUX_ARCHES); \ - ) | sed '$$s/ D\\//' > $@ + ) | sed '/X()/d' | sed '$$s/\\$$//' | sed '$$s/ D$$//' > $@ + (printf '\43define LIST_LINUX_ARCHES_WITH_BIENDIAN(X, D)\\\n' && \ + printf '\tX(%s) D\\\n' $(SUPPORTED_LINUX_ARCHES) \ + | sed -n 's/_LE)/)/p'; \ + ) | sed '/X()/d' | sed '$$s/\\$$//' | sed '$$s/ D$$//' >> $@ + (printf '\43define LIST_LINUX_ARCHES_WITH_UNIENDIAN(X, D)\\\n' && \ + printf '\tX(%s) D\\\n' $(SUPPORTED_LINUX_ARCHES); \ + ) | sed '/_[LB]E)/d' \ + | sed '/X()/d' | sed '$$s/\\$$//' | sed '$$s/ D$$//' >> $@ + (printf '\43define LIST_LINUX_ARCHES_WITHOUT_ENDIANS(X, D)\\\n' && \ + printf '\tX(%s) D\\\n' $(SUPPORTED_LINUX_ARCHES); \ + ) | sed 's/_[LB]E)/)/' | uniq \ + | sed '/X()/d' | sed '$$s/\\$$//' | sed '$$s/ D$$//' >> $@ diff --git a/linux/signals.c b/linux/signals.c index 743fc89..7adc44c 100644 --- a/linux/signals.c +++ b/linux/signals.c @@ -14,7 +14,8 @@ get_linux_signals(enum libsyscalls_arch arch, const struct libsyscalls_named_num goto out switch ((int)arch) { - case LIBSYSCALLS_ARCH_ALPHA: + case LIBSYSCALLS_ARCH_ALPHA_LE: + case LIBSYSCALLS_ARCH_ALPHA_BE: #ifdef LIST_LINUX_SIGNALS_FOR_ALPHA CASE(alpha); #else @@ -30,15 +31,18 @@ get_linux_signals(enum libsyscalls_arch arch, const struct libsyscalls_named_num break; #endif - case LIBSYSCALLS_ARCH_ARM_OABI: - case LIBSYSCALLS_ARCH_ARM_EABI: + case LIBSYSCALLS_ARCH_ARM_OABI_LE: + case LIBSYSCALLS_ARCH_ARM_OABI_BE: + case LIBSYSCALLS_ARCH_ARM_EABI_LE: + case LIBSYSCALLS_ARCH_ARM_EABI_BE: #ifdef LIST_LINUX_SIGNALS_FOR_ARM CASE(arm); #else break; #endif - case LIBSYSCALLS_ARCH_IA64: + case LIBSYSCALLS_ARCH_IA64_LE: + case LIBSYSCALLS_ARCH_IA64_BE: #ifdef LIST_LINUX_SIGNALS_FOR_IA64 CASE(ia64); #else @@ -52,16 +56,20 @@ get_linux_signals(enum libsyscalls_arch arch, const struct libsyscalls_named_num break; #endif - case LIBSYSCALLS_ARCH_MICROBLAZE: -#ifdef LIST_LINUX_SIGNALS_FOR_MICROBLAZE + case LIBSYSCALLS_ARCH_MICROBLAZE_32_LE: + case LIBSYSCALLS_ARCH_MICROBLAZE_32_BE: +#ifdef LIST_LINUX_SIGNALS_FOR_MICROBLAZE_32 CASE(microblaze); #else break; #endif - case LIBSYSCALLS_ARCH_MIPS_O32: - case LIBSYSCALLS_ARCH_MIPS_N32: - case LIBSYSCALLS_ARCH_MIPS_N64: + case LIBSYSCALLS_ARCH_MIPS_O32_LE: + case LIBSYSCALLS_ARCH_MIPS_O32_BE: + case LIBSYSCALLS_ARCH_MIPS_N32_LE: + case LIBSYSCALLS_ARCH_MIPS_N32_BE: + case LIBSYSCALLS_ARCH_MIPS_N64_LE: + case LIBSYSCALLS_ARCH_MIPS_N64_BE: #ifdef LIST_LINUX_SIGNALS_FOR_MIPS CASE(mips); #else @@ -76,10 +84,14 @@ get_linux_signals(enum libsyscalls_arch arch, const struct libsyscalls_named_num break; #endif - case LIBSYSCALLS_ARCH_POWERPC_32: - case LIBSYSCALLS_ARCH_POWERPC_64: - case LIBSYSCALLS_ARCH_POWERPC_NOSPU: - case LIBSYSCALLS_ARCH_POWERPC_SPU: + case LIBSYSCALLS_ARCH_POWERPC_32_LE: + case LIBSYSCALLS_ARCH_POWERPC_32_BE: + case LIBSYSCALLS_ARCH_POWERPC_64_LE: + case LIBSYSCALLS_ARCH_POWERPC_64_BE: + case LIBSYSCALLS_ARCH_POWERPC_NOSPU_LE: + case LIBSYSCALLS_ARCH_POWERPC_NOSPU_BE: + case LIBSYSCALLS_ARCH_POWERPC_SPU_LE: + case LIBSYSCALLS_ARCH_POWERPC_SPU_BE: #ifdef LIST_LINUX_SIGNALS_FOR_POWERPC CASE(powerpc); #else @@ -94,7 +106,8 @@ get_linux_signals(enum libsyscalls_arch arch, const struct libsyscalls_named_num break; #endif - case LIBSYSCALLS_ARCH_SH: + case LIBSYSCALLS_ARCH_SH_LE: + case LIBSYSCALLS_ARCH_SH_BE: #ifdef LIST_LINUX_SIGNALS_FOR_SH CASE(sh); #else @@ -102,14 +115,16 @@ get_linux_signals(enum libsyscalls_arch arch, const struct libsyscalls_named_num #endif case LIBSYSCALLS_ARCH_SPARC_32: - case LIBSYSCALLS_ARCH_SPARC_64: + case LIBSYSCALLS_ARCH_SPARC_64_LE: + case LIBSYSCALLS_ARCH_SPARC_64_BE: #ifdef LIST_LINUX_SIGNALS_FOR_SPARC CASE(sparc); #else break; #endif - case LIBSYSCALLS_ARCH_XTENSA: + case LIBSYSCALLS_ARCH_XTENSA_LE: + case LIBSYSCALLS_ARCH_XTENSA_BE: #ifdef LIST_LINUX_SIGNALS_FOR_XTENSA CASE(xtensa); #else diff --git a/linux/structs.c b/linux/structs.c new file mode 100644 index 0000000..d9ac2d7 --- /dev/null +++ b/linux/structs.c @@ -0,0 +1,248 @@ +/* See LICENSE file for copyright and license details. */ + +/* This file is included from ../libsyscalls_get_struct_description.c */ + + +/* Don't forget to add new ones to ../libsyscalls.h */ +#define LIST_LINUX_STRUCTS(X, D)\ + X(STRUCT, AIO_SIGSET, 0 /* TODO bitmask */,\ + FIELD("sigmask", ULONG_ARRAY, IN, INPTR),\ + FIELD("sigsetsize", SIZE, IN)) D\ + X(STRUCT, COMPAT_AIO_SIGSET, 0 /* TODO bitmask */,\ + FIELD("sigmask", UINT32, IN, OUT),\ + FIELD("sigsetsize", UINT32, IN, OUT)) D\ + X(STRUCT, CACHESTAT, 0,\ + FIELD("nr_cache", UINT64, IN, OUT),\ + FIELD("nr_dirty", UINT64, IN, OUT),\ + FIELD("nr_writeback", UINT64, IN, OUT),\ + FIELD("nr_evicted", UINT64, IN, OUT),\ + FIELD("nr_recently_evicted", UINT64, IN, OUT)) D\ + X(STRUCT, CACHESTAT_RANGE, 0,\ + FIELD("off", UINT64, IN, OUT),\ + FIELD("len", UINT64, IN, OUT)) D\ + X(STRUCT, CLONE_ARGS, 0, /* TODO which fields are IN and OUT? */\ + FIELD("flags", UINT64, IN) /* TODO bitmask */,\ + FIELD("pidfd", UINT64, IN) /* TODO actually (int *) */,\ + FIELD("child_tid", UINT64, IN) /* TODO actually (pid_t *) */,\ + FIELD("parent_tid", UINT64, IN) /* TODO actually (pid_t *) */,\ + FIELD("exit_signal", UINT64, IN) /* TODO actually INT_SIGNAL */,\ + FIELD("stack", UINT64, IN),\ + FIELD("stack_size", UINT64, IN),\ + FIELD("tls", UINT64, IN), /* TODO actually MEMORY_ADDRESS */\ + /* Since Linux 5.5: */\ + FIELD("set_tid", UINT64, IN), /* TODO acually (pid_t *) with count in next field */\ + FIELD("set_tid_size", UINT64, IN),\ + FIELD("cgroup", UINT64, IN)) /* TODO actually INT_FD */ D\ + X(STRUCT, EPOLL_EVENT, 0, /* TODO different in libc */\ + FIELD("events", UINT, IN, OUT) /* TODO bitmask */,\ + FIELD("data", UINT64, PARTIAL, IN, OUT)) D\ + X(STRUCT, OABI_EPOLL_EVENT, 0, /* TODO different in libc */\ + FIELD("events", UINT, IN, OUT) /* TODO bitmask */,\ + FIELD("data", UINT64_FRONT_32, PARTIAL, IN, OUT),\ + FIELD("data", UINT64_BACK_32, PARTIAL, IN, OUT)) D\ + X(STRUCT, FILE_HANDLE, 0) D /* TODO */\ + X(STRUCT, FUTEX_WAITV, 0,\ + FIELD("val", UINT64, IN, OUT),\ + FIELD("uaddr", UINT64, IN, OUT), /* TODO actually (void *) */\ + FIELD("flags", UINT32, IN, OUT), /* TODO bitmask */\ + FIELD(NULL, UINT32, IN, OUT)) D\ + X(STRUCT, IOB, 0) D /* TODO */\ + X(STRUCT, IOVEC, 0) D /* TODO */\ + X(STRUCT, IO_EVENT, 0,\ + FIELD("data", UINT64, IN, OUT),\ + FIELD("obj", UINT64, IN, OUT),\ + FIELD("res", INT64, IN, OUT),\ + FIELD("res2", INT64, IN, OUT)) D\ + X(STRUCT, IO_URING_PARAMS, 0) D /* TODO */\ + X(STRUCT, ITIMERSPEC, 0,\ + FIELD("it_interval", STRUCT_TIMESPEC, IN, OUT),\ + FIELD("it_value", STRUCT_TIMESPEC, IN, OUT)) D\ + X(STRUCT, ITIMERSPEC64, 0,\ + FIELD("it_interval", STRUCT_TIMESPEC64, IN, OUT),\ + FIELD("it_value", STRUCT_TIMESPEC64, IN, OUT)) D\ + X(STRUCT, KEXEC_SEGMENT, 0) D /* TODO */\ + X(STRUCT, COMPAT_KEXEC_SEGMENT, 0) D /* TODO */\ + X(STRUCT, LANDLOCK_RULESET_ATTR, 0) D /* TODO */\ + X(STRUCT, LINUX_DIRENT, 0) D /* TODO */\ + X(STRUCT, LINUX_DIRENT64, 0) D /* TODO */\ + X(STRUCT, MMAP_ARG_STRUCT, 0) D /* TODO */\ + X(STRUCT, MMSGHDR, 0) D /* TODO */\ + X(STRUCT, MOUNT_ATTR, 0) D /* TODO */\ + X(STRUCT, MQ_ATTR, 0) D /* TODO */\ + X(STRUCT, MSGBUF, 0) D /* TODO */\ + X(STRUCT, MSGHDR, 0) D /* TODO */\ + X(STRUCT, MSQID_DS, 0) D /* TODO */\ + X(STRUCT, NEW_UTSNAME, 0,\ + FIELD("sysname", BUFFER_65, OUT),\ + FIELD("nodename", BUFFER_65, OUT),\ + FIELD("release", BUFFER_65, OUT),\ + FIELD("version", BUFFER_65, OUT),\ + FIELD("machine", BUFFER_65, OUT),\ + FIELD("domainname", BUFFER_65, OUT)) D\ + X(STRUCT, OLDOLD_UTSNAME, 0,\ + FIELD("sysname", BUFFER_9, OUT),\ + FIELD("nodename", BUFFER_9, OUT),\ + FIELD("release", BUFFER_9, OUT),\ + FIELD("version", BUFFER_9, OUT),\ + FIELD("machine", BUFFER_9, OUT)) D\ + X(STRUCT, OLD_ITIMERSPEC32, 0,\ + FIELD("it_interval", STRUCT_OLD_TIMESPEC32, IN, OUT),\ + FIELD("it_value", STRUCT_OLD_TIMESPEC32, IN, OUT)) D\ + X(STRUCT, ITIMERVAL, 0,\ + FIELD("it_interval", STRUCT_TIMEVAL, IN, OUT),\ + FIELD("it_value", STRUCT_TIMEVAL, IN, OUT)) D\ + X(STRUCT, OLD_ITIMERVAL, 0,\ + FIELD("it_interval", STRUCT_OLD_TIMEVAL, IN, OUT),\ + FIELD("it_value", STRUCT_OLD_TIMEVAL, IN, OUT)) D\ + X(STRUCT, OLD_LINUX_DIRENT, 0) D /* TODO */\ + X(STRUCT, OLD_SIGACTION, 0) D /* TODO */\ + X(STRUCT, OLD_STAT, 0) D /* TODO */\ + X(STRUCT, OLD_TIMESPEC32, 0) D /* TODO */\ + X(STRUCT, OLD_TIMEVAL, 0) D /* TODO */\ + X(STRUCT, OLD_TIMEVAL32, 0) D /* TODO */\ + X(STRUCT, OLD_TIMEX32, 0) D /* TODO */\ + X(STRUCT, OLD_UTIMBUF32, 0) D /* TODO */\ + X(STRUCT, OLD_UTSNAME, 0,\ + FIELD("sysname", BUFFER_65, OUT),\ + FIELD("nodename", BUFFER_65, OUT),\ + FIELD("release", BUFFER_65, OUT),\ + FIELD("version", BUFFER_65, OUT),\ + FIELD("machine", BUFFER_65, OUT)) D\ + X(STRUCT, OPEN_HOW, 0) D /* TODO */\ + X(STRUCT, PERF_EVENT_ATTR, 0) D /* TODO */\ + X(STRUCT, POLLFD, 0,\ + FIELD("pollfd", INT_FD, IN),\ + FIELD("events", SHORT, IN), /* TODO bitmask */\ + FIELD("revents", SHORT, OUT)) D /* TODO bitmask */\ + X(STRUCT, RLIMIT, 0,\ + FIELD("rlim_cur", ULONG, IN, OUT),\ + FIELD("rlim_max", ULONG, IN, OUT)) D\ + X(STRUCT, RLIMIT64, 0,\ + FIELD("rlim_cur", UINT64, IN, OUT),\ + FIELD("rlim_max", UINT64, IN, OUT)) D\ + X(STRUCT, COMPAT_RLIMIT, 0,\ + FIELD("rlim_cur", UINT32, IN, OUT),\ + FIELD("rlim_max", UINT32, IN, OUT)) D\ + X(STRUCT, ROBUST_LIST_HEAD, 0) D /* TODO */\ + X(STRUCT, RSEQ, 0) D /* TODO */\ + X(STRUCT, RUSAGE, 0) D /* TODO */\ + X(STRUCT, SCHED_ATTR, 0,\ + FIELD("size", UINT32, IN, OUT),\ + FIELD("sched_policy", UINT32, IN, OUT),\ + FIELD("sched_flags", UINT64, IN, OUT),\ + FIELD("sched_nice", INT32, IN, OUT),\ + FIELD("sched_priority", UINT32, IN, OUT),\ + FIELD("sched_runtime", UINT64, IN, OUT),\ + FIELD("sched_deadline", UINT32, IN, OUT),\ + FIELD("sched_period", UINT32, IN, OUT)) D\ + X(STRUCT, SCHED_PARAM, 0,\ + FIELD("sched_priority", INT, IN, OUT)) D\ + X(STRUCT, SEL_ARG_STRUCT, 0) D /* TODO */\ + X(STRUCT, SEMBUF, 0,\ + FIELD("sem_num", USHORT, IN, OUT),\ + FIELD("sem_op", SHORT, IN, OUT), /* TODO enum */\ + FIELD("sem_flg", SHORT, IN, OUT)) D /* TODO bitmask */\ + X(STRUCT, SEMID_DS, 0) D /* TODO */\ + X(STRUCT, SHMID_DS, 0) D /* TODO */\ + X(STRUCT, SIGACTION, 0) D /* TODO */\ + X(STRUCT, SIGALTSTACK, 0) D /* TODO */\ + X(STRUCT, SIGEVENT, 0) D /* TODO */\ + X(STRUCT, SIGINFO, 0) D /* TODO */\ + X(STRUCT, SOCKADDR, 0) D /* TODO */\ + X(STRUCT, STAT, 0) D /* TODO */\ + X(STRUCT, STAT64, 0) D /* TODO */\ + X(STRUCT, STATFS, 0) D /* TODO */\ + X(STRUCT, STATFS64, 0) D /* TODO */\ + X(STRUCT, STATX, 0) D /* TODO */\ + X(STRUCT, SYSINFO, 0) D /* TODO */\ + X(STRUCT, TIMESPEC, 0) D /* TODO */\ + X(STRUCT, TIMESPEC64, 0) D /* TODO */\ + X(STRUCT, TIMEVAL, 0) D /* TODO */\ + X(STRUCT, TIMEX, 0) D /* TODO */\ + X(STRUCT, TIMEZONE, 0) D /* TODO */\ + X(STRUCT, TMS, 0) D /* TODO */\ + X(STRUCT, USTAT, 0) D /* TODO */\ + X(STRUCT, UTIMBUF, 0) D /* TODO */\ + X(UNION, BPF_ATTR, 0) /* TODO */ + + +#define X(TYPE, NAME, ...)\ + static struct libsyscalls_structure_description linux_##TYPE##_##NAME##_prototype = TYPE(__VA_ARGS__) + LIST_LINUX_STRUCTS(X, ;); +#undef X + + +static enum libsyscalls_error +fix_linux_struct_description(enum libsyscalls_arch arch, enum libsyscalls_datatype datatype, unsigned class, + const void *data, size_t data_size, struct libsyscalls_structure_description *description) +{ + switch ((int)datatype) { + case LIBSYSCALLS_TYPE_STRUCT_SOCKADDR: + if (class != LIBSYSCALLS_TYPEBITS_SCALAR) + return LIBSYSCALLS_E_NOSUCHTYPE; + description->size = 0; + description->relative_position_of_size = +1; + description->absolute_position_of_size = -1; + /* TODO that is the alignment of `struct sockaddr`? */ + break; + + case LIBSYSCALLS_TYPE_STRUCT_CLONE_ARGS: + description->alignment = 64; + break; + + case LIBSYSCALLS_TYPE_STRUCT_RSEQ: + description->alignment = 4 * 64; + break; + + default: + break; + } + + (void) arch; + (void) data; + (void) data_size; + return LIBSYSCALLS_E_OK; +} + + +static enum libsyscalls_error +get_linux_struct_description(enum libsyscalls_arch arch, enum libsyscalls_datatype datatype, unsigned class, + const void *data, size_t data_size, struct libsyscalls_structure_description **description_out, + int *dont_align_fields_out) +{ + struct libsyscalls_structure_description *description; + + switch ((int)datatype) { + case LIBSYSCALLS_TYPE_STRUCT_EPOLL_EVENT: + if (arch == LIBSYSCALLS_ARCH_AMD64 || arch == LIBSYSCALLS_ARCH_AMD64_X32) + datatype = LIBSYSCALLS_TYPE_STRUCT_OABI_EPOLL_EVENT; + break; + + default: + break; + } + +#define CASE(TYPE, NAME, ...)\ + case LIBSYSCALLS_TYPE_##TYPE##_##NAME:\ + description = copy_struct(&linux_##TYPE##_##NAME##_prototype);\ + break + + switch ((int)datatype) { + LIST_LINUX_STRUCTS(CASE, ;); + default: + return LIBSYSCALLS_E_NOSUCHTYPE; + } + +#undef CASE + + if (!description) + return LIBSYSCALLS_E_NOMEM; + + (void) class; + (void) data; + (void) data_size; + + *description_out = description; + *dont_align_fields_out = 0; + return LIBSYSCALLS_E_OK; +} diff --git a/linux/structs.mk b/linux/structs.mk new file mode 100644 index 0000000..748db51 --- /dev/null +++ b/linux/structs.mk @@ -0,0 +1,4 @@ +# See LICENSE file for copyright and license details. + +libsyscalls_get_struct_description.o: linux/structs.c +libsyscalls_get_struct_description.lo: linux/structs.c diff --git a/linux/symbols.c b/linux/symbols.c index 7a3c8e5..ac90b80 100644 --- a/linux/symbols.c +++ b/linux/symbols.c @@ -32,11 +32,6 @@ extract_linux_symbol_signal(struct libsyscalls_symbol_printer_data *data, unsign } -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" -#endif - static const char * extract_linux_symbol_mode(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out) { @@ -133,10 +128,6 @@ extract_linux_symbol_umask(struct libsyscalls_symbol_printer_data *data, unsigne return data->buf; } -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - static const char * extract_linux_symbol_dev(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out) @@ -279,14 +270,9 @@ have_fun: } -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" -#endif - static struct libsyscalls_syscall_display_info * get_linux_syscall_display_info(enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall, - long long int syscall_number, unsigned long long int *syscall_argument) + long long int syscall_number, const unsigned long long int *syscall_argument) { LIBSYSCALLS_SYMBOL_PRINTER_DATA *data; libsyscalls_symbol_printer_function **funcs; @@ -314,18 +300,9 @@ get_linux_syscall_display_info(enum libsyscalls_arch arch, const struct libsysca } { -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wvla" -#endif - char data_vla_buf[(size_t)(nargs + 1) * data_size + data_align]; libsyscalls_symbol_printer_function *funcs_vla[nargs + 1]; -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - data = (void *)ALIGN_BUF(data_vla_buf, data_align); funcs = funcs_vla; @@ -343,7 +320,3 @@ get_linux_syscall_display_info(enum libsyscalls_arch arch, const struct libsysca return build_syscall_display_info(data, data_size, data_align, funcs, syscall, nargs, nsyms); } } - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif diff --git a/linux/syscall-table.c b/linux/syscall-table.c index 5a5d9c2..0b1e0a0 100644 --- a/linux/syscall-table.c +++ b/linux/syscall-table.c @@ -43,8 +43,8 @@ #define X(ARCH)\ - LIST_LINUX_SYSCALLS_FOR_##ARCH(MAKE_##ARCH##_SYSCALL_WITHOUT_COMPAT, MAKE_##ARCH##_SYSCALL_WITH_COMPAT, ;) -LIST_LINUX_ARCHES(X, ;); + LIST_LINUX_SYSCALLS_FOR_##ARCH(MAKE_##ARCH##_SYSCALL_WITHOUT_COMPAT, MAKE_##ARCH##_SYSCALL_WITH_COMPAT, ;); +LIST_LINUX_ARCHES_WITHOUT_ENDIANS(X,) #undef X #ifndef CREATING_DEDUP_TABLE @@ -57,13 +57,13 @@ LIST_LINUX_ARCHES(X, ;); #define X(ARCH)\ static const struct libsyscalls_syscall *const linux_##ARCH##_syscalls_table[] = {\ LIST_LINUX_SYSCALLS_FOR_##ARCH(MAKE_##ARCH##_SYSCALL_TABLE_ENTRY, MAKE_##ARCH##_SYSCALL_TABLE_ENTRY, COMMA)\ - } -LIST_LINUX_ARCHES(X, ;); + }; +LIST_LINUX_ARCHES_WITHOUT_ENDIANS(X,) #undef X - const struct libsyscalls_syscall *const *const libsyscalls_linux_syscalls_table_[] = { -#define X(ARCH) [LIBSYSCALLS_ARCH_##ARCH] = linux_##ARCH##_syscalls_table +#define X(ARCH)\ + [LIBSYSCALLS_ARCH_##ARCH] = linux_##ARCH##_syscalls_table LIST_LINUX_ARCHES(X, COMMA) #undef X }; diff --git a/linux/syscall-table.mk b/linux/syscall-table.mk index 7e6fb1a..a90be35 100644 --- a/linux/syscall-table.mk +++ b/linux/syscall-table.mk @@ -10,7 +10,7 @@ libsyscalls_get_syscall_range.o: $(LINUX_SYSCALLS_HDR) libsyscalls_get_syscall_range.lo: $(LINUX_SYSCALLS_HDR) -generated/linux-syscall-table.h: linux/syscall-table.c common.h linux/linux-support.mk +generated/linux-syscall-table.h: linux/syscall-table.c common.h linux/linux-support.mk linux/syscall-table.mk set -e; \ macros="$$(sed -n 's/^$(s)*$(h)$(s)*define$(s)\{1,\}MAKE_\([^(]*\)(.*$$/\1/p' < linux/syscall-table.c)"; \ for arch in $(SUPPORTED_LINUX_ARCHES); do \ @@ -18,17 +18,19 @@ generated/linux-syscall-table.h: linux/syscall-table.c common.h linux/linux-supp printf '\43define MAKE_%s_%s(...) MAKE_%s(%s, __VA_ARGS__)\n' \ "$$arch" "$$macro" "$$macro" "$$arch"; \ done; \ - done > $@ + done \ + | sed 's/_[BL]E\([_,]\)/\1/g' \ + | sort -u > $@ -generated/linux-syscalls.h: linux/syscalls.mk +generated/linux-syscalls.h: linux/syscalls.mk linux/syscall-table.mk mkdir -p -- generated printf '\43include "%s"\n' $(LINUX_SYSCALLS_HDR) \ | grep -v '"$@"' \ | sed 's:generated/::' > $@ -generated/linux-syscall-ranges.h: $(LINUX_SYSCALLS_ARCH_HDR) +generated/linux-syscall-ranges.h: $(LINUX_SYSCALLS_ARCH_HDR) linux/syscall-table.mk printf '%s\n' 'This may take some time ...'; \ set -e; arch=; \ cat -- $(LINUX_SYSCALLS_ARCH_HDR) \ @@ -60,3 +62,7 @@ generated/linux-syscall-ranges.h: $(LINUX_SYSCALLS_ARCH_HDR) MIN "$$arch" "$$min" \ MAX "$$arch" "$$max"; \ ) > $@ + printf '\43define MIN_LINUX_SYSCALL_FOR_%s\n' $(SUPPORTED_LINUX_ARCHES) \ + | sed -n 's/\(MIN_LINUX_SYSCALL_FOR_.*\)_[LB]E$$/& \1/p' >> $@ + printf '\43define MAX_LINUX_SYSCALL_FOR_%s\n' $(SUPPORTED_LINUX_ARCHES) \ + | sed -n 's/\(MAX_LINUX_SYSCALL_FOR_.*\)_[LB]E$$/& \1/p' >> $@ diff --git a/linux/syscalls.h b/linux/syscalls.h index f55dac5..36c1236 100644 --- a/linux/syscalls.h +++ b/linux/syscalls.h @@ -115,15 +115,6 @@ _Static_assert(END_OF_LINUX_SYMBOL_PRINTERS <= 0xFF, "LINUX_SYMBOL_PRINTER enums #ifndef SYMBOL_PRINTERS_ONLY -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wgnu-flexible-array-initializer" -# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" /* TODO how does that make sense in C23? */ -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wpedantic" -#endif - #define SYS(...) SYSCALL_ABI(linux, __VA_ARGS__) #define SYMBOLS(A, ...) .symbol_printer = (LINUX_SYMBOL_PRINTER_##A __VA_OPT__(SYMBOLS_2(__VA_ARGS__))) @@ -420,7 +411,7 @@ TODO_SYS(sys_sched_setaffinity, SCHEDULING, SET, 3, ZERO(INT), PARAMS(_,INT, _,U #undef TODO_SYS -#define XXX TODO /* when none on the architectures is not support yet by libsyscalls's core */ +#define XXX TODO static struct libsyscalls_syscall_abi TODO = {.category = LIBSYSCALLS_CAT_SUPPORT_PENDING, .min_argument_count = -1, @@ -725,11 +716,11 @@ static struct libsyscalls_syscall_abi TODO = #define linux_syscall_sys_idle XXX /* arm alpha */ #define linux_syscall_sys_pciconfig_iobase XXX /* arm alpha powerpc */ -#define linux_syscall_sys_pciconfig_read TODO /* arm alpha powerpc sparc ia64 */ -#define linux_syscall_sys_pciconfig_write TODO /* arm alpha powerpc sparc ia64 */ +#define linux_syscall_sys_pciconfig_read XXX /* arm alpha powerpc sparc ia64 */ +#define linux_syscall_sys_pciconfig_write XXX /* arm alpha powerpc sparc ia64 */ #define linux_syscall_sys_syscall XXX /* arm mips */ -#define linux_syscall_sys_mmap2 TODO /* arm microblaze parisc powerpc sparc ia64 m64k sh */ -#define linux_syscall_sys_rt_sigreturn_wrapper TODO /* arm microblaze parisc */ +#define linux_syscall_sys_mmap2 XXX /* arm microblaze parisc powerpc sparc ia64 m64k sh */ +#define linux_syscall_sys_rt_sigreturn_wrapper XXX /* arm microblaze parisc */ #define linux_syscall_sys_afs_syscall XXX /* arm */ #define linux_syscall_sys_arm_fadvise64_64 XXX /* arm */ #define linux_syscall_sys_break XXX /* arm */ @@ -764,16 +755,16 @@ static struct libsyscalls_syscall_abi TODO = #define linux_syscall_sys_stty XXX /* arm */ #define linux_syscall_sys_ulimit XXX /* arm */ -#define linux_syscall_compat_sys_epoll_pwait TODO /* mips parisc powerpc sparc s390 */ -#define linux_syscall_compat_sys_fanotify_mark TODO /* mips parisc powerpc sparc s390 */ -#define linux_syscall_compat_sys_fcntl TODO /* mips parisc powerpc sparc s390 */ -#define linux_syscall_sys_cacheflush TODO /* mips parisc m68k sh */ -#define linux_syscall_sys32_rt_sigreturn TODO /* mips sparc */ -#define linux_syscall_sys32_sigreturn TODO /* mips sparc */ +#define linux_syscall_compat_sys_epoll_pwait XXX /* mips parisc powerpc sparc s390 */ +#define linux_syscall_compat_sys_fanotify_mark XXX /* mips parisc powerpc sparc s390 */ +#define linux_syscall_compat_sys_fcntl XXX /* mips parisc powerpc sparc s390 */ +#define linux_syscall_sys_cacheflush XXX /* mips parisc m68k sh */ +#define linux_syscall_sys32_rt_sigreturn XXX /* mips sparc */ +#define linux_syscall_sys32_sigreturn XXX /* mips sparc */ #define linux_syscall_compat_sys_recv XXX /* mips powerpc */ -#define linux_syscall___sys_clone TODO /* mips m68k */ -#define linux_syscall___sys_clone3 TODO /* mips m68k */ -#define linux_syscall___sys_fork TODO /* mips m68k */ +#define linux_syscall___sys_clone XXX /* mips m68k */ +#define linux_syscall___sys_clone3 XXX /* mips m68k */ +#define linux_syscall___sys_fork XXX /* mips m68k */ #define linux_syscall___sys_sysmips XXX /* mips */ #define linux_syscall_compat_sys_old_msgctl XXX /* mips */ #define linux_syscall_compat_sys_old_semctl XXX /* mips */ @@ -797,9 +788,9 @@ static struct libsyscalls_syscall_abi TODO = #define linux_syscall_sysm_pipe XXX /* mips */ #define linux_syscall_sysn32_rt_sigreturn XXX /* mips */ -#define linux_syscall_sys_stime TODO /* powerpc parisc sparc */ -#define linux_syscall_compat_sys_sendfile64 TODO /* powerpc parisc s390 */ -#define linux_syscall_compat_sys_fallocate TODO /* powerpc sparc */ +#define linux_syscall_sys_stime XXX /* powerpc parisc sparc */ +#define linux_syscall_compat_sys_sendfile64 XXX /* powerpc parisc s390 */ +#define linux_syscall_compat_sys_fallocate XXX /* powerpc sparc */ #define linux_syscall_alpha_syscall_zero XXX /* alpha */ #define linux_syscall_sys_getdtablesize XXX /* alpha */ @@ -851,75 +842,75 @@ static struct libsyscalls_syscall_abi TODO = #define linux_syscall_sys_pread_wrapper XXX /* sh */ #define linux_syscall_sys_pwrite_wrapper XXX /* sh */ -#define linux_syscall___sys_vfork TODO /* m68k */ -#define linux_syscall_sys_atomic_barrier TODO /* m68k */ -#define linux_syscall_sys_atomic_cmpxchg_32 TODO /* m68k */ - -#define linux_syscall_compat_sys_io_pgetevents_time64 TODO /* parisc */ -#define linux_syscall_parisc_compat_signalfd4 TODO /* parisc */ -#define linux_syscall_parisc_eventfd2 TODO /* parisc */ -#define linux_syscall_parisc_fadvise64_64 TODO /* parisc */ -#define linux_syscall_parisc_fallocate TODO /* parisc */ -#define linux_syscall_parisc_ftruncate64 TODO /* parisc */ -#define linux_syscall_parisc_inotify_init1 TODO /* parisc */ -#define linux_syscall_parisc_madvise TODO /* parisc */ -#define linux_syscall_parisc_personality TODO /* parisc */ -#define linux_syscall_parisc_pipe2 TODO /* parisc */ -#define linux_syscall_parisc_pread64 TODO /* parisc */ -#define linux_syscall_parisc_pwrite64 TODO /* parisc */ -#define linux_syscall_parisc_readahead TODO /* parisc */ -#define linux_syscall_parisc_signalfd4 TODO /* parisc */ -#define linux_syscall_parisc_sync_file_range TODO /* parisc */ -#define linux_syscall_parisc_timerfd_create TODO /* parisc */ -#define linux_syscall_parisc_truncate64 TODO /* parisc */ -#define linux_syscall_parisc_userfaultfd TODO /* parisc */ -#define linux_syscall_sys32_fanotify_mark TODO /* parisc */ -#define linux_syscall_sys32_unimplemented TODO /* parisc */ -#define linux_syscall_sys_acl_get TODO /* parisc */ -#define linux_syscall_sys_acl_set TODO /* parisc */ -#define linux_syscall_sys_alloc_hugepages TODO /* parisc */ -#define linux_syscall_sys_attrctl TODO /* parisc */ -#define linux_syscall_sys_clone3_wrapper TODO /* parisc */ -#define linux_syscall_sys_clone_wrapper TODO /* parisc */ -#define linux_syscall_sys_fork_wrapper TODO /* parisc */ -#define linux_syscall_sys_free_hugepages TODO /* parisc */ -#define linux_syscall_sys_timerfd TODO /* parisc */ -#define linux_syscall_sys_vfork_wrapper TODO /* parisc */ - -#define linux_syscall_compat_sys_fadvise64 TODO /* sparc */ -#define linux_syscall_compat_sys_fadvise64_64 TODO /* sparc */ -#define linux_syscall_compat_sys_fstat64 TODO /* sparc */ -#define linux_syscall_compat_sys_fstatat64 TODO /* sparc */ -#define linux_syscall_compat_sys_lstat64 TODO /* sparc */ -#define linux_syscall_compat_sys_pread64 TODO /* sparc */ -#define linux_syscall_compat_sys_pwrite64 TODO /* sparc */ -#define linux_syscall_compat_sys_readahead TODO /* sparc */ -#define linux_syscall_compat_sys_sparc_sigaction TODO /* sparc */ -#define linux_syscall_compat_sys_stat64 TODO /* sparc */ -#define linux_syscall_compat_sys_sync_file_range TODO /* sparc */ -#define linux_syscall_sparc_exit TODO /* sparc */ -#define linux_syscall_sparc_exit_group TODO /* sparc */ -#define linux_syscall_sunos_execv TODO /* sparc */ -#define linux_syscall_sys32_execve TODO /* sparc */ -#define linux_syscall_sys32_execveat TODO /* sparc */ -#define linux_syscall_sys32_mmap2 TODO /* sparc */ -#define linux_syscall_sys32_socketcall TODO /* sparc */ -#define linux_syscall_sys64_execve TODO /* sparc */ -#define linux_syscall_sys64_execveat TODO /* sparc */ -#define linux_syscall_sys_64_mremap TODO /* sparc */ -#define linux_syscall_sys_64_munmap TODO /* sparc */ -#define linux_syscall_sys_getdomainname TODO /* sparc */ -#define linux_syscall_sys_kern_features TODO /* sparc */ -#define linux_syscall_sys_memory_ordering TODO /* sparc */ -#define linux_syscall_sys_nis_syscall TODO /* sparc */ -#define linux_syscall_sys_sparc64_personality TODO /* sparc */ -#define linux_syscall_sys_sparc_adjtimex TODO /* sparc */ -#define linux_syscall_sys_sparc_clock_adjtime TODO /* sparc */ -#define linux_syscall_sys_sparc_ipc TODO /* sparc */ -#define linux_syscall_sys_sparc_pipe TODO /* sparc */ -#define linux_syscall_sys_sparc_remap_file_pages TODO /* sparc */ -#define linux_syscall_sys_sparc_sigaction TODO /* sparc */ -#define linux_syscall_sys_utrap_install TODO /* sparc */ +#define linux_syscall___sys_vfork XXX /* m68k */ +#define linux_syscall_sys_atomic_barrier XXX /* m68k */ +#define linux_syscall_sys_atomic_cmpxchg_32 XXX /* m68k */ + +#define linux_syscall_compat_sys_io_pgetevents_time64 XXX /* parisc */ +#define linux_syscall_parisc_compat_signalfd4 XXX /* parisc */ +#define linux_syscall_parisc_eventfd2 XXX /* parisc */ +#define linux_syscall_parisc_fadvise64_64 XXX /* parisc */ +#define linux_syscall_parisc_fallocate XXX /* parisc */ +#define linux_syscall_parisc_ftruncate64 XXX /* parisc */ +#define linux_syscall_parisc_inotify_init1 XXX /* parisc */ +#define linux_syscall_parisc_madvise XXX /* parisc */ +#define linux_syscall_parisc_personality XXX /* parisc */ +#define linux_syscall_parisc_pipe2 XXX /* parisc */ +#define linux_syscall_parisc_pread64 XXX /* parisc */ +#define linux_syscall_parisc_pwrite64 XXX /* parisc */ +#define linux_syscall_parisc_readahead XXX /* parisc */ +#define linux_syscall_parisc_signalfd4 XXX /* parisc */ +#define linux_syscall_parisc_sync_file_range XXX /* parisc */ +#define linux_syscall_parisc_timerfd_create XXX /* parisc */ +#define linux_syscall_parisc_truncate64 XXX /* parisc */ +#define linux_syscall_parisc_userfaultfd XXX /* parisc */ +#define linux_syscall_sys32_fanotify_mark XXX /* parisc */ +#define linux_syscall_sys32_unimplemented XXX /* parisc */ +#define linux_syscall_sys_acl_get XXX /* parisc */ +#define linux_syscall_sys_acl_set XXX /* parisc */ +#define linux_syscall_sys_alloc_hugepages XXX /* parisc */ +#define linux_syscall_sys_attrctl XXX /* parisc */ +#define linux_syscall_sys_clone3_wrapper XXX /* parisc */ +#define linux_syscall_sys_clone_wrapper XXX /* parisc */ +#define linux_syscall_sys_fork_wrapper XXX /* parisc */ +#define linux_syscall_sys_free_hugepages XXX /* parisc */ +#define linux_syscall_sys_timerfd XXX /* parisc */ +#define linux_syscall_sys_vfork_wrapper XXX /* parisc */ + +#define linux_syscall_compat_sys_fadvise64 XXX /* sparc */ +#define linux_syscall_compat_sys_fadvise64_64 XXX /* sparc */ +#define linux_syscall_compat_sys_fstat64 XXX /* sparc */ +#define linux_syscall_compat_sys_fstatat64 XXX /* sparc */ +#define linux_syscall_compat_sys_lstat64 XXX /* sparc */ +#define linux_syscall_compat_sys_pread64 XXX /* sparc */ +#define linux_syscall_compat_sys_pwrite64 XXX /* sparc */ +#define linux_syscall_compat_sys_readahead XXX /* sparc */ +#define linux_syscall_compat_sys_sparc_sigaction XXX /* sparc */ +#define linux_syscall_compat_sys_stat64 XXX /* sparc */ +#define linux_syscall_compat_sys_sync_file_range XXX /* sparc */ +#define linux_syscall_sparc_exit XXX /* sparc */ +#define linux_syscall_sparc_exit_group XXX /* sparc */ +#define linux_syscall_sunos_execv XXX /* sparc */ +#define linux_syscall_sys32_execve XXX /* sparc */ +#define linux_syscall_sys32_execveat XXX /* sparc */ +#define linux_syscall_sys32_mmap2 XXX /* sparc */ +#define linux_syscall_sys32_socketcall XXX /* sparc */ +#define linux_syscall_sys64_execve XXX /* sparc */ +#define linux_syscall_sys64_execveat XXX /* sparc */ +#define linux_syscall_sys_64_mremap XXX /* sparc */ +#define linux_syscall_sys_64_munmap XXX /* sparc */ +#define linux_syscall_sys_getdomainname XXX /* sparc */ +#define linux_syscall_sys_kern_features XXX /* sparc */ +#define linux_syscall_sys_memory_ordering XXX /* sparc */ +#define linux_syscall_sys_nis_syscall XXX /* sparc */ +#define linux_syscall_sys_sparc64_personality XXX /* sparc */ +#define linux_syscall_sys_sparc_adjtimex XXX /* sparc */ +#define linux_syscall_sys_sparc_clock_adjtime XXX /* sparc */ +#define linux_syscall_sys_sparc_ipc XXX /* sparc */ +#define linux_syscall_sys_sparc_pipe XXX /* sparc */ +#define linux_syscall_sys_sparc_remap_file_pages XXX /* sparc */ +#define linux_syscall_sys_sparc_sigaction XXX /* sparc */ +#define linux_syscall_sys_utrap_install XXX /* sparc */ #define linux_syscall_compat_sys_mmap2 XXX /* powerpc */ #define linux_syscall_compat_sys_ppc32_fadvise64 XXX /* powerpc */ @@ -978,11 +969,5 @@ static struct libsyscalls_syscall_abi TODO = #define linux_syscall_sys_s390_runtime_instr XXX /* s390 */ #define linux_syscall_sys_s390_sthyi XXX /* s390 */ -#if defined(__clang__) -# pragma clang diagnostic pop -#else -# pragma GCC diagnostic pop -#endif - #endif /* !SYMBOL_PRINTERS_ONLY */ diff --git a/linux/syscalls.mk b/linux/syscalls.mk index de748b3..190f170 100644 --- a/linux/syscalls.mk +++ b/linux/syscalls.mk @@ -161,7 +161,7 @@ generated/linux-syscalls/m68k.h: $(LINUX_SYSCALL_DIR)/m68k.tbl linux/syscalls.mk generated/linux-syscalls/microblaze.h: $(LINUX_SYSCALL_DIR)/microblaze.tbl linux/syscalls.mk mkdir -p -- generated/linux-syscalls - printf '\43define LIST_LINUX_SYSCALLS_FOR_MICROBLAZE(X, _X_COMPAT, D)\\\n' > $@ + printf '\43define LIST_LINUX_SYSCALLS_FOR_MICROBLAZE_32(X, _X_COMPAT, D)\\\n' > $@ printf '%i common %s %s\n' \ 251 set_zone_reclaim sys_set_zone_reclaim \ 285 setaltroot sys_setaltroot \ @@ -450,3 +450,5 @@ generated/linux-syscall-dedup.h: $(HDR) $(LINUX_SYSCALLS_HDR) linux/syscalls.h l fi; \ done \ ) > $@ + printf '\43define linux_%s_syscalls_table\n' $(SUPPORTED_LINUX_ARCHES) \ + | sed -n 's/ linux_\(.*\)_[LB]E_syscalls_table/& linux_\1_syscalls_table/p' >> $@ diff --git a/linux/types.c b/linux/types.c index 66bb276..83f2bd1 100644 --- a/linux/types.c +++ b/linux/types.c @@ -3,9 +3,7 @@ /* This file is included from ../libsyscalls_get_datatype_description.c */ -/* If new architectures are added, the table at the top of - * ../libsyscalls_get_datatype_description.c must be updated */ - +/* If new architectures are added, LIST_ARCH_SPECS in ../common.h must be updated */ static enum libsyscalls_error get_linux_datatype_description(enum libsyscalls_arch arch, enum libsyscalls_datatype *datatype, @@ -17,7 +15,7 @@ get_linux_datatype_description(enum libsyscalls_arch arch, enum libsyscalls_data * and long long int as 64 bit (it's code even make such assumptions), * however that's is not necessarily the case for more exotic * architectures, for example, some specialised processors have 16 bit - * chars and run Linux (although not mainline). Linux also used + * chars and run Linux (although not mainline). Linux also uses * long int for addresses (intptr_t), which is normally how it should * be done but Windows always set long int to 32 bit (at least on x86/amd64) * for backwards compatibility, and of course it cannot be assumed that diff --git a/mk/generate.mk b/mk/generate.mk index f5361c4..7e81fb4 100644 --- a/mk/generate.mk +++ b/mk/generate.mk @@ -25,6 +25,9 @@ libsyscalls_get_datatype_description.lo: generated/types.c libsyscalls_get_integer_alignment.o: generated/integers.c libsyscalls_get_integer_alignment.lo: generated/integers.c +libsyscalls_get_struct_description.o: generated/structs.c +libsyscalls_get_struct_description.lo: generated/structs.c + $(GET_SYSCALL_RANGE_GEN): get_syscall_range.template.c mk/generate.mk mkdir -p -- generated @@ -56,6 +59,10 @@ generated/integers.c: Makefile mk/generate.mk mkdir -p -- generated printf '\43include "../%s/integers.c"\n' $(OPERATING_SYSTEMS) > $@ +generated/structs.c: Makefile mk/generate.mk + mkdir -p -- generated + printf '\43include "../%s/structs.c"\n' $(OPERATING_SYSTEMS) > $@ + generated/arches.h: Makefile mk/generate.mk mkdir -p -- generated printf '\43include "%s-arches.h"\n' $(OPERATING_SYSTEMS) > $@ @@ -94,14 +101,23 @@ libsyscalls/short-enums.h: libsyscalls.h mk/generate.mk generated/macros.h: common.h mk/generate.mk set -e;\ + for find in COUNT_ARGS; do \ + text="$$(sed -n 's/^$(s)*$(h)$(s)*define$(s)\{1,\}'"$$find"'_1(/&/p' < common.h)"; \ + i=1; while (( i <= $(NFIELDS) )); do \ + j=$$(( i + 1 )); \ + printf '%s\n' "$$text" | sed -e "s/_1/_ZZZ/g" -e "s/_2/_$$j/g" -e "s/_ZZZ/_$$i/g"; \ + i=$$j; \ + done; \ + done > $@; + set -e;\ for find in COUNT_ARG_PAIRS PARAMS_BUILD_TYPES; do \ text="$$(sed -n 's/^$(s)*$(h)$(s)*define$(s)\{1,\}'"$$find"'_1(/&/p' < common.h)"; \ i=1; while (( i <= $(NPARAMS) )); do \ j=$$(( i + 1 )); \ - printf '%s\n' "$$text" | sed -e "s/_2/_$$j/g" -e "s/_1/_$$i/g"; \ + printf '%s\n' "$$text" | sed -e "s/_1/_ZZZ/g" -e "s/_2/_$$j/g" -e "s/_ZZZ/_$$i/g"; \ i=$$j; \ done; \ - done > $@; + done >> $@; (set -e; \ nparamspairs="$$(i=1; while (( i <= $(NPARAMS) )); do printf '%s\n' $$i $$i; : $$(( i++ )); done)"; \ printf '\43define PARAMS_BUILD_MASK(MASK, ...)\\\n'; \ @@ -1,68 +1,49 @@ #!/bin/sh # See LICENSE file for copyright and license details. -if test $# = 0; then - if "$0" fail for me; then - printf 'Testing is broken!\n' >&2 - exit 2 - fi - set +e - "$0" $$ - r=$? - rm -f -- .?-$$.tmp - exit $r -fi +. tests/preamble - -set -e -test $# = 1 -pid=$1 -a=.a-$pid.tmp -b=.b-$pid.tmp -PATH="$(dirname -- "$0")/testutil:$PATH" -export PATH - -. tests/load-functions - -alias t=. +t=. # this is for test development; set to : to skip tests # have already been written and passed, set to . otherwise - -if ! env | grep '^SUPPORTED_OSES=' >/dev/null; then - printf '%s\n' \ - "The test's environment has not been set up;" \ - 'you should run the test via `make check`' - exit 1 -fi +# t is used to synchronous tests, +# p is used for asynchronous tests, and use t to determine whether to run +# If you want to force all tests to run synchronous, uncomment the next line +#alias p=t set -v -(. tests/test-self-check) >/dev/null 2>/dev/null t tests/enums . tests/load-types -t tests/errors -t tests/syscall-ranges -t tests/syscall-errors -t tests/signals -t tests/split-register-classes +p tests/errors +p tests/syscall-ranges +p tests/syscall-errors +p tests/signals +p tests/split-register-classes +p tests/signness +p tests/endians +p tests/sections +await . tests/load-archinfo t tests/archinfo -t tests/fundamental-primitives -t tests/is-struct -t tests/array-types -t tests/fixed-array-types -t tests/split-register-types -t tests/os-dependent-primitives -t tests/os-dependent-arrays -t tests/os-dependent-integers - +p tests/fundamental-primitives +p tests/is-struct +p tests/array-types +p tests/fixed-array-types +p tests/split-register-types +p tests/os-dependent-primitives +p tests/os-dependent-arrays +p tests/os-dependent-integers +await +# TODO test libsyscalls_get_struct_description +# TODO test libsyscalls_get_struct_display_info # TODO test libsyscalls_get_syscall # TODO test libsyscalls_get_syscall_display_info diff --git a/tests/default-integers b/tests/default-integers index 12faa5a..a33e51a 100644 --- a/tests/default-integers +++ b/tests/default-integers @@ -9,7 +9,13 @@ for arch in $(getnamelist ARCH); do if test $arch = M68K; then maxalign=16 - elif test $arch = I386; then + elif test $arch = I386 || \ + test $arch = ARM_OABI_LE || \ + test $arch = ARM_OABI_BE || \ + test $arch = SH_LE || \ + test $arch = SH_BE || \ + test $arch = MICROBLAZE_32_LE || \ + test $arch = MICROBLAZE_32_BE; then maxalign=32 else maxalign=64 diff --git a/tests/endians b/tests/endians new file mode 100644 index 0000000..13f29f8 --- /dev/null +++ b/tests/endians @@ -0,0 +1,175 @@ +# -*- sh -*- +# See LICENSE file for copyright and license details. + +check_endian () { + xvalue="$1" + text0="$2" + text1="$3" + textoff="$4" + bits="$5" + shift 5 + + sxvalue="$(printf '%s\n' "$xvalue" | sed 's/^0*//' | sed 's/^$/0/')" + + test "$(to-tracer-endian.tu $text0 $textoff $bits $@)" = "$sxvalue" + test "$(to-tracer-endian.tu $text1 $textoff $bits $@)" = "$sxvalue" + test "$(to-tracee-endian.tu $xvalue $textoff $bits $@)" = "$text0 $text1" +} + +check_endian0 () { + xvalue="$1" + text="$2" + textoff="$3" + bits="$4" + shift 4 + check_endian $xvalue $text $text $textoff $bits $@ +} + +check_endian 0 00 FE 0 1 0 +check_endian 0 00 FD 1 1 0 +check_endian 0 00 FB 2 1 0 +check_endian 0 00 F7 3 1 0 +check_endian 0 00 EF 4 1 0 +check_endian 0 00 DF 5 1 0 +check_endian 0 00 BF 6 1 0 +check_endian 0 00 7F 7 1 0 +check_endian 0 0000 FFFE 8 1 0 + +check_endian 1 01 FF 0 1 0 +check_endian 1 02 FF 1 1 0 +check_endian 1 04 FF 2 1 0 +check_endian 1 08 FF 3 1 0 +check_endian 1 10 FF 4 1 0 +check_endian 1 20 FF 5 1 0 +check_endian 1 40 FF 6 1 0 +check_endian 1 80 FF 7 1 0 +check_endian 1 0001 FFFF 8 1 0 + +check_endian 0 00 F0 0 4 0 +check_endian 1 01 F1 0 4 0 +check_endian 2 02 F2 0 4 0 +check_endian 3 03 F3 0 4 0 +check_endian 4 04 F4 0 4 0 +check_endian 8 08 F8 0 4 0 +check_endian A 0A FA 0 4 0 +check_endian F 0F FF 0 4 0 + +check_endian 0 00 E1 1 4 0 +check_endian 0 00 C3 2 4 0 +check_endian 0 00 87 3 4 0 +check_endian 0 00 0F 4 4 0 +check_endian F 1E FF 1 4 0 +check_endian F 3C FF 2 4 0 +check_endian F 78 FF 3 4 0 +check_endian F F0 FF 4 4 0 +check_endian 0 0000 1FFE 5 4 0 +check_endian F E001 FFFF 5 4 0 +check_endian 0 0000 3FFC 6 4 0 +check_endian F C003 FFFF 6 4 0 + +check_endian0 00 00 0 8 0 +check_endian0 10 10 0 8 0 +check_endian0 01 01 0 8 0 +check_endian0 80 80 0 8 0 +check_endian0 08 08 0 8 0 +check_endian0 FF FF 0 8 0 + +check_endian 00 0000 01FE 1 8 0 +check_endian FF FE01 FFFF 1 8 0 + +check_endian 000 0000 00FE 0 9 0 +check_endian 1FF FF01 FFFF 0 9 0 + +check_endian 000 0000 00FC 0 10 0 +check_endian 3FF FF03 FFFF 0 10 0 + +check_endian 000 0000 01FC 1 9 0 +check_endian 1FF FE03 FFFF 1 9 0 + +check_endian 000 0000 01F8 1 10 0 +check_endian 3FF FE07 FFFF 1 10 0 + +check_endian0 0000 0000 0 16 8 0 +check_endian0 FFFF FFFF 0 16 8 0 +check_endian0 1234 1234 0 16 8 0 +check_endian0 0800 0800 0 16 8 0 + +check_endian0 0000 0000 0 16 0 8 +check_endian0 FFFF FFFF 0 16 0 8 +check_endian0 1234 3412 0 16 0 8 +check_endian0 0800 0008 0 16 0 8 + +check_endian0 0000 0000 0 16 0 +check_endian0 FFFF FFFF 0 16 0 +check_endian0 1234 3412 0 16 0 +check_endian0 0800 0008 0 16 0 + +check_endian0 000000 000000 0 24 16 8 0 +check_endian0 FFFFFF FFFFFF 0 24 16 8 0 +check_endian0 160800 160800 0 24 16 8 0 + +check_endian0 000000 000000 0 24 16 0 8 +check_endian0 FFFFFF FFFFFF 0 24 16 0 8 +check_endian0 160800 160008 0 24 16 0 8 + +check_endian0 000000 000000 0 24 0 8 16 +check_endian0 FFFFFF FFFFFF 0 24 0 8 16 +check_endian0 160800 000816 0 24 0 8 16 + +check_endian0 000000 000000 0 24 8 0 16 +check_endian0 FFFFFF FFFFFF 0 24 8 0 16 +check_endian0 160800 080016 0 24 8 0 16 + +check_endian0 000000 000000 0 24 0 16 8 +check_endian0 FFFFFF FFFFFF 0 24 0 16 8 +check_endian0 160800 001608 0 24 0 16 8 + +check_endian0 000000 000000 0 24 8 16 0 +check_endian0 FFFFFF FFFFFF 0 24 8 16 0 +check_endian0 160800 081600 0 24 8 16 0 + +check_endian0 00000000 00000000 0 32 24 16 8 0 +check_endian0 FFFFFFFF FFFFFFFF 0 32 24 16 8 0 +check_endian0 12345678 12345678 0 32 24 16 8 0 +check_endian0 24160800 24160800 0 32 24 16 8 0 + +check_endian0 00000000 00000000 0 32 8 0 24 16 +check_endian0 FFFFFFFF FFFFFFFF 0 32 8 0 24 16 +check_endian0 12345678 56781234 0 32 8 0 24 16 +check_endian0 24160800 08002416 0 32 8 0 24 16 + +check_endian0 00000000 00000000 0 32 0 8 16 24 +check_endian0 FFFFFFFF FFFFFFFF 0 32 0 8 16 24 +check_endian0 12345678 78563412 0 32 0 8 16 24 +check_endian0 24160800 00081624 0 32 0 8 16 24 + +check_endian0 00000000 00000000 0 32 0 16 8 24 +check_endian0 FFFFFFFF FFFFFFFF 0 32 0 16 8 24 +check_endian0 12345678 78345612 0 32 0 16 8 24 +check_endian0 24160800 00160824 0 32 0 16 8 24 + +check_endian0 0000000000000000 0000000000000000 0 64 56 48 40 32 24 16 8 0 +check_endian0 FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 0 64 56 48 40 32 24 16 8 0 +check_endian0 0123456789ABCDEF 0123456789ABCDEF 0 64 56 48 40 32 24 16 8 0 +check_endian0 5648403224160800 5648403224160800 0 64 56 48 40 32 24 16 8 0 + +check_endian0 0000000000000000 0000000000000000 0 64 24 16 8 0 56 48 40 32 +check_endian0 FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 0 64 24 16 8 0 56 48 40 32 +check_endian0 0123456789ABCDEF 89ABCDEF01234567 0 64 24 16 8 0 56 48 40 32 +check_endian0 5648403224160800 2416080056484032 0 64 24 16 8 0 56 48 40 32 + +check_endian0 0000000000000000 0000000000000000 0 64 8 0 24 16 40 32 56 48 +check_endian0 FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 0 64 8 0 24 16 40 32 56 48 +check_endian0 0123456789ABCDEF CDEF89AB45670123 0 64 8 0 24 16 40 32 56 48 +check_endian0 5648403224160800 0800241640325648 0 64 8 0 24 16 40 32 56 48 + +check_endian0 0000000000000000 0000000000000000 0 64 0 8 16 24 32 40 48 56 +check_endian0 FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 0 64 0 8 16 24 32 40 48 56 +check_endian0 0123456789ABCDEF EFCDAB8967452301 0 64 0 8 16 24 32 40 48 56 +check_endian0 5648403224160800 0008162432404856 0 64 0 8 16 24 32 40 48 56 + +check_endian 000 0000 00FE 0 9 0 8 +check_endian 1FF FF01 FFFF 0 9 0 8 + +check_endian 000 0000 FE00 0 9 8 0 +check_endian 1FF 01FF FFFF 0 9 8 0 diff --git a/tests/errors b/tests/errors index 8c74731..9e098d1 100644 --- a/tests/errors +++ b/tests/errors @@ -55,5 +55,6 @@ cat > $a <<. 7 LIBSYSCALLS_E_INVAL Invalid arguments passed to function 8 LIBSYSCALLS_E_NOSUCHTYPE Type does not exist on the selected operating system or architecture 9 LIBSYSCALLS_E_ISSTRUCT Type is a structure or union +10 LIBSYSCALLS_E_ISNOTSTRUCT Type is not a structure or union . list-errors.tu | diff -u $a - diff --git a/tests/fixed-array-types b/tests/fixed-array-types index 070920e..06dcbb5 100644 --- a/tests/fixed-array-types +++ b/tests/fixed-array-types @@ -29,5 +29,14 @@ for os in $(getnamelist OS); do | sed 's/^\(array_size\) = 1$/\1 = 2/' > $a get-datatype-description.tu $osn $archn $(lookupnum "$types" $atype) $os $arch $atype > $b diff -u $a $b + + for n in 9 65; do + ptype=CHAR + atype=BUFFER_$n + get-datatype-description.tu $osn $archn $(lookupnum "$types" $ptype) $os $arch $ptype \ + | sed 's/^\(array_size\) = 1$/\1 = '$n/ > $a + get-datatype-description.tu $osn $archn $(lookupnum "$types" $atype) $os $arch $atype > $b + diff -u $a $b + done done done diff --git a/tests/load-archinfo b/tests/load-archinfo index 09d472b..e5413b4 100644 --- a/tests/load-archinfo +++ b/tests/load-archinfo @@ -18,7 +18,7 @@ getbyteorder () { printf '%s\n' "$byteorders" | grep "^$1$2 " | cut -d ' ' -f 2- } -sed '1,/LIST_ARCH_SPECS/d' < libsyscalls_get_datatype_description.c \ +sed '1,/LIST_ARCH_SPECS/d' < common.h \ | sed '/#include/q' \ | sed 's/\(TO''DO\)[[:space:]]*([^)]*)/\1/g' \ | sed -n 's/^[[:space:]]*[A-Z_]\{1,\}(LIBSYSCALLS_ARCH_\([^)]*\)).*$/\1/p' \ diff --git a/tests/load-functions b/tests/load-functions index 2e9ddda..3436158 100644 --- a/tests/load-functions +++ b/tests/load-functions @@ -1,6 +1,30 @@ # -*- sh -*- # See LICENSE file for copyright and license details. +parallelindex=0 +p () { + ( + set +ev + pid=$$-$parallelindex + a=.a-$pid.tmp + b=.b-$pid.tmp + log=.x-$pid.tmp + ( set -ev ; $t "$@" ) > $log 2>&1 + r=$? + test $r = 0 || cat -- $log >&2 + rm -f -- .?-$pid.tmp + exit $r + ) & + eval parallelpid$(( ++parallelindex ))=$! +} +await () { + while (( parallelindex )); do + parallelvar=parallelpid$(( parallelindex-- )) + eval wait '$'$parallelvar + done +} + + stderr () { ("$@") 2>&1 >/dev/null } diff --git a/tests/preamble b/tests/preamble new file mode 100644 index 0000000..527a098 --- /dev/null +++ b/tests/preamble @@ -0,0 +1,41 @@ +# -*- sh -*- +# See LICENSE file for copyright and license details. + +if test $# = 0; then + if "$0" fail for me; then + printf 'Testing is broken!\n' >&2 + exit 2 + fi + set +e + "$0" $$ + r=$? + rm -f -- .?-$$.tmp + exit $r +fi + + +set -e +test $# = 1 +pid=$1 +a=.a-$pid.tmp +b=.b-$pid.tmp +PATH="$(dirname -- "$0")/testutil:$PATH" +export PATH + + +if ! env | grep '^SUPPORTED_OSES=' >/dev/null; then + printf '%s\n' \ + "The test's environment has not been set up;" \ + 'you should run the test via `make check`' + exit 1 +fi + +. tests/load-functions + +alias t='$t' + +if ! (. tests/test-self-check) >/dev/null 2>/dev/null; then + printf '%s\n' \ + "The test's self-check failed" + exit 1 +fi diff --git a/tests/sections b/tests/sections new file mode 100644 index 0000000..1574b8d --- /dev/null +++ b/tests/sections @@ -0,0 +1,90 @@ +# -*- sh -*- +# See LICENSE file for copyright and license details. + +check_section () { + sectionn=$1 + whole=$2 + splitinwhole=$3 + split=$(printf '%s\n' $splitinwhole | tr -d -- -) + wholebits=$(( ( $(printf '%s\n' $whole | sed 's/./+1/g') ) * 4 )) + splitbits=$(( ( $(printf '%s\n' $split | sed 's/./+1/g') ) * 4 )) + ssplit=$(printf '%s\n' $split | sed 's/^0*//' | sed 's/^$/0/' ) + ssplitinwhole=$(printf '%s\n' $splitinwhole | tr -- - 0 | sed 's/^0*//' | sed 's/^$/0/' ) + + test $(section-value.tu $sectionn $whole $wholebits) = $ssplit + test $(unsection-value.tu $sectionn $split $splitbits) = $ssplitinwhole +} + +test $(section-value.tu 32767 0 8) = inval +test $(unsection-value.tu 32767 0 8) = inval + +for section in $(getnamelist SECTION); do + sectionn=$(getnum SECTION $section) + if test $section = UNDETERMINED || test $section = WHOLE; then + check_section $sectionn 12 12 + check_section $sectionn 1234 1234 + check_section $sectionn 12345678 12345678 + check_section $sectionn 123456789ABC 123456789ABC + check_section $sectionn 0123456789ABCDEF 0123456789ABCDEF + + elif test $section = UPPER_HALF; then + check_section $sectionn 1234 12-- + check_section $sectionn 12345678 1234---- + check_section $sectionn 123456789ABC 123456------ + check_section $sectionn 0123456789ABCDEF 01234567-------- + + elif test $section = LOWER_HALF; then + check_section $sectionn 1234 --34 + check_section $sectionn 12345678 ----5678 + check_section $sectionn 123456789ABC ------789ABC + check_section $sectionn 0123456789ABCDEF --------89ABCDEF + + elif test $section = INNER_HALF; then + check_section $sectionn 12345678 --3456-- + check_section $sectionn 0123456789ABCDEF ----456789AB---- + + elif test $section = OUTER_HALF; then + check_section $sectionn 12345678 12----78 + check_section $sectionn 0123456789ABCDEF 0123--------CDEF + + elif test $section = EVEN_QUARTERS_AS_HALF; then + check_section $sectionn 12345678 --34--78 + check_section $sectionn 0123456789ABCDEF ----4567----CDEF + + elif test $section = ODD_QUARTERS_AS_HALF; then + check_section $sectionn 12345678 12--56-- + check_section $sectionn 0123456789ABCDEF 0123----89AB---- + + elif test $section = EVEN_BYTES_AS_HALF; then + check_section $sectionn 1234 --34 + check_section $sectionn 12345678 --34--78 + check_section $sectionn 123456789ABC --34--78--BC + check_section $sectionn 0123456789ABCDEF --23--67--AB--EF + + elif test $section = ODD_BYTES_AS_HALF; then + check_section $sectionn 1234 12-- + check_section $sectionn 12345678 12--56-- + check_section $sectionn 123456789ABC 12--56--9A-- + check_section $sectionn 0123456789ABCDEF 01--45--89--CD-- + + elif test $section = UPPER_QUARTER; then + check_section $sectionn 12345678 12------ + check_section $sectionn 0123456789ABCDEF 0123------------ + + elif test $section = UPPER_MID_QUARTER; then + check_section $sectionn 12345678 --34---- + check_section $sectionn 0123456789ABCDEF ----4567-------- + + elif test $section = LOWER_MID_QUARTER; then + check_section $sectionn 12345678 ----56-- + check_section $sectionn 0123456789ABCDEF --------89AB---- + + elif test $section = LOWER_QUARTER; then + check_section $sectionn 12345678 ------78 + check_section $sectionn 0123456789ABCDEF ------------CDEF + + else + printf 'Missing test for LIBSYSCALLS_SECTION_%s in tests/sections\n' "$section" >&2 + false + fi +done diff --git a/tests/signals b/tests/signals index 4052402..733baa4 100644 --- a/tests/signals +++ b/tests/signals @@ -6,11 +6,11 @@ for os in $(getnamelist OS); do for arch in $(getnamelist ARCH); do archn=$(getnum ARCH $arch) get-signals.tu $osn $archn $os $arch > $a - grep -v '^[0-9]\{1,\} -' >/dev/null < $a - grep -v '^-' < $a > $b - grep '^\([0-9]\{1,\}\) \1 ' < $a | diff -u $a - if issupported $os $arch; then (! test "$(cat $a)" = x) + grep -v '^[0-9]\{1,\} -' >/dev/null < $a + grep -v '^-' < $a > $b + grep '^\([0-9]\{1,\}\) \1 ' < $a | diff -u $a - if test "$os" = LINUX; then signed=1 grep '^[0-9]\{1,\} [0-9]\{1,\} [A-Z0-9_+]\{1,\}$' >/dev/null < $a diff --git a/tests/signness b/tests/signness new file mode 100644 index 0000000..8c29fe4 --- /dev/null +++ b/tests/signness @@ -0,0 +1,296 @@ +# -*- sh -*- +# See LICENSE file for copyright and license details. + +test $(parse-signed.tu 32767 32 0) = inval +test $(make-signed.tu 32767 32 0) = inval + +check_signed () { + test $(parse-signed.tu $1 $2 $3) = $4 + test $(make-signed.tu $1 $2 $4) = $3 +} + +ucheck_signed () { + check_signed "$@" + test $(make-signed.tu $1 $2 -$4) = $3 +} + +for sign in $(getnamelist SIGN); do + signn=$(getnum SIGN $sign) + if test $sign = UNDETERMINED; then + ucheck_signed $signn 1 0 0 + ucheck_signed $signn 1 1 1 + ucheck_signed $signn 2 0 0 + ucheck_signed $signn 2 1 1 + ucheck_signed $signn 2 2 2 + ucheck_signed $signn 2 3 3 + ucheck_signed $signn 4 4 4 + ucheck_signed $signn 4 9 9 + ucheck_signed $signn 4 A A + ucheck_signed $signn 4 C C + ucheck_signed $signn 4 F F + ucheck_signed $signn 7 00 00 + ucheck_signed $signn 7 08 08 + ucheck_signed $signn 7 70 70 + ucheck_signed $signn 7 7F 7F + ucheck_signed $signn 8 00 00 + ucheck_signed $signn 8 08 08 + ucheck_signed $signn 8 80 80 + ucheck_signed $signn 8 FF FF + ucheck_signed $signn 16 0001 0001 + ucheck_signed $signn 16 0020 0020 + ucheck_signed $signn 16 0300 0300 + ucheck_signed $signn 16 4000 4000 + ucheck_signed $signn 16 0008 0008 + ucheck_signed $signn 16 0090 0090 + ucheck_signed $signn 16 0A00 0A00 + ucheck_signed $signn 16 B000 B000 + ucheck_signed $signn 17 08100 08100 + ucheck_signed $signn 17 00820 00820 + ucheck_signed $signn 17 00083 00083 + ucheck_signed $signn 17 04008 04008 + ucheck_signed $signn 17 11008 11008 + ucheck_signed $signn 17 10280 10280 + ucheck_signed $signn 17 10830 10830 + ucheck_signed $signn 17 18004 18004 + ucheck_signed $signn 32 12345678 12345678 + ucheck_signed $signn 32 9ABCDEF0 9ABCDEF0 + ucheck_signed $signn 32 87654321 87654321 + ucheck_signed $signn 32 0FEDCBA9 0FEDCBA9 + ucheck_signed $signn 64 0123456789ABCDEF 0123456789ABCDEF + ucheck_signed $signn 64 123456789ABCDEF0 123456789ABCDEF0 + ucheck_signed $signn 64 23456789ABCDEF01 23456789ABCDEF01 + ucheck_signed $signn 64 3456789ABCDEF012 3456789ABCDEF012 + ucheck_signed $signn 64 89ABCDEF01234567 89ABCDEF01234567 + ucheck_signed $signn 64 9ABCDEF012345678 9ABCDEF012345678 + ucheck_signed $signn 64 ABCDEF0123456789 ABCDEF0123456789 + ucheck_signed $signn 64 BCDEF0123456789A BCDEF0123456789A + ucheck_signed $signn 64 0000000000000000 0000000000000000 + ucheck_signed $signn 64 7FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF + ucheck_signed $signn 64 8000000000000000 8000000000000000 + ucheck_signed $signn 64 FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF + + elif test $sign = SIGN_MAGNITUDE; then + check_signed $signn 1 0 0 + check_signed $signn 1 1 -0 + check_signed $signn 2 0 0 + check_signed $signn 2 1 1 + check_signed $signn 2 2 -0 + check_signed $signn 2 3 -1 + check_signed $signn 4 4 4 + check_signed $signn 4 9 -1 + check_signed $signn 4 A -2 + check_signed $signn 4 C -4 + check_signed $signn 4 F -7 + check_signed $signn 7 00 00 + check_signed $signn 7 08 08 + check_signed $signn 7 70 -30 + check_signed $signn 7 7F -3F + check_signed $signn 8 00 00 + check_signed $signn 8 08 08 + check_signed $signn 8 80 -00 + check_signed $signn 8 FF -7F + check_signed $signn 16 0001 0001 + check_signed $signn 16 0020 0020 + check_signed $signn 16 0300 0300 + check_signed $signn 16 4000 4000 + check_signed $signn 16 0008 0008 + check_signed $signn 16 0090 0090 + check_signed $signn 16 0A00 0A00 + check_signed $signn 16 B000 -3000 + check_signed $signn 17 08100 08100 + check_signed $signn 17 00820 00820 + check_signed $signn 17 00083 00083 + check_signed $signn 17 04008 04008 + check_signed $signn 17 11008 -01008 + check_signed $signn 17 10280 -00280 + check_signed $signn 17 10830 -00830 + check_signed $signn 17 18004 -08004 + check_signed $signn 32 12345678 12345678 + check_signed $signn 32 9ABCDEF0 -1ABCDEF0 + check_signed $signn 32 87654321 -07654321 + check_signed $signn 32 0FEDCBA9 0FEDCBA9 + check_signed $signn 64 0123456789ABCDEF 0123456789ABCDEF + check_signed $signn 64 123456789ABCDEF0 123456789ABCDEF0 + check_signed $signn 64 23456789ABCDEF01 23456789ABCDEF01 + check_signed $signn 64 3456789ABCDEF012 3456789ABCDEF012 + check_signed $signn 64 89ABCDEF01234567 -09ABCDEF01234567 + check_signed $signn 64 9ABCDEF012345678 -1ABCDEF012345678 + check_signed $signn 64 ABCDEF0123456789 -2BCDEF0123456789 + check_signed $signn 64 BCDEF0123456789A -3CDEF0123456789A + check_signed $signn 64 0000000000000000 0000000000000000 + check_signed $signn 64 7FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF + check_signed $signn 64 8000000000000000 -0000000000000000 + check_signed $signn 64 FFFFFFFFFFFFFFFF -7FFFFFFFFFFFFFFF + + elif test $sign = ONES_COMPLEMENT; then + check_signed $signn 1 0 0 + check_signed $signn 1 1 -0 + check_signed $signn 2 0 0 + check_signed $signn 2 1 1 + check_signed $signn 2 2 -1 + check_signed $signn 2 3 -0 + check_signed $signn 4 4 4 + check_signed $signn 4 9 -6 + check_signed $signn 4 A -5 + check_signed $signn 4 C -3 + check_signed $signn 4 F -0 + check_signed $signn 7 00 00 + check_signed $signn 7 08 08 + check_signed $signn 7 70 -0F + check_signed $signn 7 7F -00 + check_signed $signn 8 00 00 + check_signed $signn 8 08 08 + check_signed $signn 8 80 -7F + check_signed $signn 8 FF -00 + check_signed $signn 16 0001 0001 + check_signed $signn 16 0020 0020 + check_signed $signn 16 0300 0300 + check_signed $signn 16 4000 4000 + check_signed $signn 16 0008 0008 + check_signed $signn 16 0090 0090 + check_signed $signn 16 0A00 0A00 + check_signed $signn 16 B000 -4FFF + check_signed $signn 17 08100 08100 + check_signed $signn 17 00820 00820 + check_signed $signn 17 00083 00083 + check_signed $signn 17 04008 04008 + check_signed $signn 17 11008 -0EFF7 + check_signed $signn 17 10280 -0FD7F + check_signed $signn 17 10830 -0F7CF + check_signed $signn 17 18004 -07FFB + check_signed $signn 32 12345678 12345678 + check_signed $signn 32 9ABCDEF0 -6543210F + check_signed $signn 32 87654321 -789ABCDE + check_signed $signn 32 0FEDCBA9 0FEDCBA9 + check_signed $signn 64 0123456789ABCDEF 0123456789ABCDEF + check_signed $signn 64 123456789ABCDEF0 123456789ABCDEF0 + check_signed $signn 64 23456789ABCDEF01 23456789ABCDEF01 + check_signed $signn 64 3456789ABCDEF012 3456789ABCDEF012 + check_signed $signn 64 89ABCDEF01234567 -76543210FEDCBA98 + check_signed $signn 64 9ABCDEF012345678 -6543210FEDCBA987 + check_signed $signn 64 ABCDEF0123456789 -543210FEDCBA9876 + check_signed $signn 64 BCDEF0123456789A -43210FEDCBA98765 + check_signed $signn 64 0000000000000000 0000000000000000 + check_signed $signn 64 7FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF + check_signed $signn 64 8000000000000000 -7FFFFFFFFFFFFFFF + check_signed $signn 64 FFFFFFFFFFFFFFFF -0000000000000000 + + elif test $sign = TWOS_COMPLEMENT; then + check_signed $signn 1 0 0 + check_signed $signn 1 1 -1 + check_signed $signn 2 0 0 + check_signed $signn 2 1 1 + check_signed $signn 2 2 -2 + check_signed $signn 2 3 -1 + check_signed $signn 4 4 4 + check_signed $signn 4 9 -7 + check_signed $signn 4 A -6 + check_signed $signn 4 C -4 + check_signed $signn 4 F -1 + check_signed $signn 7 00 00 + check_signed $signn 7 08 08 + check_signed $signn 7 70 -10 + check_signed $signn 7 7F -01 + check_signed $signn 8 00 00 + check_signed $signn 8 08 08 + check_signed $signn 8 80 -80 + check_signed $signn 8 FF -01 + check_signed $signn 16 0001 0001 + check_signed $signn 16 0020 0020 + check_signed $signn 16 0300 0300 + check_signed $signn 16 4000 4000 + check_signed $signn 16 0008 0008 + check_signed $signn 16 0090 0090 + check_signed $signn 16 0A00 0A00 + check_signed $signn 16 B000 -5000 + check_signed $signn 17 08100 08100 + check_signed $signn 17 00820 00820 + check_signed $signn 17 00083 00083 + check_signed $signn 17 04008 04008 + check_signed $signn 17 11008 -0EFF8 + check_signed $signn 17 10280 -0FD80 + check_signed $signn 17 10830 -0F7D0 + check_signed $signn 17 18004 -07FFC + check_signed $signn 32 12345678 12345678 + check_signed $signn 32 9ABCDEF0 -65432110 + check_signed $signn 32 87654321 -789ABCDF + check_signed $signn 32 0FEDCBA9 0FEDCBA9 + check_signed $signn 64 0123456789ABCDEF 0123456789ABCDEF + check_signed $signn 64 123456789ABCDEF0 123456789ABCDEF0 + check_signed $signn 64 23456789ABCDEF01 23456789ABCDEF01 + check_signed $signn 64 3456789ABCDEF012 3456789ABCDEF012 + check_signed $signn 64 89ABCDEF01234567 -76543210FEDCBA99 + check_signed $signn 64 9ABCDEF012345678 -6543210FEDCBA988 + check_signed $signn 64 ABCDEF0123456789 -543210FEDCBA9877 + check_signed $signn 64 BCDEF0123456789A -43210FEDCBA98766 + check_signed $signn 64 0000000000000000 0000000000000000 + check_signed $signn 64 7FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF + check_signed $signn 64 8000000000000000 -8000000000000000 + check_signed $signn 64 FFFFFFFFFFFFFFFF -0000000000000001 + test $(make-signed.tu $signn 1 -0) = 0 + test $(make-signed.tu $signn 4 -0) = 0 + + elif test $sign = EXCESS_HALF; then + check_signed $signn 1 0 -1 + check_signed $signn 1 1 0 + check_signed $signn 2 0 -2 + check_signed $signn 2 1 -1 + check_signed $signn 2 2 0 + check_signed $signn 2 3 1 + check_signed $signn 4 4 -4 + check_signed $signn 4 9 1 + check_signed $signn 4 A 2 + check_signed $signn 4 C 4 + check_signed $signn 4 F 7 + check_signed $signn 7 00 -40 + check_signed $signn 7 08 -38 + check_signed $signn 7 70 30 + check_signed $signn 7 7F 3F + check_signed $signn 8 00 -80 + check_signed $signn 8 08 -78 + check_signed $signn 8 80 00 + check_signed $signn 8 FF 7F + check_signed $signn 16 0001 -7FFF + check_signed $signn 16 0020 -7FE0 + check_signed $signn 16 0300 -7D00 + check_signed $signn 16 4000 -4000 + check_signed $signn 16 0008 -7FF8 + check_signed $signn 16 0090 -7F70 + check_signed $signn 16 0A00 -7600 + check_signed $signn 16 B000 3000 + check_signed $signn 17 08100 -07F00 + check_signed $signn 17 00820 -0F7E0 + check_signed $signn 17 00083 -0FF7D + check_signed $signn 17 04008 -0BFF8 + check_signed $signn 17 11008 01008 + check_signed $signn 17 10280 00280 + check_signed $signn 17 10830 00830 + check_signed $signn 17 18004 08004 + check_signed $signn 32 12345678 -6DCBA988 + check_signed $signn 32 9ABCDEF0 1ABCDEF0 + check_signed $signn 32 87654321 07654321 + check_signed $signn 32 0FEDCBA9 -70123457 + check_signed $signn 64 0123456789ABCDEF -7EDCBA9876543211 + check_signed $signn 64 123456789ABCDEF0 -6DCBA98765432110 + check_signed $signn 64 23456789ABCDEF01 -5CBA9876543210FF + check_signed $signn 64 3456789ABCDEF012 -4BA9876543210FEE + check_signed $signn 64 89ABCDEF01234567 09ABCDEF01234567 + check_signed $signn 64 9ABCDEF012345678 1ABCDEF012345678 + check_signed $signn 64 ABCDEF0123456789 2BCDEF0123456789 + check_signed $signn 64 BCDEF0123456789A 3CDEF0123456789A + check_signed $signn 64 0000000000000000 -8000000000000000 + check_signed $signn 64 7FFFFFFFFFFFFFFF -0000000000000001 + check_signed $signn 64 8000000000000000 0000000000000000 + check_signed $signn 64 FFFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF + test $(make-signed.tu $signn 1 -0) = 1 + test $(make-signed.tu $signn 4 -0) = 8 + + else + printf 'Missing test for LIBSYSCALLS_SIGN_%s in tests/signness\n' "$sign" >&2 + false + fi + test $(parse-signed.tu $signn 0 0) = inval + test $(parse-signed.tu $signn 32767 0) = inval + test $(make-signed.tu $signn 0 0) = inval + test $(make-signed.tu $signn 32767 0) = inval +done diff --git a/tests/syscall-errors b/tests/syscall-errors index 8d85ded..4608fe7 100644 --- a/tests/syscall-errors +++ b/tests/syscall-errors @@ -6,11 +6,11 @@ for os in $(getnamelist OS); do for arch in $(getnamelist ARCH); do archn=$(getnum ARCH $arch) get-syscall-errors.tu $osn $archn $os $arch > $a - grep -v '^[0-9]\{1,\} -' >/dev/null < $a - grep -v '^-' < $a > $b - grep '^\([0-9]\{1,\}\) \1 ' < $a | diff -u $a - if issupported $os $arch; then (! test "$(cat $a)" = x) + grep -v '^[0-9]\{1,\} -' >/dev/null < $a + grep -v '^-' < $a > $b + grep '^\([0-9]\{1,\}\) \1 ' < $a | diff -u $a - if test "$os" = LINUX; then signed=1 grep '^[0-9]\{1,\} [0-9]\{1,\} [A-Z0-9_]\{1,\}$' >/dev/null < $a diff --git a/tests/test-self-check b/tests/test-self-check index 8e42f18..c0e1d0d 100644 --- a/tests/test-self-check +++ b/tests/test-self-check @@ -9,6 +9,9 @@ stderr_printf () { test "$(stderr_printf 'hello\n')" = '' test "$(stderr stderr_printf 'hello\n' 2>&1)" = 'hello' +failing_function () { false; true; } # use of { } rather than ( ) is important +( ! failing_function ) + (! (false > $a) ) getname OS 0 @@ -39,6 +42,10 @@ printf 'a\n' > $a printf 'a\n' > $b diff -u $a $b +true & wait $! +( false & ! wait $! ) +await + for os in ${SUPPORTED_OSES}; do issupported $os for arch in $(env | sed -n 's/^SUPPORTED_'"$os"'_ARCHES=//p' | xargs printf '%s\n'); do diff --git a/testutil/get-integer-alignment.c b/testutil/get-integer-alignment.c index 6c91824..7d0fcc3 100644 --- a/testutil/get-integer-alignment.c +++ b/testutil/get-integer-alignment.c @@ -15,7 +15,7 @@ int main(int argc, char **argv) { int os, arch, width; - unsigned alignment = -1; + unsigned alignment = 0; enum libsyscalls_error err; if (argc != 6) { diff --git a/testutil/make-signed.c b/testutil/make-signed.c new file mode 100644 index 0000000..7cd0134 --- /dev/null +++ b/testutil/make-signed.c @@ -0,0 +1,56 @@ +/* See LICENSE file for copyright and license details. */ +#include "../libsyscalls.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* clang is just being silly */ +#endif + + +int +main(int argc, char **argv) +{ + int sign, neg = -1; + size_t bits; + const char *xval; + enum libsyscalls_error err; + unsigned long long int value; + char *end; + + if (argc != 4) { + usage: + fprintf(stderr, "usage error\n"); + return 1; + } + + sign = atoi(argv[1]); + bits = (unsigned long long int)atoll(argv[2]); + xval = argv[3]; + neg = *xval == '-'; + xval = &xval[neg]; + errno = 0; + value = strtoull(xval, &end, 16); + if (errno || *end) + goto usage; + + err = libsyscalls_make_signed_integer(value, neg, (enum libsyscalls_datatype_sign_representation)sign, bits, &value); + if (err == LIBSYSCALLS_E_INVAL) { + printf("inval\n"); + goto out; + } else if (err) { + libsyscalls_perror(NULL, err); + return 1; + } + printf("%0*llX\n", (int)strlen(xval), value); + +out: + if (fflush(stdout) || fclose(stdout)) { + perror(NULL); + return 1; + } + return 0; +} diff --git a/testutil/parse-signed.c b/testutil/parse-signed.c new file mode 100644 index 0000000..0fea405 --- /dev/null +++ b/testutil/parse-signed.c @@ -0,0 +1,56 @@ +/* See LICENSE file for copyright and license details. */ +#include "../libsyscalls.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* clang is just being silly */ +#endif + + +int +main(int argc, char **argv) +{ + int sign, neg = -1; + size_t bits; + const char *xval; + enum libsyscalls_error err; + unsigned long long int value; + char *end; + + if (argc != 4) { + usage: + fprintf(stderr, "usage error\n"); + return 1; + } + + sign = atoi(argv[1]); + bits = (unsigned long long int)atoll(argv[2]); + xval = argv[3]; + errno = 0; + value = strtoull(xval, &end, 16); + if (errno || *end) + goto usage; + + err = libsyscalls_parse_signed_integer(value, (enum libsyscalls_datatype_sign_representation)sign, bits, &value, &neg); + if (err == LIBSYSCALLS_E_INVAL) { + printf("inval\n"); + goto out; + } else if (err) { + libsyscalls_perror(NULL, err); + return 1; + } + if (neg != 0 && neg != 1) + abort(); + printf("%.*s%0*llX\n", neg, "-", (int)strlen(xval), value); + +out: + if (fflush(stdout) || fclose(stdout)) { + perror(NULL); + return 1; + } + return 0; +} diff --git a/testutil/section-value.c b/testutil/section-value.c new file mode 100644 index 0000000..b4c0304 --- /dev/null +++ b/testutil/section-value.c @@ -0,0 +1,52 @@ +/* See LICENSE file for copyright and license details. */ +#include "../libsyscalls.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* clang is just being silly */ +#endif + + +int +main(int argc, char **argv) +{ + enum libsyscalls_datatype_section section; + unsigned long long int value; + size_t bits; + char *end; + enum libsyscalls_error err; + + if (argc != 4) { + usage: + fprintf(stderr, "usage error\n"); + return 1; + } + + section = (enum libsyscalls_datatype_section)atoi(argv[1]); + errno = 0; + value = strtoull(argv[2], &end, 16); + if (errno || *end) + goto usage; + bits = (size_t)atol(argv[3]); + + err = libsyscalls_section_value(value, bits, section, &value); + if (err == LIBSYSCALLS_E_INVAL) { + printf("inval\n"); + goto out; + } else if (err) { + libsyscalls_perror(NULL, err); + return 1; + } + + printf("%llX\n", value); + +out: + if (fflush(stdout) || fclose(stdout)) { + perror(NULL); + return 1; + } + return 0; +} diff --git a/testutil/to-tracee-endian.c b/testutil/to-tracee-endian.c new file mode 100644 index 0000000..4346883 --- /dev/null +++ b/testutil/to-tracee-endian.c @@ -0,0 +1,111 @@ +/* See LICENSE file for copyright and license details. */ +#include "../libsyscalls.h" + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* clang is just being silly */ +#endif + + +static void +make_hex(char *out, const char *in, size_t n) +{ + for (; n--; in++) { + *out++ = "0123456789ABCDEF"[((unsigned)*in >> 4) & 0xFU]; + *out++ = "0123456789ABCDEF"[((unsigned)*in >> 0) & 0xFU]; + } + *out = '\0'; +} + + +int +main(int argc, char **argv) +{ + struct libsyscalls_datatype_description type; + char *data, *end, *text0, *text1; + size_t dataoff, i, datasize; + unsigned long long int value; + enum libsyscalls_error err; + + _Static_assert(CHAR_BIT, "We only support 8-bit char at the moment in testutil/to-tracee-endian.c"); + + if (argc < 5) { + usage: + fprintf(stderr, "usage error\n"); + return 1; + } + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +#endif + + errno = 0; + value = strtoull(argv[1], &end, 16); + if (errno || *end) + goto usage; + dataoff = (size_t)atol(argv[2]); + type.width_in_bits = (unsigned short int)atoi(argv[3]); + argv = &argv[4]; + i = 0; + for (; argv[i] && i < sizeof(type.byteorder) / sizeof(*type.byteorder); i++) + type.byteorder[i] = (unsigned)atoi(argv[i]); + if (argv[i]) + goto usage; + for (; i < sizeof(type.byteorder) / sizeof(*type.byteorder); i++) { + type.byteorder[i] = 0U; + type.byteorder[i] = ~type.byteorder[i]; + } + +#if defined(__clang__) +# pragma GCC diagnostic pop +#endif + + datasize = ((size_t)type.width_in_bits + dataoff + 7UL) / 8UL; + data = malloc(datasize); + text0 = malloc(datasize * 2UL + 1UL); + text1 = malloc(datasize * 2UL + 1UL); + + memset(data, 0, datasize); + err = libsyscalls_to_tracee_endian(value, &type, data, dataoff); + if (err == LIBSYSCALLS_E_INVAL) { + printf("inval\n"); + free(data); + goto out; + } else if (err) { + libsyscalls_perror(NULL, err); + return 1; + } + make_hex(text0, data, datasize); + + memset(data, ~0, datasize); + err = libsyscalls_to_tracee_endian(value, &type, data, dataoff); + if (err == LIBSYSCALLS_E_INVAL) { + printf("inval\n"); + free(data); + goto out; + } else if (err) { + libsyscalls_perror(NULL, err); + return 1; + } + make_hex(text1, data, datasize); + + free(data); + + printf("%s %s\n", text0, text1); + + free(text0); + free(text1); + +out: + if (fflush(stdout) || fclose(stdout)) { + perror(NULL); + return 1; + } + return 0; +} diff --git a/testutil/to-tracer-endian.c b/testutil/to-tracer-endian.c new file mode 100644 index 0000000..53cb380 --- /dev/null +++ b/testutil/to-tracer-endian.c @@ -0,0 +1,83 @@ +/* See LICENSE file for copyright and license details. */ +#include "../libsyscalls.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* clang is just being silly */ +#endif + + +int +main(int argc, char **argv) +{ + struct libsyscalls_datatype_description type; + const char *text; + char *data; + size_t dataoff, i; + unsigned long long int value; + unsigned char high, low; + enum libsyscalls_error err; + + _Static_assert(CHAR_BIT, "We only support 8-bit char at the moment in testutil/to-tracer-endian.c"); + + if (argc < 5) { + usage: + fprintf(stderr, "usage error\n"); + return 1; + } + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +#endif + + text = argv[1]; + dataoff = (size_t)atol(argv[2]); + type.width_in_bits = (unsigned short int)atoi(argv[3]); + argv = &argv[4]; + i = 0; + for (; argv[i] && i < sizeof(type.byteorder) / sizeof(*type.byteorder); i++) + type.byteorder[i] = (unsigned)atoi(argv[i]); + if (argv[i]) + goto usage; + for (; i < sizeof(type.byteorder) / sizeof(*type.byteorder); i++) { + type.byteorder[i] = 0U; + type.byteorder[i] = ~type.byteorder[i]; + } + +#if defined(__clang__) +# pragma GCC diagnostic pop +#endif + + if (strlen(text) & 1 || !strlen(text)) + goto usage; + data = malloc(strlen(text) / 2); + for (i = 0; *text; i++) { + high = (unsigned char)*text++; + low = (unsigned char)*text++; + high = (unsigned char)((high & 15U) + (high > '9' ? 9U : 0U)); + low = (unsigned char)((low & 15U) + (low > '9' ? 9U : 0U)); + data[i] = (char)((high << 4) | low); + } + + err = libsyscalls_to_tracer_endian(data, dataoff, &type, &value); + free(data); + if (err == LIBSYSCALLS_E_INVAL) { + printf("inval\n"); + goto out; + } else if (err) { + libsyscalls_perror(NULL, err); + return 1; + } + printf("%llX\n", value); + +out: + if (fflush(stdout) || fclose(stdout)) { + perror(NULL); + return 1; + } + return 0; +} diff --git a/testutil/unsection-value.c b/testutil/unsection-value.c new file mode 100644 index 0000000..9c85b3b --- /dev/null +++ b/testutil/unsection-value.c @@ -0,0 +1,52 @@ +/* See LICENSE file for copyright and license details. */ +#include "../libsyscalls.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* clang is just being silly */ +#endif + + +int +main(int argc, char **argv) +{ + enum libsyscalls_datatype_section section; + unsigned long long int value; + size_t bits; + char *end; + enum libsyscalls_error err; + + if (argc != 4) { + usage: + fprintf(stderr, "usage error\n"); + return 1; + } + + section = (enum libsyscalls_datatype_section)atoi(argv[1]); + errno = 0; + value = strtoull(argv[2], &end, 16); + if (errno || *end) + goto usage; + bits = (size_t)atol(argv[3]); + + err = libsyscalls_unsection_value(value, bits, section, &value); + if (err == LIBSYSCALLS_E_INVAL) { + printf("inval\n"); + goto out; + } else if (err) { + libsyscalls_perror(NULL, err); + return 1; + } + + printf("%llX\n", value); + +out: + if (fflush(stdout) || fclose(stdout)) { + perror(NULL); + return 1; + } + return 0; +} |