From 2e7b4df9f7dfd6a4a6796cd2fcee010ea78427ea Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 17 Dec 2023 13:23:51 +0100 Subject: Miscellaneous improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 2 + common.h | 102 ++-- config.mk | 13 + libsyscalls.h | 826 +++++++++++++++++++++------------ libsyscalls_find_named_number.c | 141 ++++++ libsyscalls_get_datatype_description.c | 36 +- libsyscalls_get_integer_alignment.c | 69 +-- libsyscalls_get_struct_description.c | 69 ++- libsyscalls_get_syscall_display_info.c | 152 +----- libsyscalls_get_syscall_range.c | 3 +- libsyscalls_parse_signed_integer.c | 3 +- libsyscalls_section_value.c | 12 +- libsyscalls_unsection_value.c | 14 +- linux/symbols.c | 2 +- test | 3 + tests/archinfo | 17 +- tests/error-search | 13 + tests/load-archinfo | 7 +- tests/run | 4 + tests/signal-search | 13 + testutil/get-datatype-description.c | 2 +- testutil/get-integer-alignment.c | 2 +- testutil/get-signals.c | 2 +- testutil/get-syscall-errors.c | 2 +- testutil/get-syscall-range.c | 2 +- testutil/is-datatype-struct.c | 2 +- testutil/make-signed.c | 1 + testutil/parse-signed.c | 1 + testutil/section-value.c | 1 + testutil/test-search.c | 114 +++++ testutil/to-tracee-endian.c | 8 +- testutil/to-tracer-endian.c | 4 + testutil/unsection-value.c | 1 + 33 files changed, 1027 insertions(+), 616 deletions(-) create mode 100644 libsyscalls_find_named_number.c create mode 100644 tests/error-search create mode 100644 tests/run create mode 100644 tests/signal-search create mode 100644 testutil/test-search.c diff --git a/Makefile b/Makefile index dbe8bcc..7916431 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,7 @@ OBJ =\ libsyscalls_get_syscall_display_info.o\ libsyscalls_get_syscall_errors.o\ libsyscalls_get_syscall_range.o\ + libsyscalls_find_named_number.o\ libsyscalls_make_signed_integer.o\ libsyscalls_parse_signed_integer.o\ libsyscalls_perror.o\ @@ -151,6 +152,7 @@ TESTUTILS =\ testutil/section-value.tu\ testutil/strerror-all.tu\ testutil/strerror-bad.tu\ + testutil/test-search.tu\ testutil/to-tracee-endian.tu\ testutil/to-tracer-endian.tu\ testutil/unsection-value.tu diff --git a/common.h b/common.h index e2a5422..8b2ff2b 100644 --- a/common.h +++ b/common.h @@ -57,12 +57,16 @@ #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 MISALIGNMENT(ADDR, ALIGN) ((ADDR) & ((uintptr_t)(ALIGN) - 1U)) +#define ALIGNMENT_ADJUSTMENT(ADDR, ALIGN) MISALIGNMENT((ALIGN) - MISALIGNMENT((ADDR), (ALIGN)), (ALIGN)) +#define ALIGN_BUF(BUF, ALIGN) (&(BUF)[(size_t)ALIGNMENT_ADJUSTMENT((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)) +#define POST_HIGHEST_OF_CONSECUTIVELY_BITS(X) ((X) + LOWEST_BIT((X))) +#define IS_NOT_2POW(X) ((X) & ((X) - 1)) +#define SET_MASK_TRAIL(X) ((X) | ((X) - 1U)) +#define USAT_MINUS(A, B) ((A) < (B) ? 0 : (A) - (B)) struct libsyscalls_symbol_printer_data { @@ -76,54 +80,54 @@ enum endian { Little }; - -/* Don't forget to update SUPPORTED_ARCHES in Makefile */ -#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\ + /* [------ size ------] [align] */ +#define LIST_ARCH_SPECS(X, D) /* byte intptr size_t intmax endian sign */\ + X(LIBSYSCALLS_ARCH_ALPHA_LE, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ALPHA_BE, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_AMD64, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_AMD64_X32, 8, 32, 32, 64, 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_ARM_OABI_LE, 8, TODO, TODO, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ARM_OABI_BE, 8, TODO, TODO, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ARM_EABI_LE, 8, TODO, TODO, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ARM_EABI_BE, 8, TODO, TODO, 64, 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) + X(LIBSYSCALLS_ARCH_IA64_LE, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_IA64_BE, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_IA64_P32_LE, 8, 32, 32, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_IA64_P32_BE, 8, 32, 32, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_M68K, 8, 32, 32, 16, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MICROBLAZE_32_LE, 8, 32, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MICROBLAZE_32_BE, 8, 32, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MICROBLAZE_64_LE, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MICROBLAZE_64_BE, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_O32_LE, 8, 32, 32, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_O32_BE, 8, 32, 32, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_N32_LE, 8, 32, 32, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_N32_BE, 8, 32, 32, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_N64_LE, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_MIPS_N64_BE, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_PARISC_32, 8, 32, 32, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_PARISC_64, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_32_LE, 8, 32, 32, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_32_BE, 8, 32, 32, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_64_LE, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_64_BE, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_NOSPU_LE, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_NOSPU_BE, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_SPU_LE, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_POWERPC_SPU_BE, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_S390_32, 8, 32, 32, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_S390_64, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SH_LE, 8, 32, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SH_BE, 8, 32, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SPARC_32, 8, 32, 32, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SPARC_64_LE, 8, 64, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_SPARC_64_BE, 8, 64, 64, 64, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_I386, 8, 32, 32, 32, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_XTENSA_LE, 8, 32, 32, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_XTENSA_BE, 8, 32, 32, 64, Big, TWOS_COMPLEMENT) + /* Don't forget to update SUPPORTED_ARCHES in Makefile */ #include "generated/oses.h" diff --git a/config.mk b/config.mk index 1cc7dcb..e0b7aa7 100644 --- a/config.mk +++ b/config.mk @@ -23,6 +23,19 @@ LDFLAGS = # 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. +# Additionally, you can add -DUSE_INTERPOLATION_SEARCH to CPPFLAGS +# if you want the library to use interpolation search instead of +# binary search, this is probably a bad idea on platforms that do +# not support division natively, even on amd64, it does not seem to +# make any difference at the moment. If you add -DUSE_INTERPOLATION_SEARCH, +# you may also add `-DINTERPOLATION_SEARCH_FLOAT=long double` (default), +# `-DINTERPOLATION_SEARCH_FLOAT=double` or `-DINTERPOLATION_SEARCH_FLOAT=float` +# to specify which floating point type interpolation search should use +# if it cannot used integers; which option is best depends on the +# platform, as some platforms can work natively with any of the types +# and those `float` is most performant, and other platforms (such as +# i386) can only work natively with a specific type (`long double` in +# the case of i386) and thus performs best with that type. DOWNLOAD = curl -- diff --git a/libsyscalls.h b/libsyscalls.h index f2d5fdd..df4de69 100644 --- a/libsyscalls.h +++ b/libsyscalls.h @@ -16,7 +16,7 @@ * the enum value name of the error (identifier), * and the description of the error (string literal) * @param D:code Macro that expands between each expansion of X - * + * * The primary purpose of the existance of this macro * is to ease implementation of the library; it will * probably not disappear (no promises) @@ -119,28 +119,34 @@ enum libsyscalls_datatype { /* You can use these macros classify and convert data types */ #define LIBSYSCALLS_TYPEBITSMASK 0xF000 #define LIBSYSCALLS_TYPEBITS_SCALAR 0x0000 /* predefined total width, even if aggregate */ -#define LIBSYSCALLS_TYPEBITS_ARRAY 0x1000 /* count is stored in next parameter, and is updated with fill - * or returned if no outputable to the next parameter */ -#define LIBSYSCALLS_TYPEBITS_ARRAY_UNKNOWN_FILL 0x2000 /* count is stored in next parameter, fill is in no way returned, - * this chould either be because the array is always (unless an - * error is returned) entirely filled or because the end is - * infered from the contents (e.g. null byte termination) */ +#define LIBSYSCALLS_TYPEBITS_ARRAY 0x1000 /* count is stored in next parameter, and is + * updated with fill or returned if no outputable + * to the next parameter */ +#define LIBSYSCALLS_TYPEBITS_ARRAY_UNKNOWN_FILL 0x2000 /* count is stored in next parameter, fill is + * in no way returned, this chould either be + * because the array is always (unless an error + * is returned) entirely filled or because the + * end is inferred from the contents (e.g. null + * byte termination) */ #define LIBSYSCALLS_LIST_SPECIAL_TYPES(X, SUFFIX, D, FIRST)\ - /* the type used in the system call has not yet be added recorded in the library */\ + /* the type used in the system call has not yet be + * added recorded in the library */\ X(LIBSYSCALLS_TYPE_UNKNOWN ## SUFFIX, FIRST, "(unknown type)") D\ /* the type depends on the system call input or output */\ X(LIBSYSCALLS_TYPE_DYNAMIC ## SUFFIX,, "(undetermined type)") D\ - /* the system call should never returned to the calling process (return to tracer is usually expected) */\ + /* the system call should never returned to the calling + * process (return to tracer is usually expected) */\ X(LIBSYSCALLS_TYPE_NO_RETURN ## SUFFIX,, "no_return") D\ - /* either used as return type, to skip a register in the parameters - * (do not dismiss this, on some architectures a system call - * may need padding with dummy arguments to align latter - * register pairs; an application printing the system call - * must choose between omitting, printing the argument, or - * indicating that there is a dummy parameter (of course - * the latter two can be combined)), or to add padding - * (or reserved space for future expansion) to a struct */\ + /* either used as return type, to skip a register in the + * parameters (do not dismiss this, on some architectures + * a system call may need padding with dummy arguments to + * align latter register pairs; an application printing + * the system call must choose between omitting, printing + * the argument, or indicating that there is a dummy + * parameter (of course the latter two can be combined)), + * or to add padding (or reserved space for future + * expansion) to a struct */\ X(LIBSYSCALLS_TYPE_VOID ## SUFFIX,, "void") #define LIBSYSCALLS_LIST_SPLIT_PRIMITIVES(X, SUFFIX, D, FIRST)\ @@ -332,17 +338,17 @@ enum libsyscalls_syscall_category { */ LIBSYSCALLS_CAT_NOT_IMPLEMENTED, - LIBSYSCALLS_CAT_NETWORK_ENABLED_IPC, /**< See enum libsyscalls_network_enabled_ipc_syscall_subcategory */ - LIBSYSCALLS_CAT_IPC, /**< See enum libsyscalls_ipc_syscall_subcategory */ - LIBSYSCALLS_CAT_FILESYSTEM, /**< See enum libsyscalls_filesystem_syscall_subcategory */ - LIBSYSCALLS_CAT_FILE_DESCRIPTORS, /**< See enum libsyscalls_file_descriptors_syscall_subcategory */ - LIBSYSCALLS_CAT_PROCESSES, /**< See enum libsyscalls_processes_syscall_subcategory */ - LIBSYSCALLS_CAT_LOGGING, /**< See enum libsyscalls_logging_syscall_subcategory */ - LIBSYSCALLS_CAT_TIME, /**< See enum libsyscalls_time_syscall_subcategory */ - LIBSYSCALLS_CAT_SIGNALS, /**< See enum libsyscalls_singals_syscall_subcategory */ - LIBSYSCALLS_CAT_MEMORY, /**< See enum libsyscalls_memory_syscall_subcategory */ - LIBSYSCALLS_CAT_SYSTEM, /**< See enum libsyscalls_system_syscall_subcategory */ - LIBSYSCALLS_CAT_SCHEDULING /**< See enum libsyscalls_scheduling_syscall_subcategory */ + LIBSYSCALLS_CAT_NETWORK_ENABLED_IPC, /**< See enum libsyscalls_network_enabled_ipc_syscall_subcategory */ + LIBSYSCALLS_CAT_IPC, /**< See enum libsyscalls_ipc_syscall_subcategory */ + LIBSYSCALLS_CAT_FILESYSTEM, /**< See enum libsyscalls_filesystem_syscall_subcategory */ + LIBSYSCALLS_CAT_FILE_DESCRIPTORS, /**< See enum libsyscalls_file_descriptors_syscall_subcategory */ + LIBSYSCALLS_CAT_PROCESSES, /**< See enum libsyscalls_processes_syscall_subcategory */ + LIBSYSCALLS_CAT_LOGGING, /**< See enum libsyscalls_logging_syscall_subcategory */ + LIBSYSCALLS_CAT_TIME, /**< See enum libsyscalls_time_syscall_subcategory */ + LIBSYSCALLS_CAT_SIGNALS, /**< See enum libsyscalls_singals_syscall_subcategory */ + LIBSYSCALLS_CAT_MEMORY, /**< See enum libsyscalls_memory_syscall_subcategory */ + LIBSYSCALLS_CAT_SYSTEM, /**< See enum libsyscalls_system_syscall_subcategory */ + LIBSYSCALLS_CAT_SCHEDULING /**< See enum libsyscalls_scheduling_syscall_subcategory */ }; /** @@ -1473,17 +1479,17 @@ enum libsyscalls_scheduling_syscall_subcategory { * LIBSYSCALLS_CAT_SUPPORT_PENDING or LIBSYSCALLS_CAT_NOT_IMPLEMENTED */ union libsyscalls_syscall_subcategory { - enum_libsyscalls_network_enabled_ipc_syscall_subcategory network_enabled_ipc; /**< Use for LIBSYSCALLS_CAT_NETWORK_ENABLED_IPC */ - enum_libsyscalls_ipc_syscall_subcategory ipc; /**< Use for LIBSYSCALLS_CAT_IPC */ - enum_libsyscalls_filesystem_syscall_subcategory filesystem; /**< Use for LIBSYSCALLS_CAT_FILESYSTEM */ - enum_libsyscalls_file_descriptors_syscall_subcategory file_descriptors; /**< Use for LIBSYSCALLS_CAT_FILE_DESCRIPTORS */ - enum_libsyscalls_processes_syscall_subcategory processes; /**< Use for LIBSYSCALLS_CAT_PROCESSES */ - enum_libsyscalls_logging_syscall_subcategory logging; /**< Use for LIBSYSCALLS_CAT_LOGGING */ - enum_libsyscalls_time_syscall_subcategory time; /**< Use for LIBSYSCALLS_CAT_TIME */ - enum_libsyscalls_signals_syscall_subcategory signals; /**< Use for LIBSYSCALLS_CAT_SIGNALS */ - enum_libsyscalls_memory_syscall_subcategory memory; /**< Use for LIBSYSCALLS_CAT_MEMORY */ - enum_libsyscalls_system_syscall_subcategory system; /**< Use for LIBSYSCALLS_CAT_SYSTEM */ - enum_libsyscalls_scheduling_syscall_subcategory scheduling; /**< Use for LIBSYSCALLS_CAT_SCHEDULING */ + enum_libsyscalls_network_enabled_ipc_syscall_subcategory network_enabled_ipc; /**< If LIBSYSCALLS_CAT_NETWORK_ENABLED_IPC */ + enum_libsyscalls_ipc_syscall_subcategory ipc; /**< If LIBSYSCALLS_CAT_IPC */ + enum_libsyscalls_filesystem_syscall_subcategory filesystem; /**< If LIBSYSCALLS_CAT_FILESYSTEM */ + enum_libsyscalls_file_descriptors_syscall_subcategory file_descriptors; /**< If LIBSYSCALLS_CAT_FILE_DESCRIPTORS */ + enum_libsyscalls_processes_syscall_subcategory processes; /**< If LIBSYSCALLS_CAT_PROCESSES */ + enum_libsyscalls_logging_syscall_subcategory logging; /**< If LIBSYSCALLS_CAT_LOGGING */ + enum_libsyscalls_time_syscall_subcategory time; /**< If LIBSYSCALLS_CAT_TIME */ + enum_libsyscalls_signals_syscall_subcategory signals; /**< If LIBSYSCALLS_CAT_SIGNALS */ + enum_libsyscalls_memory_syscall_subcategory memory; /**< If LIBSYSCALLS_CAT_MEMORY */ + enum_libsyscalls_system_syscall_subcategory system; /**< If LIBSYSCALLS_CAT_SYSTEM */ + enum_libsyscalls_scheduling_syscall_subcategory scheduling; /**< If LIBSYSCALLS_CAT_SCHEDULING */ }; /** @@ -1567,7 +1573,8 @@ struct libsyscalls_syscall_abi { */ unsigned short int queer : 1; - short int : LIBSYSCALLS_PAD_(sizeof(short int)/sizeof(char)*CHAR_BIT, 4*16 + 2*6 + 3*1); + short int : LIBSYSCALLS_PAD_(sizeof(short int)/sizeof(char)*CHAR_BIT, + 4*16 + 2*6 + 3*1); /** * This is used internally by `libsyscalls_get_syscall_display_info` @@ -1714,7 +1721,9 @@ struct libsyscalls_named_number { * none was found. The returned string may be stored * in `data` and those override at the next call. */ -typedef const char *libsyscalls_symbol_printer_function(LIBSYSCALLS_SYMBOL_PRINTER_DATA *, unsigned long long int *, char *); +typedef const char *libsyscalls_symbol_printer_function(LIBSYSCALLS_SYMBOL_PRINTER_DATA *data, + unsigned long long int *valuep, + char *fallback_out); /** * Information about a system call parameter or return value @@ -1739,7 +1748,8 @@ struct libsyscalls_syscall_type_info { */ enum_libsyscalls_datatype type; - char padding__[LIBSYSCALLS_PAD_(sizeof(void *)/sizeof(char), sizeof(enum_libsyscalls_datatype)/sizeof(char) + 1)]; + char padding__[LIBSYSCALLS_PAD_(sizeof(void *)/sizeof(char), + sizeof(enum_libsyscalls_datatype)/sizeof(char) + 1)]; unsigned char : CHAR_BIT - 1; /** @@ -1792,8 +1802,8 @@ struct libsyscalls_syscall_display_info { */ enum libsyscalls_datatype_sign_representation { /** - * The data type was LIBSYSCALLS_TYPE_UNKNOWN or - * LIBSYSCALLS_TYPE_DYNAMIC + * The data type was LIBSYSCALLS_TYPE_UNKNOWN + * or LIBSYSCALLS_TYPE_DYNAMIC */ LIBSYSCALLS_SIGN_UNDETERMINED, @@ -1844,43 +1854,45 @@ enum libsyscalls_datatype_annotation { LIBSYSCALLS_ANNOTATION_NONE, /** - * The value represents an operating system signal (e.g. SIGKILL) + * The value represents an operating system signal + * (e.g. SIGKILL) * - * This affords the application the opportunity to print - * more detail information about a signal (such as when - * it is used, whether it is a realtime signal, default - * action, whether it can be caught, and what its normal - * usage is) + * This affords the application the opportunity + * to print more detail information about a signal + * (such as when it is used, whether it is a + * realtime signal, default action, whether it + * can be caught, and what its normal usage is) */ LIBSYSCALLS_ANNOTATION_SIGNAL, /** * The value represents a file descriptor * - * This affords the application the opportunity to print - * file information (such as file name, address, file type, - * and offset) + * This affords the application the opportunity + * toprint file information (such as file name, + * address, file type, and offset) */ LIBSYSCALLS_ANNOTATION_FD, /** - * The value represents a file descriptor or a special value - * for a known file such as AT_FDCWD + * The value represents a file descriptor or a + * special value for a known file such as AT_FDCWD * - * This affords the application the opportunity to print - * file information (such as file name, address, file type, - * and offset) + * This affords the application the opportunity + * to print file information (such as file name, + * address, file type, and offset) */ LIBSYSCALLS_ANNOTATION_ATFD }; /** - * Register-split/struct field-split information for a data type + * Register-split/struct field-split information + * for a data type */ enum libsyscalls_datatype_section { /** - * The data type was LIBSYSCALLS_TYPE_UNKNOWN or - * LIBSYSCALLS_TYPE_DYNAMIC + * The data type was LIBSYSCALLS_TYPE_UNKNOWN + * or LIBSYSCALLS_TYPE_DYNAMIC */ LIBSYSCALLS_SECTION_UNDETERMINED, @@ -1891,12 +1903,15 @@ enum libsyscalls_datatype_section { */ LIBSYSCALLS_SECTION_WHOLE, - /* + /** * This whether a data type represents a half section * of larger data type * - * @param S:enum libsyscalls_datatype_section The data type section information - * @return :int Whether the larger that type was split into two halves + * @param S:enum libsyscalls_datatype_section + * The data type section information + * + * @return :int Whether the larger that type was + * split into two halves */ #define LIBSYSCALLS_IS_SECTION_HALF(S)\ (((S) >= LIBSYSCALLS_SECTION_UPPER_HALF) &&\ @@ -1998,12 +2013,15 @@ enum libsyscalls_datatype_section { */ LIBSYSCALLS_SECTION_ODD_BYTES_AS_HALF, - /* + /** * This whether a data type represents a quarter section * of larger data type * - * @param S:enum libsyscalls_datatype_section The data type section information - * @return :int Whether the larger that type was split into four quarters + * @param S:enum libsyscalls_datatype_section + * The data type section information + * + * @return :int Whether the larger that type was + * split into four quarters */ #define LIBSYSCALLS_IS_SECTION_QUARTER(S)\ (((S) >= LIBSYSCALLS_SECTION_UPPER_QUARTER) &&\ @@ -2061,18 +2079,73 @@ enum libsyscalls_datatype_section { */ LIBSYSCALLS_SECTION_LOWER_QUARTER - /* - * Get the number of registers/fields the data type was split into + /** + * Get the number of registers/fields the data type + * was split into + * + * @param S:enum libsyscalls_datatype_section + * The data type section information * - * @param S:enum libsyscalls_datatype_section The data type section information - * @return :unsigned int The number registers/fields the data type was split into; - * invalid if `S` is LIBSYSCALLS_SECTION_UNDETERMINED + * @return :unsigned int + * The number registers/fields the data + * type was split into; invalid if `S` + * is LIBSYSCALLS_SECTION_UNDETERMINED */ #define LIBSYSCALLS_GET_SECTION_FRACTION(S)\ (LIBSYSCALLS_IS_SECTION_HALF(S) ? 2U :\ LIBSYSCALLS_IS_SECTION_QUARTER(S) ? 4U : 1U) }; + +/** + * Macro for enumerating type-split sections + * + * The numbers are stored in `enum libsyscalls_datatype_section` + * + * @param X:macro(NAME, ...) Macro that expands, will a number of arguments: + * 1) The name of the enum value + * 2) 1 if the section is both compatible with 16-bit + * integers and is the first section with its + * pattern of covered bits for 16-bit integers, + * 0 otherwise + * 3) Mask of bits the section covers for a 16-bit integer + * 4) 1 if the section is both compatible with 32-bit + * integers and is the first section with its + * pattern of covered bits for 32-bit integers, + * 0 otherwise + * 5) Mask of bits the section covers for a 32-bit integer + * 6) 1 if the section is both compatible with 64-bit + * integers and is the first section with its + * pattern of covered bits for 64-bit integers, + * 0 otherwise + * 7) Mask of bits the section covers for a 64-bit integer + * Arguments 3, 5, and 7 are `0` when the section is not + * compatible with the data type and otherwise a `0x` + * prefixed uppercase hexadecimal number without any type + * suffix. + * Addition arguments may be added in the future. + * @param D:code Macro that expands between each expansion of X + * + * The primary purpose of the existance of this macro + * is to ease implementation of the library; it will + * probably not disappear (no promises) + */ +#define LIBSYSCALLS_LIST_SECTIONS(X, D)\ + X(LIBSYSCALLS_SECTION_WHOLE, 1, 0xFFFF, 1, 0xFFFFFFFF, 1, 0xFFFFFFFFFFFFFFFF) D\ + X(LIBSYSCALLS_SECTION_UPPER_HALF, 1, 0xFF00, 1, 0xFFFF0000, 1, 0xFFFFFFFF00000000) D\ + X(LIBSYSCALLS_SECTION_LOWER_HALF, 1, 0x00FF, 1, 0x0000FFFF, 1, 0x00000000FFFFFFFF) D\ + X(LIBSYSCALLS_SECTION_INNER_HALF, 0, 0, 1, 0x00FFFF00, 1, 0x0000FFFFFFFF0000) D\ + X(LIBSYSCALLS_SECTION_OUTER_HALF, 0, 0, 1, 0xFF0000FF, 1, 0xFFFF00000000FFFF) D\ + X(LIBSYSCALLS_SECTION_EVEN_QUARTERS_AS_HALF, 0, 0, 1, 0x00FF00FF, 1, 0x0000FFFF0000FFFF) D\ + X(LIBSYSCALLS_SECTION_ODD_QUARTERS_AS_HALF, 0, 0, 1, 0xFF00FF00, 1, 0xFFFF0000FFFF0000) D\ + X(LIBSYSCALLS_SECTION_EVEN_BYTES_AS_HALF, 0, 0, 0, 0x00FF00FF, 1, 0x00FF00FF00FF00FF) D\ + X(LIBSYSCALLS_SECTION_ODD_BYTES_AS_HALF, 0, 0, 0, 0xFF00FF00, 1, 0xFF00FF00FF00FF00) D\ + X(LIBSYSCALLS_SECTION_UPPER_QUARTER, 0, 0, 1, 0xFF000000, 1, 0xFFFF000000000000) D\ + X(LIBSYSCALLS_SECTION_UPPER_MID_QUARTER, 0, 0, 1, 0x00FF0000, 1, 0x0000FFFF00000000) D\ + X(LIBSYSCALLS_SECTION_LOWER_MID_QUARTER, 0, 0, 1, 0x0000FF00, 1, 0x00000000FFFF0000) D\ + X(LIBSYSCALLS_SECTION_LOWER_QUARTER, 0, 0, 1, 0x000000FF, 1, 0x000000000000FFFF) + + /** * Information on how an instance of data type is to be parsed * @@ -2176,7 +2249,8 @@ struct libsyscalls_datatype_description { */ unsigned min_is_minus_max : 1; - int padding__ : LIBSYSCALLS_PAD_(sizeof(int)/sizeof(char)*CHAR_BIT, 2*5 + 4*1); + int padding__ : LIBSYSCALLS_PAD_(sizeof(int)/sizeof(char)*CHAR_BIT, + 2*5 + 4*1); /** * Only used if .is_signed is 1 @@ -2231,20 +2305,25 @@ struct libsyscalls_datatype_description { unsigned char byteorder[32]; /** - * Test whether a value in `struct libsyscalls_datatype_description.byteorder` - * marks the end of the byteorder's shift value (testing - * that the value is ~0). Using this macro helps avoiding - * bugs caused by integer type promotion. + * Test whether a value in `struct + * libsyscalls_datatype_description.byteorder` + * marks the end of the byteorder's shift value + * (testing that the value is ~0). Using this + * macro helps avoiding bugs caused by integer + * type promotion. * - * @param SHIFT The value to test `struct libsyscalls_datatype_description.byteorder` + * @param SHIFT The value to test `struct + * libsyscalls_datatype_description.byteorder` * @return :int Whether the value is ~0 */ #ifdef UINTMAX_C # define LIBSYSCALLS_IS_BYTEORDER_END(SHIFT)\ - (!~((SHIFT) | ~LIBSYSCALLS_FIELD_MASK_(UINTMAX_C(1), struct libsyscalls_datatype_description, byteorder[0]))) + (!~((SHIFT) | ~LIBSYSCALLS_FIELD_MASK_(UINTMAX_C(1),\ + struct libsyscalls_datatype_description, byteorder[0]))) #else # define LIBSYSCALLS_IS_BYTEORDER_END(SHIFT)\ - (!~((SHIFT) | ~LIBSYSCALLS_FIELD_MASK_(1ULL, struct libsyscalls_datatype_description, byteorder[0]))) + (!~((SHIFT) | ~LIBSYSCALLS_FIELD_MASK_(1ULL,\ + struct libsyscalls_datatype_description, byteorder[0]))) #endif /** @@ -2252,8 +2331,8 @@ struct libsyscalls_datatype_description { * 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])) + ((size_t)(INDEX) == sizeof((DESC)->byteorder) / sizeof(*(DESC)->byteorder) || \ + LIBSYSCALLS_IS_BYTEORDER_END((DESC)->byteorder[INDEX])) }; /** @@ -2506,7 +2585,8 @@ struct libsyscalls_structure_description { # if !LIBSYSCALLS_CAN_ALIGN_(7, 16, CHAR_BIT) # error Sorry, we require that the a byte is no longer than (7*16) bits while evenly dividing (7*16) bits # endif - char padding__[LIBSYSCALLS_PAD_(sizeof(void *)/sizeof(char), (7*16)/CHAR_BIT)]; + char padding__[LIBSYSCALLS_PAD_(sizeof(void *)/sizeof(char), + (7*16)/CHAR_BIT)]; #endif /** @@ -2520,11 +2600,13 @@ struct libsyscalls_structure_description { * Return a description of a libsyscalls error * * @param error The libsyscalls error - * @return Description of the error, the first character will be in uppercase + * @return Description of the error, the first + * character will be in uppercase */ LIBSYSCALLS_GCC_ATTRIBUTES_(__const__, __returns_nonnull__, __warn_unused_result__) const char * -libsyscalls_strerror(enum libsyscalls_error); +libsyscalls_strerror(enum libsyscalls_error error); + /** * Print a line with a description of a @@ -2535,21 +2617,25 @@ libsyscalls_strerror(enum libsyscalls_error); * @param error The libsyscalls error */ void -libsyscalls_perror(const char *, enum libsyscalls_error); +libsyscalls_perror(const char *prefix, enum libsyscalls_error err); + /** * Get the valid range system call numbers * - * @param os The operating system the range shall valid for - * @param arch The architecture the range shall valid for - * @param min_out Output parameter for the lowest used system call number (may be NULL) - * @param max_out Output parameter for the highest used system call number (may be NULL) - * @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`) + * @param os The operating system the range shall valid for + * @param arch The architecture the range shall valid for + * @param min_out Output parameter for the lowest used + * system call number (may be NULL) + * @param max_out Output parameter for the highest used + * system call number (may be NULL) + * + * @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`) * * This function always fails if the selected combination * of operating system (`os`) and architecture (`arch`) is @@ -2559,36 +2645,45 @@ 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__, __access__(__write_only__, 3), __access__(__write_only__, 4)) +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 *); +libsyscalls_get_syscall_range(enum libsyscalls_os os, enum libsyscalls_arch arch, + long long int *min_out, long long int *max_out); + /** * Get the description of a system call * - * @param os The operating system the range shall valid for - * @param arch The architecture the range shall valid for - * @param syscallnr The system call's number - * @param syscall_out Output parameter for the system call description - * (the argument may be NULL, *syscall_out will - * never be set to NULL) - * @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_NOSUCHSYSCALL - `syscallnr` does not correspond to a known - * system call for the selected architecture (`arch`) - * on the selected operating system (`os`) + * @param os The operating system the range shall valid for + * @param arch The architecture the range shall valid for + * @param syscall_nr The system call's number + * @param syscall_out Output parameter for the system call description + * (the argument may be NULL, *syscall_out will + * never be set to NULL) + * + * @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_NOSUCHSYSCALL - `syscall_nr` does not correspond to a known + * system call for the selected architecture (`arch`) + * on the selected operating system (`os`) * * This function always fails if the selected combination * of operating system (`os`) and architecture (`arch`) is * unsupported */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 4)) +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 **); +libsyscalls_get_syscall(enum libsyscalls_os os, enum libsyscalls_arch arch, + long long int syscall_nr, + const struct libsyscalls_syscall **syscall_out); + /** * Get the system call errors defined by an operating system @@ -2599,27 +2694,36 @@ libsyscalls_get_syscall(enum libsyscalls_os, enum libsyscalls_arch, long long in * The returned listing will be sorted by the error numbers * in ascending order * - * @param os The operating system whose errors shall be returned - * @param arch The architecture the error numbers shall be valid for - * @param errors_out Output parameter for the error list (may be NULL, never filled with NULL) - * @param num_errors_out Output parameter for the number of errors returned in `*errors_out` (may be NULL) - * (if `errors_out` is NULL, the number that would be returned is stored) - * @param are_signed_out Output parameter for whether the error numbers are signed (may be NULL) - * @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_NOERRORS - The operating system does not use named error numbers + * @param os The operating system whose errors shall be returned + * @param arch The architecture the error numbers shall be valid for + * @param errors_out Output parameter for the error list + * (may be NULL, never filled with NULL) + * @param num_errors_out Output parameter for the number of errors returned + * in `*errors_out` (may be NULL) (if `errors_out` is NULL, + * the number that would be returned is stored) + * @param are_signed_out Output parameter for whether the error numbers are + * signed (may be NULL) + * + * @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_NOERRORS - The operating system does not use named error numbers * * This function will always fail if the operating system (`os`) * 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), __access__(__write_only__, 5)) +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 3), + __access__(__write_only__, 4), + __access__(__write_only__, 5)) enum libsyscalls_error -libsyscalls_get_syscall_errors(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_named_number **, size_t *, int *); +libsyscalls_get_syscall_errors(enum libsyscalls_os os, enum libsyscalls_arch arch, + const struct libsyscalls_named_number **errors_out, + size_t *num_errors_out, int *are_signed_out); + /** * Get the system signals defined by an operating system @@ -2630,58 +2734,140 @@ libsyscalls_get_syscall_errors(enum libsyscalls_os, enum libsyscalls_arch, const * The returned listing will be sorted by the signal * numbers in ascending order * - * @param os The operating system whose errors shall be returned - * @param arch The architecture the error numbers shall be valid for - * @param signals_out Output parameter for the signal list (may be NULL, never filled with NULL) - * @param num_signals_out Output parameter for the number of signals returned in `*signals_out` (may be NULL) - * (if `signals_out` is NULL, the number that would be returned is stored) - * @param are_signed_ out Output parameter for whether the signal numbers are signed (may be NULL) - * @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_NOSIGNALS - The operating system does not use named signal numbers + * @param os The operating system whose errors shall be returned + * @param arch The architecture the error numbers shall be valid for + * @param signals_out Output parameter for the signal list + * (may be NULL, never filled with NULL) + * @param num_signals_out Output parameter for the number of signals returned + * in `*signals_out` (may be NULL) (if `signals_out` is + * NULL, the number that would be returned is stored) + * @param are_signed_out Output parameter for whether the signal numbers are + * signed (may be NULL) + * + * @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_NOSIGNALS - The operating system does not use named signal numbers * * This function will always fail if the operating system (`os`) * 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), __access__(__write_only__, 5)) +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 3), + __access__(__write_only__, 4), + __access__(__write_only__, 5)) enum libsyscalls_error -libsyscalls_get_signals(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_named_number **, size_t *, int *); +libsyscalls_get_signals(enum libsyscalls_os os, enum libsyscalls_arch arch, + const struct libsyscalls_named_number **signals_out, + size_t *num_signals_out, int *are_signed_out); + + +/** + * Finds a named number in a sorted array by its signed number + * + * @param key The signed number of the named number to find + * @param base The array of named numbers, sorted in ascending + * order by their signed numbers + * @param n The number of elements in `base` + * @return The element in `base` whose signed number is `key`, + * `NULL` if not found + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __pure__, + __access__(__read_only__, 2, 3)) +const struct libsyscalls_named_number * +libsyscalls_find_signed_named_number(signed long long int key, + const struct libsyscalls_named_number *base, size_t n); + + +/** + * Finds a named number in a sorted array by its unsigned number + * + * @param key The unsigned number of the named number to find + * @param base The array of named numbers, sorted in ascending + * order by their unsigned numbers + * @param n The number of elements in `base` + * @return The element in `base` whose unsigned number is `key`, + * `NULL` if not found + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __pure__, + __access__(__read_only__, 2, 3)) +const struct libsyscalls_named_number * +libsyscalls_find_unsigned_named_number(unsigned long long int key, + const struct libsyscalls_named_number *base, size_t n); + + +/** + * Finds a named number in a sorted array by its number + * + * @param key The number of the named number to find + * @param is_signed Whether the numbers are signed + * @param base The array of named numbers, sorted in ascending + * order by their numbers + * @param n The number of elements in `base` + * @return The element in `base` whose number is `key`, + * `NULL` if not found + * + * If `is_signed` is non-zero, `key` is reinterpreted (not cast) as a signed number; + * thus it is important that if `key` uses all bits in `long long int`, + * would be an error to take a `int`, reinterpret it as an `unsigned int`, + * and input it to as `key` casting it to `unsigned long long int`; rather + * an `int` must first be cast to `long long int`, and then reinterpreted + * as a `unsigned long long int` before it is input as `key`. Using + * `libsyscalls_find_signed_named_number` instead removes this complication + * in such a senario. + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __pure__, + __access__(__read_only__, 3, 4)) +inline const struct libsyscalls_named_number * +libsyscalls_find_named_number(unsigned long long int key, int is_signed, + const struct libsyscalls_named_number *base, size_t n) +{ + signed long long int skey = *(signed long long int *)&key; + return is_signed ? libsyscalls_find_signed_named_number(skey, base, n) + : libsyscalls_find_unsigned_named_number(key, base, n); +} + /** * Get system call information tweak for the arguments passed * to the system call, as well as information about how to * print named values in the arguments and return * - * @param os The operating system the system call was invoked on - * @param arch The architecture the system call was invoked on - * @param syscall The ABI of the system call (see libsyscalls_get_syscall) - * @param syscall_number The system call's number - * @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; - * 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_NOMEM - Failed to allocate memory for `*info_out` - * LIBSYSCALLS_E_INVAL - One of the arguments was NULL + * @param os The operating system the system call was invoked on + * @param arch The architecture the system call was invoked on + * @param syscall The ABI of the system call (see libsyscalls_get_syscall) + * @param syscall_number The system call's number + * @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; + * 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_NOMEM - Failed to allocate memory for `*info_out` + * LIBSYSCALLS_E_INVAL - One of the arguments was NULL */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __nonnull__, __access__(__read_only__, 3), __access__(__write_only__, 6)) +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, const unsigned long long int *, struct libsyscalls_syscall_display_info **); +libsyscalls_get_syscall_display_info(enum libsyscalls_os os, enum libsyscalls_arch arch, + const struct libsyscalls_syscall_abi *syscall, + long long int syscall_number, + const unsigned long long int *syscall_arguments, + struct libsyscalls_syscall_display_info **info_out); + /** * Get information on how an instance of non-struct, non-union @@ -2692,32 +2878,36 @@ libsyscalls_get_syscall_display_info(enum libsyscalls_os, enum libsyscalls_arch, * 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, `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 - * @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_ISSTRUCT - `datatype` represents a structure or union, - * or an array of a structure or union + * @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, `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 + * + * @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_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__, __access__(__write_only__, 4)) +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 *); +libsyscalls_get_datatype_description(enum libsyscalls_os os, enum libsyscalls_arch arch, + enum libsyscalls_datatype datatype, + struct libsyscalls_datatype_description *description_out); + /** * Get the alignment used for or a scalar integer data type @@ -2733,34 +2923,38 @@ libsyscalls_get_datatype_description(enum libsyscalls_os, enum libsyscalls_arch, * optimal alignment), in such cases, that proscribed alignment will * be returned instead. * - * @param os The operating system the data type is used on - * @param arch The architecture the data type is used on - * @param width_in_bits The width of the integer, in bits - * @param alignment_out Output parameter for the alignment, in bits - * (may be NULL, will never be filled with 0) - * @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 - `width_in_bits` is 0 - * LIBSYSCALLS_E_NOSUCHTYPE - The selected architecture (`arch`) does not - * support any integer width the specified - * width (`width_in_bits`), or the operating - * system (`os`) does not support the data type - * (that would only be the case if the data type - * uses a new register that must be specifically - * supported in the operating system's context - * switching) + * @param os The operating system the data type is used on + * @param arch The architecture the data type is used on + * @param width_in_bits The width of the integer, in bits + * @param alignment_out Output parameter for the alignment, in bits + * (may be NULL, will never be filled with 0) + * + * @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 - `width_in_bits` is 0 + * LIBSYSCALLS_E_NOSUCHTYPE - The selected architecture (`arch`) does not + * support any integer width the specified + * width (`width_in_bits`), or the operating + * system (`os`) does not support the data type + * (that would only be the case if the data type + * uses a new register that must be specifically + * supported in the operating system's context + * switching) * * The function may complete successfully even if out ought to * return LIBSYSCALLS_E_ARCHNOSUP, in such cases, the result * is indeed reliable */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 4)) +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 *); +libsyscalls_get_integer_alignment(enum libsyscalls_os os, enum libsyscalls_arch arch, + unsigned width_in_bits, unsigned *alignment_out); + /** * Parse a string of bits as a signed integer @@ -2768,20 +2962,26 @@ libsyscalls_get_integer_alignment(enum libsyscalls_os, enum libsyscalls_arch, un * 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` + * @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 > sizeof(long long int) * CHAR_BIT` */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 4), __access__(__write_only__, 5)) +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 *); +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); + /** * Create a string of bits representing a signed integer @@ -2789,20 +2989,23 @@ libsyscalls_parse_signed_integer(unsigned long long int, enum libsyscalls_dataty * 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` + * @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 > 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 *); +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); + /** * Take bits from a section of a split value @@ -2813,18 +3016,23 @@ libsyscalls_make_signed_integer(unsigned long long int, int, enum libsyscalls_da * 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` + * @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 > 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 *); +libsyscalls_unsection_value(unsigned long long int value_in, size_t bits, + enum libsyscalls_datatype_section section, + unsigned long long int *value_out); + /** * Create a split section from a value @@ -2832,51 +3040,70 @@ libsyscalls_unsection_value(unsigned long long int, size_t, enum libsyscalls_dat * 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` + * @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 > 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 *); +libsyscalls_section_value(unsigned long long int value_in, size_t bits, + enum libsyscalls_datatype_section section, + unsigned long long int *value_out); + /** * 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 + * @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)) +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 *); +libsyscalls_to_tracer_endian(const void *value_in, size_t offset_in, + const struct libsyscalls_datatype_description *type, + unsigned long long int *value_out); + /** * 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 + * @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)) +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); +libsyscalls_to_tracee_endian(unsigned long long int value_in, + const struct libsyscalls_datatype_description *type, + void *value_out, size_t out_offset); + /** * Get information on how an instance of struct or union is to be parsed @@ -2886,37 +3113,44 @@ libsyscalls_to_tracee_endian(unsigned long long int, const struct libsyscalls_da * 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 + * @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)) +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 **); +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); #endif /* TODO add libsyscalls_get_struct_display_info */ diff --git a/libsyscalls_find_named_number.c b/libsyscalls_find_named_number.c new file mode 100644 index 0000000..fe8bb47 --- /dev/null +++ b/libsyscalls_find_named_number.c @@ -0,0 +1,141 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +#ifdef USE_INTERPOLATION_SEARCH + +# ifndef INTERPOLATION_SEARCH_FLOAT +# define INTERPOLATION_SEARCH_FLOAT long double +# endif + + +/* 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 {\ + INTERPOLATION_SEARCH_FLOAT 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)[0] : NULL;\ + if ((KEY) >= READ((BASE), h))\ + return (KEY) == READ((BASE), h) ? &(BASE)[h] : NULL;\ + if (READ((BASE), 0) == READ((BASE), h))\ + return NULL;\ + \ + goto use_double;\ + 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 ((KEY) <= READ((BASE), 0))\ + return (KEY) == READ((BASE), 0) ? &(BASE)[0] : NULL;\ + if ((KEY) >= READ((BASE), h))\ + return (KEY) == READ((BASE), h) ? &(BASE)[h] : NULL;\ + if (READ((BASE), 0) == READ((BASE), h))\ + return NULL;\ + }\ + \ + use_double:\ + for (;;) {\ + guess = DIFF(long long int, (KEY), READ((BASE), 0));\ + guess_d = (INTERPOLATION_SEARCH_FLOAT)guess * (INTERPOLATION_SEARCH_FLOAT)h;\ + guess = DIFF(long long int, READ((BASE), h), READ((BASE), 0));\ + guess_d /= (INTERPOLATION_SEARCH_FLOAT)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 ((KEY) <= READ((BASE), 0))\ + return (KEY) == READ((BASE), 0) ? &(BASE)[0] : NULL;\ + if ((KEY) >= READ((BASE), h))\ + return (KEY) == READ((BASE), h) ? &(BASE)[h] : NULL;\ + if (READ((BASE), 0) == READ((BASE), h))\ + return NULL;\ + }\ + } while (0) + + +#else + + +PURE_FUNCTION +static int +signed_named_number_cmp(const void *a_, const void *b_) +{ + const struct libsyscalls_named_number *a = a_, *b = b_; + return a->number.s < b->number.s ? -1 : a->number.s > b->number.s; +} + + +PURE_FUNCTION +static int +unsigned_named_number_cmp(const void *a_, const void *b_) +{ + const struct libsyscalls_named_number *a = a_, *b = b_; + return a->number.u < b->number.u ? -1 : a->number.u > b->number.u; +} + + +#endif + + +const struct libsyscalls_named_number * +libsyscalls_find_signed_named_number(signed long long int key, + const struct libsyscalls_named_number *base, size_t n) +{ +#ifdef USE_INTERPOLATION_SEARCH +# define X(ARR, I) ((ARR)[I].number.s) + INTERPOL_SEARCH(key, base, n, X); +# undef X +#else + struct libsyscalls_named_number struct_key = {.number.s = key}; + return bsearch(&struct_key, base, n, sizeof(*base), &signed_named_number_cmp); +#endif +} + + +const struct libsyscalls_named_number * +libsyscalls_find_unsigned_named_number(unsigned long long int key, + const struct libsyscalls_named_number *base, size_t n) +{ +#ifdef USE_INTERPOLATION_SEARCH +# define X(ARR, I) ((ARR)[I].number.u) + INTERPOL_SEARCH(key, base, n, X); +# undef X +#else + struct libsyscalls_named_number struct_key = {.number.u = key}; + return bsearch(&struct_key, base, n, sizeof(*base), &unsigned_named_number_cmp); +#endif +} + + +extern inline const struct libsyscalls_named_number * +libsyscalls_find_named_number(unsigned long long int key, int is_signed, + const struct libsyscalls_named_number *base, size_t n); diff --git a/libsyscalls_get_datatype_description.c b/libsyscalls_get_datatype_description.c index a418eb3..974c0fe 100644 --- a/libsyscalls_get_datatype_description.c +++ b/libsyscalls_get_datatype_description.c @@ -5,7 +5,8 @@ #include "generated/types.c" enum libsyscalls_error -libsyscalls_get_datatype_description(enum libsyscalls_os os, enum libsyscalls_arch arch, enum libsyscalls_datatype datatype, +libsyscalls_get_datatype_description(enum libsyscalls_os os, enum libsyscalls_arch arch, + enum libsyscalls_datatype datatype, struct libsyscalls_datatype_description *description_out) { struct libsyscalls_datatype_description description_discard, larger_type; @@ -19,7 +20,7 @@ libsyscalls_get_datatype_description(enum libsyscalls_os os, enum libsyscalls_ar if (!description_out) description_out = &description_discard; - if ((unsigned)datatype & ~(LIBSYSCALLS_TYPEBITSMASK | (LIBSYSCALLS_TYPEBITSMASK - 1U))) + if ((unsigned)datatype & ~SET_MASK_TRAIL(LIBSYSCALLS_TYPEBITSMASK)) return LIBSYSCALLS_E_INVAL; datatype ^= class = datatype & LIBSYSCALLS_TYPEBITSMASK; @@ -63,7 +64,7 @@ libsyscalls_get_datatype_description(enum libsyscalls_os os, enum libsyscalls_ar memset(description_out->byteorder, ~0, sizeof(description_out->byteorder)); -#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, ENDIAN, SIGN)\ +#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, INTMAX_ALIGN, ENDIAN, SIGN)\ case ARCH: description_out->sign_representation = LIBSYSCALLS_SIGN_##SIGN; break switch ((int)arch) { LIST_ARCH_SPECS(CASE, ;); @@ -147,7 +148,8 @@ 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_LIST(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; @@ -163,7 +165,8 @@ 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_LIST(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; @@ -258,7 +261,7 @@ arch_dependent: goto not_os_dependent; case LIBSYSCALLS_TYPE_INTPTR: case LIBSYSCALLS_TYPE_PTRDIFF: -#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, ENDIAN, SIGN)\ +#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, INTMAX_ALIGN, ENDIAN, SIGN)\ case ARCH: description_out->width_in_bits = INTPTR_BITS; break switch ((int)arch) { LIST_ARCH_SPECS(CASE, ;); @@ -268,7 +271,7 @@ arch_dependent: goto not_os_dependent; #undef CASE case LIBSYSCALLS_TYPE_SSIZE: -#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, ENDIAN, SIGN)\ +#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, INTMAX_ALIGN, ENDIAN, SIGN)\ case ARCH: description_out->width_in_bits = SIZE_BITS; break switch ((int)arch) { LIST_ARCH_SPECS(CASE, ;); @@ -314,7 +317,7 @@ not_os_dependent: if (divide_array_size_with_type_size_out) description_out->array_size /= description_out->width_in_bits; -#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, ENDIAN, SIGN)\ +#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, INTMAX_ALIGN, ENDIAN, SIGN)\ case ARCH: charbits = CHARBITS; endian = ENDIAN; break switch ((int)arch) { LIST_ARCH_SPECS(CASE, ;); @@ -377,17 +380,12 @@ not_os_dependent: /* we known from the code above that we are working with split 64-bit integers */ if (half == +1) - coverage ^= 0xFFFFFFFFFFFFFFFFull; - if (coverage == 0xFFFFFFFF00000000ull) description_out->section = LIBSYSCALLS_SECTION_UPPER_HALF; - else if (coverage == 0x00000000FFFFFFFFull) description_out->section = LIBSYSCALLS_SECTION_LOWER_HALF; - else if (coverage == 0x0000FFFFFFFF0000ull) description_out->section = LIBSYSCALLS_SECTION_INNER_HALF; - else if (coverage == 0xFFFF00000000FFFFull) description_out->section = LIBSYSCALLS_SECTION_OUTER_HALF; - else if (coverage == 0x0000FFFF0000FFFFull) description_out->section = LIBSYSCALLS_SECTION_EVEN_QUARTERS_AS_HALF; - else if (coverage == 0xFFFF0000FFFF0000ull) description_out->section = LIBSYSCALLS_SECTION_ODD_QUARTERS_AS_HALF; - else if (coverage == 0x00FF00FF00FF00FFull) description_out->section = LIBSYSCALLS_SECTION_EVEN_BYTES_AS_HALF; - else if (coverage == 0xFF00FF00FF00FF00ull) description_out->section = LIBSYSCALLS_SECTION_ODD_BYTES_AS_HALF; - else - abort(); + coverage ^= 0xFFFFFFFFFFFFFFFFULL; +#define CASE(SECTION, PAT16_FIRST, PAT16, PAT32_FIRST, PAT32, PAT64_FIRST, PAT64)\ + if (PAT64_FIRST && LIBSYSCALLS_GET_SECTION_FRACTION(SECTION) && coverage == PAT64##ULL)\ + description_out->section = SECTION + LIBSYSCALLS_LIST_SECTIONS(CASE, ; else); else abort(); +#undef CASE } return LIBSYSCALLS_E_OK; diff --git a/libsyscalls_get_integer_alignment.c b/libsyscalls_get_integer_alignment.c index 1c2d10e..f13f40f 100644 --- a/libsyscalls_get_integer_alignment.c +++ b/libsyscalls_get_integer_alignment.c @@ -4,73 +4,26 @@ #include "generated/integers.c" +#define X(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, INTMAX_ALIGN, ENDIAN, SIGN) [ARCH] = INTMAX_ALIGN +static const unsigned char aligntable[] = {LIST_ARCH_SPECS(X, COMMA)}; +#undef X + enum libsyscalls_error -libsyscalls_get_integer_alignment(enum libsyscalls_os os, enum libsyscalls_arch arch, unsigned width_in_bits, unsigned *alignment_out) +libsyscalls_get_integer_alignment(enum libsyscalls_os os, enum libsyscalls_arch arch, + unsigned width_in_bits, unsigned *alignment_out) { unsigned maxalign; if (!width_in_bits) return LIBSYSCALLS_E_INVAL; - switch ((int)arch) { - case LIBSYSCALLS_ARCH_M68K: /* https://m680x0.github.io/doc/abi.html#scalar-types - * https://lists.nongnu.org/archive/html/qemu-devel/2015-02/msg04797.html */ - maxalign = 16; - 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_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_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_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; - - default: + if ((size_t)arch >= ELEMSOF(aligntable)) + return LIBSYSCALLS_E_ARCHNOSUP; + maxalign = aligntable[(size_t)arch]; + if (!maxalign) return LIBSYSCALLS_E_ARCHNOSUP; - } - if (width_in_bits & (width_in_bits - 1) || width_in_bits & 7 || width_in_bits > 64) + if (IS_NOT_2POW(width_in_bits) || width_in_bits % 8 || width_in_bits > 64) return LIBSYSCALLS_E_NOSUCHTYPE; *alignment_out = width_in_bits < maxalign ? width_in_bits : maxalign; diff --git a/libsyscalls_get_struct_description.c b/libsyscalls_get_struct_description.c index 4d9ce68..cc1c42b 100644 --- a/libsyscalls_get_struct_description.c +++ b/libsyscalls_get_struct_description.c @@ -41,8 +41,9 @@ struct padding { 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); +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 * @@ -74,7 +75,8 @@ create_pad_description(enum libsyscalls_os os, enum libsyscalls_arch arch, unsig static enum libsyscalls_error -shift_fields(enum libsyscalls_os os, enum libsyscalls_arch arch, struct libsyscalls_structure_description *description, +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; @@ -201,22 +203,28 @@ move_in_subdescriptions(char *buffer, size_t *offsetp, struct libsyscalls_struct 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) + 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; + enum libsyscalls_datatype type; + const struct libsyscalls_datatype_description *type_description; unsigned splits, expected_splits, end; unsigned long long int result = 0, subresult; signed long long int sresult; int is_negative; + type = description->fields[i].type; + type_description = description->fields[i].type_description.nonstructure; + if ((type & LIBSYSCALLS_TYPEBITSMASK) != LIBSYSCALLS_TYPEBITS_SCALAR) abort(); type ^= LIBSYSCALLS_TYPEBITS_SCALAR; - if (type >= LIBSYSCALLS_TYPEOFFSET_SPLIT_PRIMITIVES && type < LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES) + 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) + else if (type >= LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS && + type < LIBSYSCALLS_TYPEOFFSET_FIXED_ARRAYS) splits = 1; else abort(); @@ -229,9 +237,11 @@ read_field(const void *data, size_t data_size, const size_t *field_offsets, if ((type & LIBSYSCALLS_TYPEBITSMASK) != LIBSYSCALLS_TYPEBITS_SCALAR) abort(); type ^= LIBSYSCALLS_TYPEBITS_SCALAR; - if (type >= LIBSYSCALLS_TYPEOFFSET_SPLIT_PRIMITIVES && type < LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES) + 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) + else if (type >= LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS && + type < LIBSYSCALLS_TYPEOFFSET_FIXED_ARRAYS) splits = 1; else abort(); @@ -258,7 +268,8 @@ read_field(const void *data, size_t data_size, const size_t *field_offsets, } if (type_description->is_signed) { - if (libsyscalls_parse_signed_integer(result, type_description->sign_representation, bits, &result, &is_negative)) + if (libsyscalls_parse_signed_integer(result, type_description->sign_representation, + bits, &result, &is_negative)) abort(); if (is_negative) { #if LLONG_MIN == -LLONG_MAX @@ -397,9 +408,10 @@ adjust_for_struct(enum libsyscalls_os os, enum libsyscalls_arch arch, const void 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); + r = get_struct_description(os, arch, description->fields[i].type, + &((const char *)data)[field_offsets[i]], + USAT_MINUS(data_size, field_offsets[i]), + &struct_description, extra_sizep); if (r) return r; @@ -418,7 +430,7 @@ adjust_for_struct(enum libsyscalls_os os, enum libsyscalls_arch arch, const void if (field > i) abort(); set_subsize: - uvalue = read_field(data, data_size, field_offsets, description, i, undetermined_sizep); + uvalue = read_field(data, data_size, field_offsets, description, field, undetermined_sizep); /* TODO set `*subsizep` to `uvalue` (may overflow) */ } if (!struct_description->array_size) @@ -442,7 +454,7 @@ adjust_for_struct(enum libsyscalls_os os, enum libsyscalls_arch arch, const void 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 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]; @@ -494,8 +506,10 @@ adjust_for_fields(enum libsyscalls_os os, enum libsyscalls_arch arch, const void 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) +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; @@ -508,7 +522,7 @@ get_struct_description(enum libsyscalls_os os, enum libsyscalls_arch arch, enum size_t npaddings = 0, paddings_size = 0; struct padding *paddings = NULL; - if ((unsigned)datatype & ~(LIBSYSCALLS_TYPEBITSMASK | (LIBSYSCALLS_TYPEBITSMASK - 1U))) + if ((unsigned)datatype & ~SET_MASK_TRAIL(LIBSYSCALLS_TYPEBITSMASK)) return LIBSYSCALLS_E_INVAL; datatype ^= class = datatype & LIBSYSCALLS_TYPEBITSMASK; @@ -577,7 +591,8 @@ get_struct_description(enum libsyscalls_os os, enum libsyscalls_arch arch, enum #define CASE(UPPERCASE, LOWERCASE)\ case LIBSYSCALLS_OS_##UPPERCASE:\ - r = fix_##LOWERCASE##_struct_description(arch, datatype, class, data, data_size, description);\ + r = fix_##LOWERCASE##_struct_description(arch, datatype, class,\ + data, data_size, description);\ break switch ((int)os) { @@ -613,8 +628,10 @@ fail: 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) +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; @@ -637,7 +654,7 @@ libsyscalls_get_struct_description(enum libsyscalls_os os, enum libsyscalls_arch size = offsetof(struct libsyscalls_structure_description, fields); size += (size_t)description->num_fields * sizeof(*description->fields); - size += (align - (size & (align - 1))) & (align - 1); + size += ALIGNMENT_ADJUSTMENT(size, align); new = realloc(description, size + extra_size); if (!new) { @@ -647,9 +664,11 @@ libsyscalls_get_struct_description(enum libsyscalls_os os, enum libsyscalls_arch } description = new; - move_in_subdescriptions((void *)description, &size, description, nalign == align, salign == align); + 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); + move_in_subdescriptions((void *)description, &size, description, + nalign != align, salign != align); *description_out = description; return LIBSYSCALLS_E_OK; diff --git a/libsyscalls_get_syscall_display_info.c b/libsyscalls_get_syscall_display_info.c index add65e2..f18834c 100644 --- a/libsyscalls_get_syscall_display_info.c +++ b/libsyscalls_get_syscall_display_info.c @@ -43,146 +43,18 @@ trailing_zeroes(unsigned long long int x) } -#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_) -{ - const struct libsyscalls_named_number *a = a_, *b = b_; - return a->number.s < b->number.s ? -1 : a->number.s > b->number.s; -} - - -PURE_FUNCTION -static int -unsigned_named_number_cmp(const void *a_, const void *b_) -{ - const struct libsyscalls_named_number *a = a_, *b = b_; - return a->number.u < b->number.u ? -1 : a->number.u > b->number.u; -} - - -#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) +extract_signal(enum libsyscalls_os os, enum libsyscalls_arch arch, + unsigned long long int *valuep, char *fallback_out) { const struct libsyscalls_named_number *signals, *found; size_t nsignals; - struct libsyscalls_named_number key = {.number.u = *valuep}; int is_signed; if (libsyscalls_get_signals(os, arch, &signals, &nsignals, &is_signed)) return NULL; -#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 + found = libsyscalls_find_named_number(*valuep, is_signed, signals, nsignals); if (!found) return NULL; @@ -196,11 +68,11 @@ extract_signal(enum libsyscalls_os os, enum libsyscalls_arch arch, unsigned long 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, - const struct libsyscalls_syscall_abi *syscall, int nargs, int nsyms) + const struct libsyscalls_syscall_abi *syscall, + size_t nargs, size_t nsyms) { struct libsyscalls_syscall_display_info *ret; - size_t size, dataoff, paramoff; - int i; + size_t i, size, dataoff, paramoff; size = sizeof(*ret); @@ -209,14 +81,14 @@ build_syscall_display_info(void *data, size_t data_size, size_t data_align, size += 1; } dataoff = size; - size += (size_t)nsyms * data_size; + size += nsyms * data_size; if (size & (alignof(struct libsyscalls_syscall_type_info) - 1)) { size |= alignof(struct libsyscalls_syscall_type_info) - 1; size += 1; } paramoff = size; - size += (size_t)(nargs + 1) * sizeof(*ret->params); + size += (nargs + 1U) * sizeof(*ret->params); ret = calloc(1, size); if (!ret) @@ -231,8 +103,8 @@ build_syscall_display_info(void *data, size_t data_size, size_t data_align, ret->params[i].type = syscall->parameters_types[i]; if (funcs[i]) { ret->params[i].function = funcs[i]; - ret->params[i].data = (void *)&((char *)ret)[dataoff + (size_t)nsyms * data_size]; - memcpy(ret->params[i].data, &((char *)data)[(size_t)i * data_size], data_size); + ret->params[i].data = (void *)&((char *)ret)[dataoff + nsyms * data_size]; + memcpy(ret->params[i].data, &((char *)data)[i * data_size], data_size); nsyms++; } } @@ -240,8 +112,8 @@ build_syscall_display_info(void *data, size_t data_size, size_t data_align, ret->retvalue->expect_zero = syscall->expect_zero; if (funcs[i]) { ret->retvalue->function = funcs[i]; - ret->retvalue->data = (void *)&((char *)ret)[dataoff + (size_t)nsyms * data_size]; - memcpy(ret->retvalue->data, &((char *)data)[(size_t)i * data_size], data_size); + ret->retvalue->data = (void *)&((char *)ret)[dataoff + nsyms * data_size]; + memcpy(ret->retvalue->data, &((char *)data)[i * data_size], data_size); } return ret; diff --git a/libsyscalls_get_syscall_range.c b/libsyscalls_get_syscall_range.c index eb9b11e..0fd2554 100644 --- a/libsyscalls_get_syscall_range.c +++ b/libsyscalls_get_syscall_range.c @@ -5,7 +5,8 @@ #include "generated/get_syscall_range.c" enum libsyscalls_error -libsyscalls_get_syscall_range(enum libsyscalls_os os, enum libsyscalls_arch arch, long long int *min_out, long long int *max_out) +libsyscalls_get_syscall_range(enum libsyscalls_os os, enum libsyscalls_arch arch, + long long int *min_out, long long int *max_out) { long long int discarded; diff --git a/libsyscalls_parse_signed_integer.c b/libsyscalls_parse_signed_integer.c index da6f078..635000d 100644 --- a/libsyscalls_parse_signed_integer.c +++ b/libsyscalls_parse_signed_integer.c @@ -3,7 +3,8 @@ enum libsyscalls_error -libsyscalls_parse_signed_integer(unsigned long long int value_in, enum libsyscalls_datatype_sign_representation representation, +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; diff --git a/libsyscalls_section_value.c b/libsyscalls_section_value.c index dc86cca..6cdb787 100644 --- a/libsyscalls_section_value.c +++ b/libsyscalls_section_value.c @@ -4,9 +4,11 @@ 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) + enum libsyscalls_datatype_section section, + unsigned long long int *value_out) { unsigned long long int value = value_in, mask, shift; + size_t hbits; if (bits > sizeof(value) / sizeof(char) * CHAR_BIT || bits & (size_t)(LIBSYSCALLS_GET_SECTION_FRACTION(section) - 1U)) @@ -43,14 +45,18 @@ libsyscalls_section_value(unsigned long long int value_in, size_t bits, break; case LIBSYSCALLS_SECTION_OUTER_HALF: /* 0xFFFF00000000FFFF */ - value = ((value & (mask << (bits + bits / 2))) >> bits) | (value & (mask >> (bits / 2))); + hbits = bits / 2; + value = ((value & (mask << (bits + hbits))) >> bits) + | (value & (mask >> hbits)); 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))); + hbits = bits / 2; + value = ((value & (mask << hbits) & ~mask) >> hbits) + | (value & (mask >> hbits)); break; case LIBSYSCALLS_SECTION_ODD_BYTES_AS_HALF: /* 0xFF00FF00FF00FF00 */ diff --git a/libsyscalls_unsection_value.c b/libsyscalls_unsection_value.c index 6cd797e..fb0f1fe 100644 --- a/libsyscalls_unsection_value.c +++ b/libsyscalls_unsection_value.c @@ -4,7 +4,8 @@ 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) + enum libsyscalls_datatype_section section, + unsigned long long int *value_out) { unsigned long long int value = value_in, mask, shift; @@ -15,8 +16,6 @@ libsyscalls_unsection_value(unsigned long long int value_in, size_t bits, 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; @@ -40,17 +39,20 @@ libsyscalls_unsection_value(unsigned long long int value_in, size_t bits, case LIBSYSCALLS_SECTION_OUTER_HALF: /* 0xFFFF00000000FFFF */ mask = (1ULL << (bits / 2)) - 1ULL; - value = ((value & ~mask) << bits) | (value & mask); + 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); + 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 = ((value & ~mask) << (bits / 2)) + | (value & mask); value <<= bits / 2; break; diff --git a/linux/symbols.c b/linux/symbols.c index cbfb661..5cc848d 100644 --- a/linux/symbols.c +++ b/linux/symbols.c @@ -275,7 +275,7 @@ get_linux_syscall_display_info(enum libsyscalls_arch arch, const struct libsysca { LIBSYSCALLS_SYMBOL_PRINTER_DATA *data; libsyscalls_symbol_printer_function **funcs; - int i, nargs, nsyms; + size_t i, nargs, nsyms; size_t data_size = offsetof(LIBSYSCALLS_SYMBOL_PRINTER_DATA, buf); size_t data_align = alignof(LIBSYSCALLS_SYMBOL_PRINTER_DATA); size_t bufspace, bufspace1, bufspace2; diff --git a/test b/test index 4af52c8..28ce256 100755 --- a/test +++ b/test @@ -42,6 +42,9 @@ p tests/os-dependent-arrays p tests/os-dependent-integers await +t tests/error-search +t tests/signal-search + # TODO test libsyscalls_get_struct_description # TODO test libsyscalls_get_struct_display_info diff --git a/tests/archinfo b/tests/archinfo index 5034766..334571e 100644 --- a/tests/archinfo +++ b/tests/archinfo @@ -1,19 +1,22 @@ # -*- sh -*- # See LICENSE file for copyright and license details. -printf '%s\n' "$archinfo" | grep '^AMD64 8 64 64 Little TWOS_COMPLEMENT' >/dev/null -printf '%s\n' "$archinfo" | grep '^AMD64_X32 8 32 32 Little TWOS_COMPLEMENT' >/dev/null -printf '%s\n' "$archinfo" | grep '^M68K 8 32 32 Big TWOS_COMPLEMENT' >/dev/null -printf '%s\n' "$archinfo" | grep '^PARISC_32 8 32 32 Big TWOS_COMPLEMENT' >/dev/null -printf '%s\n' "$archinfo" | grep '^PARISC_64 8 64 64 Big TWOS_COMPLEMENT' >/dev/null -printf '%s\n' "$archinfo" | grep '^SPARC_32 8 32 32 Big TWOS_COMPLEMENT' >/dev/null -printf '%s\n' "$archinfo" | grep '^I386 8 32 32 Little TWOS_COMPLEMENT' >/dev/null +printf '%s\n' "$archinfo" | grep '^AMD64 8 64 64 64 Little TWOS_COMPLEMENT' >/dev/null +printf '%s\n' "$archinfo" | grep '^AMD64_X32 8 32 32 64 Little TWOS_COMPLEMENT' >/dev/null +printf '%s\n' "$archinfo" | grep '^M68K 8 32 32 16 Big TWOS_COMPLEMENT' >/dev/null +printf '%s\n' "$archinfo" | grep '^PARISC_32 8 32 32 64 Big TWOS_COMPLEMENT' >/dev/null +printf '%s\n' "$archinfo" | grep '^PARISC_64 8 64 64 64 Big TWOS_COMPLEMENT' >/dev/null +printf '%s\n' "$archinfo" | grep '^SPARC_32 8 32 32 64 Big TWOS_COMPLEMENT' >/dev/null +printf '%s\n' "$archinfo" | grep '^I386 8 32 32 32 Little TWOS_COMPLEMENT' >/dev/null test $(getbytesize AMD64) = 8 test $(getbytesize I386) = 8 test $(getaddrsize I386) = 32 test $(getaddrsize AMD64) = 64 test $(getsizesize AMD64) = 64 test $(getsizesize I386) = 32 +test $(getintalign I386) = 32 +test $(getintalign AMD64) = 64 +test $(getintalign M68K) = 16 test $(getendian I386) = Little test $(getendian AMD64) = Little test $(getendian M68K) = Big diff --git a/tests/error-search b/tests/error-search new file mode 100644 index 0000000..dd71bd9 --- /dev/null +++ b/tests/error-search @@ -0,0 +1,13 @@ +# -*- sh -*- +# See LICENSE file for copyright and license details. + +for os in $(getnamelist OS); do + osn=$(getnum OS $os) + for arch in $(getnamelist ARCH); do + archn=$(getnum ARCH $arch) + if issupported $os $arch; then + p tests/run test-search.tu errors $osn $archn $os $arch + fi + done + await +done diff --git a/tests/load-archinfo b/tests/load-archinfo index e5413b4..8e6b2a6 100644 --- a/tests/load-archinfo +++ b/tests/load-archinfo @@ -33,9 +33,12 @@ getaddrsize () { getsizesize () { printf '%s\n' "$archinfo" | grep "^$1 " | cut -d ' ' -f 4 } -getendian () { +getintalign () { printf '%s\n' "$archinfo" | grep "^$1 " | cut -d ' ' -f 5 } -getsign () { +getendian () { printf '%s\n' "$archinfo" | grep "^$1 " | cut -d ' ' -f 6 } +getsign () { + printf '%s\n' "$archinfo" | grep "^$1 " | cut -d ' ' -f 7 +} diff --git a/tests/run b/tests/run new file mode 100644 index 0000000..c9bd4b6 --- /dev/null +++ b/tests/run @@ -0,0 +1,4 @@ +# -*- sh -*- +# See LICENSE file for copyright and license details. + +"$@" diff --git a/tests/signal-search b/tests/signal-search new file mode 100644 index 0000000..b4afc49 --- /dev/null +++ b/tests/signal-search @@ -0,0 +1,13 @@ +# -*- sh -*- +# See LICENSE file for copyright and license details. + +for os in $(getnamelist OS); do + osn=$(getnum OS $os) + for arch in $(getnamelist ARCH); do + archn=$(getnum ARCH $arch) + if issupported $os $arch; then + p tests/run test-search.tu signals $osn $archn $os $arch + fi + done + await +done diff --git a/testutil/get-datatype-description.c b/testutil/get-datatype-description.c index 9c26626..b3d2637 100644 --- a/testutil/get-datatype-description.c +++ b/testutil/get-datatype-description.c @@ -31,7 +31,7 @@ main(int argc, char **argv) err = libsyscalls_get_datatype_description((enum libsyscalls_os)os, (enum libsyscalls_arch)arch, (enum libsyscalls_datatype)type, &desc); if (err) { - fprintf(stderr, "libsyscalls_get_datatype_description %s %s %s: ", argv[4], argv[5], argv[6]); + fprintf(stderr, "get-datatype-description %s %s %s: ", argv[4], argv[5], argv[6]); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/get-integer-alignment.c b/testutil/get-integer-alignment.c index 7d0fcc3..cb67eef 100644 --- a/testutil/get-integer-alignment.c +++ b/testutil/get-integer-alignment.c @@ -30,7 +30,7 @@ main(int argc, char **argv) err = libsyscalls_get_integer_alignment((enum libsyscalls_os)os, (enum libsyscalls_arch)arch, (unsigned)width, &alignment); if (err) { - fprintf(stderr, "libsyscalls_get_integer_alignment %s %s %s: ", argv[4], argv[5], argv[3]); + fprintf(stderr, "get-integer-alignment %s %s %s: ", argv[4], argv[5], argv[3]); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/get-signals.c b/testutil/get-signals.c index 54fcac4..2a2ea03 100644 --- a/testutil/get-signals.c +++ b/testutil/get-signals.c @@ -34,7 +34,7 @@ main(int argc, char **argv) } else if (err == LIBSYSCALLS_E_NOSIGNALS) { return 0; } else if (err) { - fprintf(stderr, "test-get-syscall-signals %s %s: ", argv[3], argv[4]); + fprintf(stderr, "get-signals %s %s: ", argv[3], argv[4]); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/get-syscall-errors.c b/testutil/get-syscall-errors.c index a5923f4..0870e07 100644 --- a/testutil/get-syscall-errors.c +++ b/testutil/get-syscall-errors.c @@ -34,7 +34,7 @@ main(int argc, char **argv) } else if (err == LIBSYSCALLS_E_NOERRORS) { return 0; } else if (err) { - fprintf(stderr, "test-get-syscall-errors %s %s: ", argv[3], argv[4]); + fprintf(stderr, "get-syscall-errors %s %s: ", argv[3], argv[4]); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/get-syscall-range.c b/testutil/get-syscall-range.c index 2c40b71..a199091 100644 --- a/testutil/get-syscall-range.c +++ b/testutil/get-syscall-range.c @@ -31,7 +31,7 @@ main(int argc, char **argv) printf("max: x\n"); return 0; } else if (err) { - fprintf(stderr, "test-get-syscall-range %s %s: ", argv[3], argv[4]); + fprintf(stderr, "get-syscall-range %s %s: ", argv[3], argv[4]); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/is-datatype-struct.c b/testutil/is-datatype-struct.c index e9eb2ef..ffaff5f 100644 --- a/testutil/is-datatype-struct.c +++ b/testutil/is-datatype-struct.c @@ -32,7 +32,7 @@ main(int argc, char **argv) if (err == LIBSYSCALLS_E_ISSTRUCT) { return 0; } else if (err) { - fprintf(stderr, "libsyscalls_get_datatype_description %s %s %s: ", argv[4], argv[5], argv[6]); + fprintf(stderr, "is-datatype-struct %s %s %s: ", argv[4], argv[5], argv[6]); libsyscalls_perror(NULL, err); return 2; } diff --git a/testutil/make-signed.c b/testutil/make-signed.c index 7cd0134..5ac7338 100644 --- a/testutil/make-signed.c +++ b/testutil/make-signed.c @@ -42,6 +42,7 @@ main(int argc, char **argv) printf("inval\n"); goto out; } else if (err) { + fprintf(stderr, "make-signed %s %s %s: ", argv[1], argv[2], argv[3]); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/parse-signed.c b/testutil/parse-signed.c index 0fea405..f5e6d35 100644 --- a/testutil/parse-signed.c +++ b/testutil/parse-signed.c @@ -40,6 +40,7 @@ main(int argc, char **argv) printf("inval\n"); goto out; } else if (err) { + fprintf(stderr, "parse-signed %s %s %s: ", argv[1], argv[2], argv[3]); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/section-value.c b/testutil/section-value.c index b4c0304..bb86b8d 100644 --- a/testutil/section-value.c +++ b/testutil/section-value.c @@ -37,6 +37,7 @@ main(int argc, char **argv) printf("inval\n"); goto out; } else if (err) { + fprintf(stderr, "section-value %s %s %s: ", argv[1], argv[2], argv[3]); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/test-search.c b/testutil/test-search.c new file mode 100644 index 0000000..93d6d03 --- /dev/null +++ b/testutil/test-search.c @@ -0,0 +1,114 @@ +/* See LICENSE file for copyright and license details. */ +#include "../libsyscalls.h" + +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* clang is just being silly */ +#endif + + +static struct libsyscalls_named_number not_found; +static size_t not_found_count = 0; +static char **argv; + +static void +check(unsigned long long int key, const struct libsyscalls_named_number *base, size_t n, int is_signed) +{ + static int first = 1; + + const struct libsyscalls_named_number *found; + found = libsyscalls_find_named_number(key, is_signed, base, n); + if (found) { + if (first) + not_found.number.u = key + 1; + if (found->number.u != key) { + fprintf(stderr, "test-search %s %s %s: found incorrect element: %llu instead of %llu\n", + argv[1], argv[4], argv[5], found->number.u, key); + exit(1); + } + } else { + if (first) { + fprintf(stderr, "test-search %s %s %s: did not find first element\n", argv[1], argv[4], argv[5]); + exit(1); + } + not_found.number.u = key; + not_found_count += 1; + } + + first = 0; +} + + +int +main(int argc, char **argv_) +{ + int os, arch, search_singals, is_signed; + enum libsyscalls_error err; + const struct libsyscalls_named_number *base, *min, *max; + unsigned long long int ukey; + signed long long int skey; + size_t n, expected_not_found_count; + + argv = argv_; + + if (argc != 6) { + usage: + fprintf(stderr, "usage error\n"); + return 1; + } + + if (!strcmp(argv[1], "signals")) + search_singals = 1; + else if (!strcmp(argv[1], "errors")) + search_singals = 0; + else + goto usage; + os = atoi(argv[2]); + arch = atoi(argv[3]); + + if (search_singals) + err = libsyscalls_get_signals((enum libsyscalls_os)os, (enum libsyscalls_arch)arch, &base, &n, &is_signed); + else + err = libsyscalls_get_syscall_errors((enum libsyscalls_os)os, (enum libsyscalls_arch)arch, &base, &n, &is_signed); + if (err) { + fprintf(stderr, "test-search %s %s %s: ", argv[1], argv[4], argv[5]); + libsyscalls_perror(NULL, err); + return 1; + } + + if (!n) + return 0; + + min = &base[0]; + max = &base[n - 1]; + + if (is_signed) { + skey = min->number.s; + do { + check(*(unsigned long long int *)&skey, base, n, is_signed); + } while (skey++ != max->number.s); + expected_not_found_count = (size_t)((unsigned long long int)max->number.s - + (unsigned long long int)min->number.s - + (unsigned long long int)n + 1); + } else { + ukey = min->number.u; + do { + check(ukey, base, n, is_signed); + } while (ukey++ != max->number.u); + expected_not_found_count = (size_t)(max->number.u - min->number.u - (unsigned long long int)n + 1); + } + + if (not_found.number.u == max->number.u) { + fprintf(stderr, "test-search %s %s %s: did not find last element\n", argv[1], argv[4], argv[5]); + return 1; + } + if (not_found_count != expected_not_found_count) { + fprintf(stderr, "test-search %s %s %s: did not find all elements\n", argv[1], argv[4], argv[5]); + return 1; + } + + return 0; +} diff --git a/testutil/to-tracee-endian.c b/testutil/to-tracee-endian.c index 4346883..ba97a95 100644 --- a/testutil/to-tracee-endian.c +++ b/testutil/to-tracee-endian.c @@ -78,6 +78,11 @@ main(int argc, char **argv) free(data); goto out; } else if (err) { + fail: + fprintf(stderr, "to-tracee-endian"); + for (argv = &argv[1 - argc]; *argv; argv++) + fprintf(stderr, " %s", *argv); + fprintf(stderr, ": "); libsyscalls_perror(NULL, err); return 1; } @@ -90,8 +95,7 @@ main(int argc, char **argv) free(data); goto out; } else if (err) { - libsyscalls_perror(NULL, err); - return 1; + goto fail; } make_hex(text1, data, datasize); diff --git a/testutil/to-tracer-endian.c b/testutil/to-tracer-endian.c index 53cb380..668499f 100644 --- a/testutil/to-tracer-endian.c +++ b/testutil/to-tracer-endian.c @@ -69,6 +69,10 @@ main(int argc, char **argv) printf("inval\n"); goto out; } else if (err) { + fprintf(stderr, "to-tracer-endian"); + for (argv = &argv[1 - argc]; *argv; argv++) + fprintf(stderr, " %s", *argv); + fprintf(stderr, ": "); libsyscalls_perror(NULL, err); return 1; } diff --git a/testutil/unsection-value.c b/testutil/unsection-value.c index 9c85b3b..9c7e68a 100644 --- a/testutil/unsection-value.c +++ b/testutil/unsection-value.c @@ -37,6 +37,7 @@ main(int argc, char **argv) printf("inval\n"); goto out; } else if (err) { + fprintf(stderr, "unsection-value %s %s %s: ", argv[1], argv[2], argv[3]); libsyscalls_perror(NULL, err); return 1; } -- cgit v1.2.3-70-g09d2