summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2023-12-16 12:40:10 +0100
committerMattias Andrée <maandree@kth.se>2023-12-16 12:40:10 +0100
commit683f205402a99cfc8cea46c83ce9b46a42616d42 (patch)
treef6ee1619454a6ec8b9e31770bbbc2abf36aae2fd
parentImprove portability (diff)
downloadlibsyscalls-683f205402a99cfc8cea46c83ce9b46a42616d42.tar.gz
libsyscalls-683f205402a99cfc8cea46c83ce9b46a42616d42.tar.bz2
libsyscalls-683f205402a99cfc8cea46c83ce9b46a42616d42.tar.xz
All kinds of stuff
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--Makefile63
-rw-r--r--TODO3
-rw-r--r--common.h111
-rw-r--r--config-figure-this-out-for-me.mk24
-rw-r--r--config.mk4
-rw-r--r--libsyscalls.h369
-rw-r--r--libsyscalls/internal-begin.h7
-rw-r--r--libsyscalls/internal-end.h5
-rw-r--r--libsyscalls_get_datatype_description.c80
-rw-r--r--libsyscalls_get_integer_alignment.c42
-rw-r--r--libsyscalls_get_struct_description.c656
-rw-r--r--libsyscalls_get_syscall.c9
-rw-r--r--libsyscalls_get_syscall_display_info.c169
-rw-r--r--libsyscalls_make_signed_integer.c56
-rw-r--r--libsyscalls_parse_signed_integer.c61
-rw-r--r--libsyscalls_perror.c2
-rw-r--r--libsyscalls_section_value.c74
-rw-r--r--libsyscalls_to_tracee_endian.c60
-rw-r--r--libsyscalls_to_tracer_endian.c59
-rw-r--r--libsyscalls_unsection_value.c76
-rw-r--r--linux/errors.c47
-rw-r--r--linux/linux-support.mk60
-rw-r--r--linux/signals.c47
-rw-r--r--linux/structs.c248
-rw-r--r--linux/structs.mk4
-rw-r--r--linux/symbols.c29
-rw-r--r--linux/syscall-table.c12
-rw-r--r--linux/syscall-table.mk14
-rw-r--r--linux/syscalls.h187
-rw-r--r--linux/syscalls.mk4
-rw-r--r--linux/types.c6
-rw-r--r--mk/generate.mk20
-rwxr-xr-xtest71
-rw-r--r--tests/default-integers8
-rw-r--r--tests/endians175
-rw-r--r--tests/errors1
-rw-r--r--tests/fixed-array-types9
-rw-r--r--tests/load-archinfo2
-rw-r--r--tests/load-functions24
-rw-r--r--tests/preamble41
-rw-r--r--tests/sections90
-rw-r--r--tests/signals6
-rw-r--r--tests/signness296
-rw-r--r--tests/syscall-errors6
-rw-r--r--tests/test-self-check7
-rw-r--r--testutil/get-integer-alignment.c2
-rw-r--r--testutil/make-signed.c56
-rw-r--r--testutil/parse-signed.c56
-rw-r--r--testutil/section-value.c52
-rw-r--r--testutil/to-tracee-endian.c111
-rw-r--r--testutil/to-tracer-endian.c83
-rw-r--r--testutil/unsection-value.c52
52 files changed, 3344 insertions, 412 deletions
diff --git a/Makefile b/Makefile
index 6d520ca..dbe8bcc 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/TODO b/TODO
index 0dffc6b..32b8326 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/common.h b/common.h
index b9b7174..446f438 100644
--- a/common.h
+++ b/common.h
@@ -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'; \
diff --git a/config.mk b/config.mk
index c4d7eb3..1cc7dcb 100644
--- a/config.mk
+++ b/config.mk
@@ -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'; \
diff --git a/test b/test
index 185d915..4af52c8 100755
--- a/test
+++ b/test
@@ -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;
+}