diff options
Diffstat (limited to '')
-rw-r--r-- | libsyscalls.h | 1327 | ||||
-rw-r--r-- | libsyscalls/advanced.h | 13 | ||||
-rw-r--r-- | libsyscalls/internal-begin.h | 76 | ||||
-rw-r--r-- | libsyscalls/internal-end.h | 21 | ||||
-rw-r--r-- | libsyscalls_get_datatype_description.c | 418 | ||||
-rw-r--r-- | libsyscalls_get_signals.c | 32 | ||||
-rw-r--r-- | libsyscalls_get_syscall.c | 37 | ||||
-rw-r--r-- | libsyscalls_get_syscall_display_info.c | 148 | ||||
-rw-r--r-- | libsyscalls_get_syscall_errors.c | 32 | ||||
-rw-r--r-- | libsyscalls_get_syscall_range.c | 26 | ||||
-rw-r--r-- | libsyscalls_perror.c | 15 | ||||
-rw-r--r-- | libsyscalls_strerror.c | 18 | ||||
-rw-r--r-- | libsyscalls_syscalls_tables_.c | 10 |
13 files changed, 2173 insertions, 0 deletions
diff --git a/libsyscalls.h b/libsyscalls.h new file mode 100644 index 0000000..f63d023 --- /dev/null +++ b/libsyscalls.h @@ -0,0 +1,1327 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBSYSCALLS_H +#define LIBSYSCALLS_H + +#include "libsyscalls/internal-begin.h" +#include "libsyscalls/short-enums.h" +#include "libsyscalls/advanced.h" + + +/** + * Macro for enumerating libsyscall error numbers + * + * The numbers are stored in `libsyscalls_error` + * + * @param X(NAME, STR) Macro that expands, will be given two arguments: + * the enum value name of the error (identifier), + * and the description of the error (string literal) + * @param D 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_ERRORS(X, D)\ + X(LIBSYSCALLS_E_OK, "Success") D\ + X(LIBSYSCALLS_E_OSNOSUP, "Operating system not supported") D\ + X(LIBSYSCALLS_E_ARCHNOSUP, "Architecture not supported for selected operating system") D\ + X(LIBSYSCALLS_E_NOSUCHSYSCALL, "No such system call") D\ + X(LIBSYSCALLS_E_NOERRORS, "There is no error listing for selected operating system") D\ + X(LIBSYSCALLS_E_NOSIGNALS, "There is no signal listing for selected operating system") D\ + X(LIBSYSCALLS_E_NOMEM, "Failed to allocate required memory") D\ + X(LIBSYSCALLS_E_INVAL, "Invalid arguments passed to function") D\ + X(LIBSYSCALLS_E_NOSUCHTYPE, "Type does not exist on the selected operating system or architecture") D\ + X(LIBSYSCALLS_E_ISSTRUCT, "Type is a structure or union") + +/** + * libsyscall error numbers + */ +enum libsyscalls_error { + LIBSYSCALLS_LIST_ERRORS(LIBSYSCALLS_LIST_ERRORS_X_, LIBSYSCALLS_COMMA_) +}; + +/** + * Operating systems + */ +enum libsyscalls_os { + LIBSYSCALLS_OS_LINUX +}; + +/** + * Architectures + */ +enum libsyscalls_arch { + LIBSYSCALLS_ARCH_ALPHA, + LIBSYSCALLS_ARCH_AMD64, + LIBSYSCALLS_ARCH_AMD64_X32, /* 32-bit ABI, not traditional 32-bit x86 ISA */ + LIBSYSCALLS_ARCH_ARM_OABI, + LIBSYSCALLS_ARCH_ARM_EABI, + LIBSYSCALLS_ARCH_IA64, + LIBSYSCALLS_ARCH_M68K, + LIBSYSCALLS_ARCH_MICROBLAZE, + LIBSYSCALLS_ARCH_MIPS_O32, + LIBSYSCALLS_ARCH_MIPS_N32, + LIBSYSCALLS_ARCH_MIPS_N64, + LIBSYSCALLS_ARCH_PARISC_32, + LIBSYSCALLS_ARCH_PARISC_64, + LIBSYSCALLS_ARCH_POWERPC_32, + LIBSYSCALLS_ARCH_POWERPC_64, + LIBSYSCALLS_ARCH_POWERPC_NOSPU, + LIBSYSCALLS_ARCH_POWERPC_SPU, + LIBSYSCALLS_ARCH_S390_32, + LIBSYSCALLS_ARCH_S390_64, + LIBSYSCALLS_ARCH_SH, + LIBSYSCALLS_ARCH_SPARC_32, + LIBSYSCALLS_ARCH_SPARC_64, + LIBSYSCALLS_ARCH_I386, + LIBSYSCALLS_ARCH_XTENSA +}; + +enum libsyscalls_datatype { + + /* Type renaming, these macros will be undefined later */ +#define LIBSYSCALLS_TYPE_CHAR_ARRAY LIBSYSCALLS_TYPE_BUFFER +#define LIBSYSCALLS_TYPE_CHAR_ARRAY_UNKNOWN_FILL LIBSYSCALLS_TYPE_BUFFER_UNKNOWN_FILL + + /* 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_LIST_SPECIAL_TYPES(X, SUFFIX, D, FIRST)\ + /* 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) */\ + X(LIBSYSCALLS_TYPE_NO_RETURN ## SUFFIX,, "no_return") D\ + /* either used as return type or 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)) */\ + X(LIBSYSCALLS_TYPE_VOID ## SUFFIX,, "void") + +#define LIBSYSCALLS_LIST_SPLIT_PRIMITIVES(X, SUFFIX, D, FIRST)\ + X(LIBSYSCALLS_TYPE_UINT64_HIGH_32 ## SUFFIX, FIRST, "uint64_t {. << 32}") D\ + X(LIBSYSCALLS_TYPE_UINT64_LOW_32 ## SUFFIX,, "uint64_t {. & 0xFFFFFFFF}") D\ + X(LIBSYSCALLS_TYPE_UINT64_FRONT_32 ## SUFFIX,, "uint64_t {((uint32_t *)&.)[0]}") D\ + X(LIBSYSCALLS_TYPE_UINT64_BACK_32 ## SUFFIX,, "uint64_t {((uint32_t *)&.)[1]}") D\ + X(LIBSYSCALLS_TYPE_INT64_HIGH_32 ## SUFFIX,, "int64_t {. << 32}") D\ + X(LIBSYSCALLS_TYPE_INT64_LOW_32 ## SUFFIX,, "int64_t {. & 0xFFFFFFFF}") D\ + X(LIBSYSCALLS_TYPE_INT64_FRONT_32 ## SUFFIX,, "int64_t {((uint32_t *)&.)[0]}") D\ + X(LIBSYSCALLS_TYPE_INT64_BACK_32 ## SUFFIX,, "int64_t {((uint32_t *)&.)[1]}") + +#define LIBSYSCALLS_LIST_COMPOSITE_PRIMITIVES(X, SUFFIX, D, FIRST)\ + X(LIBSYSCALLS_TYPE_STRING ## SUFFIX, FIRST, "const char *") D\ + X(LIBSYSCALLS_TYPE_STRINGS_THEN_NULL ## SUFFIX,, "const char **") + +#define LIBSYSCALLS_LIST_UNANNOTATED_NUMERICALS(X, SUFFIX, D, FIRST)\ + X(LIBSYSCALLS_TYPE_MEMORY_ADDRESS ## SUFFIX, FIRST, "void *") D\ + X(LIBSYSCALLS_TYPE_CHAR ## SUFFIX,, "char") D\ + X(LIBSYSCALLS_TYPE_SCHAR ## SUFFIX,, "signed char") D\ + X(LIBSYSCALLS_TYPE_UCHAR ## SUFFIX,, "unsigned char") D\ + X(LIBSYSCALLS_TYPE_SHORT ## SUFFIX,, "short int") D\ + X(LIBSYSCALLS_TYPE_USHORT ## SUFFIX,, "unsigned short int") D\ + X(LIBSYSCALLS_TYPE_INT ## SUFFIX,, "int") D\ + X(LIBSYSCALLS_TYPE_UINT ## SUFFIX,, "unsigned int") D\ + X(LIBSYSCALLS_TYPE_LONG ## SUFFIX,, "long int") D\ + X(LIBSYSCALLS_TYPE_ULONG ## SUFFIX,, "unsigned long int") D\ + X(LIBSYSCALLS_TYPE_LLONG ## SUFFIX,, "long long int") D\ + X(LIBSYSCALLS_TYPE_ULLONG ## SUFFIX,, "unsigned long long int") D\ + X(LIBSYSCALLS_TYPE_SSIZE ## SUFFIX,, "ssize_t") D\ + X(LIBSYSCALLS_TYPE_SIZE ## SUFFIX,, "size_t") D\ + X(LIBSYSCALLS_TYPE_PTRDIFF ## SUFFIX,, "ptrdiff_t") D\ + X(LIBSYSCALLS_TYPE_UPTRDIFF ## SUFFIX,, "uptrdiff_t") D\ + X(LIBSYSCALLS_TYPE_INTPTR ## SUFFIX,, "intptr_t") D\ + X(LIBSYSCALLS_TYPE_UINTPTR ## SUFFIX,, "uintptr_t") D\ + X(LIBSYSCALLS_TYPE_INT8 ## SUFFIX,, "int8_t") D\ + X(LIBSYSCALLS_TYPE_UINT8 ## SUFFIX,, "uint8_t") D\ + X(LIBSYSCALLS_TYPE_INT16 ## SUFFIX,, "int16_t") D\ + X(LIBSYSCALLS_TYPE_UINT16 ## SUFFIX,, "uint16_t") D\ + X(LIBSYSCALLS_TYPE_INT32 ## SUFFIX,, "int32_t") D\ + X(LIBSYSCALLS_TYPE_UINT32 ## SUFFIX,, "uint32_t") D\ + X(LIBSYSCALLS_TYPE_INT64 ## SUFFIX,, "int64_t") D\ + X(LIBSYSCALLS_TYPE_UINT64 ## SUFFIX,, "uint64_t") + +#define LIBSYSCALLS_LIST_ANNOTATED_NUMERICALS(X, SUFFIX, D, FIRST)\ + X(LIBSYSCALLS_TYPE_INT_SIGNAL ## SUFFIX, FIRST, "int") D /* OS signal */\ + X(LIBSYSCALLS_TYPE_INT_FD ## SUFFIX,, "int") D /* file descriptor */ \ + X(LIBSYSCALLS_TYPE_INT_ATFD ## SUFFIX,, "int") D /* file descriptor or current working directory */ \ + X(LIBSYSCALLS_TYPE_LONG_FD ## SUFFIX,, "long int") D\ + X(LIBSYSCALLS_TYPE_LONG_ATFD ## SUFFIX,, "long int") + +#define LIBSYSCALLS_LIST_STRUCTS_AND_UNIONS(X, SUFFIX, D, FIRST)\ + X(LIBSYSCALLS_TYPE_STRUCT_AIO_SIGSET ## SUFFIX, FIRST, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_CACHESTAT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_CACHESTAT_RANGE ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_CLONE_ARGS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_EPOLL_EVENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_FILE_HANDLE ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_FUTEX_WAITV ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_IOB ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_IOVEC ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_IO_EVENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_IO_URING_PARAMS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_ITIMERSPEC ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_KEXEC_SEGMENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_LANDLOCK_RULESET_ATTR ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_LINUX_DIRENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_LINUX_DIRENT64 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_MMAP_ARG_STRUCT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_MMSGHDR ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_MOUNT_ATTR ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_MQ_ATTR ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_MSGBUF ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_MSGHDR ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_MSQID_DS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_NEW_UTSNAME ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLDOLD_UTSNAME ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_ITIMERSPEC32 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_ITIMERVAL ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_LINUX_DIRENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_SIGACTION ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_STAT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_TIMESPEC32 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_TIMEVAL ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_TIMEVAL32 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_TIMEX32 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_UTIMBUF32 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OLD_UTSNAME ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OPEN_HOW ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_PERF_EVENT_ATTR ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_POLLFD ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_RLIMIT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_RLIMIT64 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_ROBUST_LIST_HEAD ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_RSEQ ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_RUSAGE ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SCHED_ATTR ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SCHED_PARAM ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SEL_ARG_STRUCT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SEMBUF ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SEMID_DS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SHMID_DS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SIGACTION ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SIGALTSTACK ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SIGEVENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SIGINFO ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SOCKADDR ## SUFFIX,, "struct") D /* size is always in the next argument */\ + X(LIBSYSCALLS_TYPE_STRUCT_STAT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_STAT64 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_STATFS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_STATFS64 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_STATX ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_SYSINFO ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_TIMESPEC ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_TIMEX ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_TIMEZONE ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_TMS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_USTAT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_UTIMBUF ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_UNION_BPF_ATTR ## SUFFIX,, "union") + +#define LIBSYSCALLS_LIST_FIXED_ARRAYS(X, SUFFIX, D, FIRST)\ + X(LIBSYSCALLS_TYPE_2_INTS ## SUFFIX, FIRST, "int[2]") D\ + X(LIBSYSCALLS_TYPE_2_INTS_FD ## SUFFIX,, "int[2]") D\ + X(LIBSYSCALLS_TYPE_2_UINT32S ## SUFFIX,, "uint32[2]") D\ + X(LIBSYSCALLS_TYPE_FD_SET ## SUFFIX,, "unsigned long[]") /* size depends on OS, (1024 / CHAR_BIT / sizeof(long)) in Linux */ + + /* these don't have any suffix */ + LIBSYSCALLS_MAKE_SPECIAL_TYPES_(), + LIBSYSCALLS_MAKE_SPLIT_PRIMITIVES_(), + LIBSYSCALLS_MAKE_COMPOSITE_PRIMITIVES_(), + LIBSYSCALLS_MAKE_UNANNOTATED_NUMERICALS_(), + LIBSYSCALLS_MAKE_ANNOTATED_NUMERICALS_(), + LIBSYSCALLS_MAKE_STRUCTS_AND_UNIONS_(), + + /* the following are always pointers unless returned */ + + /* size in next parameter (or the previous parameter if there is no next parameter), + * updated with fill if possible, otherwise returned (these use the suffix _ARRAY) */ + LIBSYSCALLS_MAKE_UNANNOTATED_NUMERICALS_(_ARRAY), + LIBSYSCALLS_MAKE_ANNOTATED_NUMERICALS_(_ARRAY), + LIBSYSCALLS_MAKE_STRUCTS_AND_UNIONS_(_ARRAY), + + /* size in next parameter (or the previous parameter if there is no next parameter), + * fill is in no way returned (these use the suffix _ARRAY_UNKNOWN_FILL) */ + LIBSYSCALLS_MAKE_UNANNOTATED_NUMERICALS_(_ARRAY_UNKNOWN_FILL), + LIBSYSCALLS_MAKE_ANNOTATED_NUMERICALS_(_ARRAY_UNKNOWN_FILL), + LIBSYSCALLS_MAKE_STRUCTS_AND_UNIONS_(_ARRAY_UNKNOWN_FILL), + + /* these don't have any suffix */ + LIBSYSCALLS_MAKE_FIXED_ARRAYS_() + +#undef LIBSYSCALLS_TYPE_CHAR_ARRAY +#undef LIBSYSCALLS_TYPE_CHAR_ARRAY_UNKNOWN_FILL +}; + +enum libsyscalls_syscall_category { + LIBSYSCALLS_CAT_SUPPORT_PENDING, + LIBSYSCALLS_CAT_NOT_IMPLEMENTED, + LIBSYSCALLS_CAT_NETWORK_ENABLED_IPC, + LIBSYSCALLS_CAT_IPC, + LIBSYSCALLS_CAT_FILESYSTEM, + LIBSYSCALLS_CAT_FILE_DESCRIPTORS, + LIBSYSCALLS_CAT_PROCESSES, + LIBSYSCALLS_CAT_LOGGING, + LIBSYSCALLS_CAT_TIME, + LIBSYSCALLS_CAT_SIGNALS, + LIBSYSCALLS_CAT_MEMORY, + LIBSYSCALLS_CAT_SYSTEM, + LIBSYSCALLS_CAT_SCHEDULING +}; + +/* IPC that can but does not have to be over a network, + * "bind" system calls can create inodes in the file system */ +enum libsyscalls_syscall_network_enabled_ipc_subcategory { + LIBSYSCALLS_NETWORK_ENABLED_IPC_SUBCAT_ACCEPT, + LIBSYSCALLS_NETWORK_ENABLED_IPC_SUBCAT_LISTEN, + LIBSYSCALLS_NETWORK_ENABLED_IPC_SUBCAT_BIND, + LIBSYSCALLS_NETWORK_ENABLED_IPC_SUBCAT_CONNECT, + LIBSYSCALLS_NETWORK_ENABLED_IPC_SUBCAT_STAT +}; + +enum libsyscalls_syscall_ipc_subcategory { + LIBSYSCALLS_IPC_SUBCAT_ADVISORY_FILE_LOCK, + LIBSYSCALLS_IPC_SUBCAT_MANDATORY_FILE_LOCK, + LIBSYSCALLS_IPC_SUBCAT_FILE_LOCK, /* may or may not be advisory (e.g. flock(2) since Linux 5.5) */ + LIBSYSCALLS_IPC_SUBCAT_CONTROL, /* includes creation, deletion, and stat */ + LIBSYSCALLS_IPC_SUBCAT_ATTACH, + LIBSYSCALLS_IPC_SUBCAT_DETACH, + LIBSYSCALLS_IPC_SUBCAT_COMMUNICATE, + LIBSYSCALLS_IPC_SUBCAT_COMMUNICATE_WITH_RELATIVE_TIMEOUT, + LIBSYSCALLS_IPC_SUBCAT_COMMUNICATE_WITH_ABSOLUTE_TIMEOUT +}; + +/* syscalls that can work on either paths or FDs ([1]) are located here */ +enum libsyscalls_syscall_filesystem_subcategory { + LIBSYSCALLS_FILESYSTEM_SUBCAT_STAT, + LIBSYSCALLS_FILESYSTEM_SUBCAT_MODIFY, + LIBSYSCALLS_FILESYSTEM_SUBCAT_SYNC, /* [1] some of these only work on file descriptors or memory maps */ + LIBSYSCALLS_FILESYSTEM_SUBCAT_LINK, + LIBSYSCALLS_FILESYSTEM_SUBCAT_UNLINK, + LIBSYSCALLS_FILESYSTEM_SUBCAT_LINK_OR_UNLINK, + LIBSYSCALLS_FILESYSTEM_SUBCAT_UMASK, /* modifies the process, not the filesystem */ + LIBSYSCALLS_FILESYSTEM_SUBCAT_MOUNTPOINT, + LIBSYSCALLS_FILESYSTEM_SUBCAT_STATFS, + LIBSYSCALLS_FILESYSTEM_SUBCAT_WRITE, + LIBSYSCALLS_FILESYSTEM_SUBCAT_READLINK, + LIBSYSCALLS_FILESYSTEM_SUBCAT_MONITOR, + LIBSYSCALLS_FILESYSTEM_SUBCAT_QUOTA +}; + +/* syscalls that work FDs but not paths are located here */ +enum libsyscalls_syscall_file_descriptors_subcategory { + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_STAT, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_MODIFY, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_DUP_OR_CLOSE, /* includes partial close (shutdown) */ + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_CLOSE_OR_UNSHARE, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_READ, /* may have timeout */ + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_READ_OR_PEEK, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_WRITE, /* may have timeout */ + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_SEEK, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_PEEK, /* may have timeout */ + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_READ_AND_WRITE, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_PEEK_AND_WRITE, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_READ_OR_PEEK_AND_WRITE, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_READ_OR_PEEK_AND_STAT, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_ADVISE, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_STATFS, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_CREATE, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_CREATE_POLL, + LIBSYSCALLS_FILE_DESCRIPTORS_SUBCAT_POLL /* can work as pause or relative sleep */ +}; + +enum libsyscalls_syscall_processes_subcategory { + LIBSYSCALLS_PROCESSES_SUBCAT_EXIT, + LIBSYSCALLS_PROCESSES_SUBCAT_STAT_SELF, + LIBSYSCALLS_PROCESSES_SUBCAT_STAT_CHILD, /* may also stat self */ + LIBSYSCALLS_PROCESSES_SUBCAT_STAT_PARENT, /* may also stat self or children */ + LIBSYSCALLS_PROCESSES_SUBCAT_STAT_OTHER, + LIBSYSCALLS_PROCESSES_SUBCAT_CHANGE_PERMISSIONS, + LIBSYSCALLS_PROCESSES_SUBCAT_CLONE, + LIBSYSCALLS_PROCESSES_SUBCAT_EXEC, + LIBSYSCALLS_PROCESSES_SUBCAT_CHDIR, + LIBSYSCALLS_PROCESSES_SUBCAT_CHROOT, + LIBSYSCALLS_PROCESSES_SUBCAT_SESSION /* vhangup, setsid, setpgid */ +}; + +enum libsyscalls_syscall_logging_subcategory { + LIBSYSCALLS_LOGGING_SUBCAT_PROCESSES +}; + +enum libsyscalls_syscall_time_subcategory { + LIBSYSCALLS_TIME_SUBCAT_GET_OR_SET, + LIBSYSCALLS_TIME_SUBCAT_GET, + LIBSYSCALLS_TIME_SUBCAT_SET, + LIBSYSCALLS_TIME_SUBCAT_INTROSPECT, + LIBSYSCALLS_TIME_SUBCAT_TIMER_RELATIVE, + LIBSYSCALLS_TIME_SUBCAT_TIMER_ABSOLUTE, + LIBSYSCALLS_TIME_SUBCAT_TIMER, + LIBSYSCALLS_TIME_SUBCAT_TIMER_RELATIVE_READ, + LIBSYSCALLS_TIME_SUBCAT_TIMER_ABSOLUTE_READ, + LIBSYSCALLS_TIME_SUBCAT_TIMER_READ, + LIBSYSCALLS_TIME_SUBCAT_TIMER_RELATIVE_WITH_READ, + LIBSYSCALLS_TIME_SUBCAT_TIMER_ABSOLUTE_WITH_READ, + LIBSYSCALLS_TIME_SUBCAT_TIMER_WITH_READ, + LIBSYSCALLS_TIME_SUBCAT_SLEEP_RELATIVE, + LIBSYSCALLS_TIME_SUBCAT_SLEEP_ABSOLUTE, + LIBSYSCALLS_TIME_SUBCAT_SLEEP +}; + +enum libsyscalls_syscall_signals_subcategory { + LIBSYSCALLS_SIGNALS_SUBCAT_PAUSE, + LIBSYSCALLS_SIGNALS_SUBCAT_KILL +}; + +/* These may work on memory mapped files */ +enum libsyscalls_syscall_memory_subcategory { + LIBSYSCALLS_MEMORY_SUBCAT_ALLOCATE, + LIBSYSCALLS_MEMORY_SUBCAT_READ, + LIBSYSCALLS_MEMORY_SUBCAT_WRITE, + LIBSYSCALLS_MEMORY_SUBCAT_ADVISE, + LIBSYSCALLS_MEMORY_SUBCAT_WRITE_OR_ADVISE, + LIBSYSCALLS_MEMORY_SUBCAT_LOCK, + LIBSYSCALLS_MEMORY_SUBCAT_UNLOCK, + LIBSYSCALLS_MEMORY_SUBCAT_STAT /* stats memory allocated to the process, not system resources */ +}; + +enum libsyscalls_syscall_system_subcategory { + LIBSYSCALLS_SYSTEM_SUBCAT_SWAP, + LIBSYSCALLS_SYSTEM_SUBCAT_REBOOT, + LIBSYSCALLS_SYSTEM_SUBCAT_GET_NAME, + LIBSYSCALLS_SYSTEM_SUBCAT_SET_NAME, + LIBSYSCALLS_SYSTEM_SUBCAT_STAT, + LIBSYSCALLS_SYSTEM_SUBCAT_RANDOM, + LIBSYSCALLS_SYSTEM_SUBCAT_FUNDAMENTAL +}; + +enum libsyscalls_syscall_scheduling_subcategory { + LIBSYSCALLS_SCHEDULING_SUBCAT_YEILD, + LIBSYSCALLS_SCHEDULING_SUBCAT_SET, + LIBSYSCALLS_SCHEDULING_SUBCAT_GET, + LIBSYSCALLS_SCHEDULING_SUBCAT_INTROSPECT +}; + +union libsyscalls_syscall_subcategory { + enum_libsyscalls_syscall_network_enabled_ipc_subcategory network_enabled_ipc; + enum_libsyscalls_syscall_ipc_subcategory ipc; + enum_libsyscalls_syscall_filesystem_subcategory filesystem; + enum_libsyscalls_syscall_file_descriptors_subcategory file_descriptors; + enum_libsyscalls_syscall_processes_subcategory processes; + enum_libsyscalls_syscall_logging_subcategory logging; + enum_libsyscalls_syscall_time_subcategory time; + enum_libsyscalls_syscall_signals_subcategory signals; + enum_libsyscalls_syscall_memory_subcategory memory; + enum_libsyscalls_syscall_system_subcategory system; + enum_libsyscalls_syscall_scheduling_subcategory scheduling; +}; + +/** + * System call interface + */ +struct libsyscalls_syscall_abi { + /** + * Classification of what the system call does + * + * Check `.category` to se which group of + * classifications to used + */ + union libsyscalls_syscall_subcategory subcategory; + + /** + * Broad classification of what the system calls does + */ + enum_libsyscalls_syscall_category category : 16; + + /** + * For set any bit indexed I (starting from 0), the + * system call parameter I is a pointer that the + * the system call reads from + * + * Note that there are types that fundamentally are + * pointers (such as strings), for these, this bit + * is not set unless it is a pointer to a string + */ + unsigned short int in_pointer_mask : 16; + + /** + * For set any bit indexed I (starting from 0), the + * system call parameter I is a pointer that the + * the system call write to + * + * Note that there are types that fundamentally are + * pointers (such as strings), for these, this bit + * is not set unless it is a pointer to a string + */ + unsigned short int out_pointer_mask : 16; + + /** + * For set any bit indexed I (starting from 0), the + * system call parameter I can be resolved into a + * symbolic string by the library + */ + unsigned short int symbolic_mask : 16; + + /** + * The minimum number of arguments that must be + * passed into the system call, -1 if unknown + */ + short int min_argument_count : 6; + + /** + * The maximum number of arguments that can be + * passed into the system call, -1 if unknown + */ + short int max_argument_count : 6; + + /** + * If set, the library can resolve the value the + * system call returns into a symbolic string + */ + unsigned short int symbolic_return : 1; + + /** + * If 1, the system call shall always either return + * an error, return the value 0, or not return at all + */ + unsigned short int expect_zero : 1; + + /** + * If 1, the system call invocation must be parsed + * especially as it is not does follow what is + * proscribed for the used data types + * + * The library may use this temporarily until it + * in a later version provides a convension that + * can be followed + */ + unsigned short int queer : 1; + + short int : LIBSYSCALLS_PAD_(sizeof(short int)/sizeof(char)*CHAR_BIT, 4*16 + 2*6 + 3*1); + + /** + * This is internally by `libsyscalls_get_syscall_display_info` + * to find out how values ought to be printed to be both human + * and machines friendly (symbolic names are indeed easier for + * the application to deal with as their values can depend on + * the architecture), and occasionally to determine what types + * are used for on arguments whose type is argument dependent, + * and to figure which optional arguments are included in the + * system call + * + * If this is value is 0, `libsyscalls_get_syscall_display_info` + * will not be able to provide any useful information, which + * would either be because everything is provided here (in + * struct libsyscalls_syscall_abi) or because the library hasn't + * yet added full support for the system call + */ + LIBSYSCALLS_SYMBOL_PRINTER symbol_printer : 16; + + /** + * The system call's return type + */ + enum_libsyscalls_datatype return_type : 16; + + /** + * The type of each of the systems call's parameter + * + * The application must not read `.parameters_types[.max_argument_count]` + * or beyond, doing so will probably mean reading beyond the memory + * allocated for the instance of the structure + */ + enum_libsyscalls_datatype parameters_types[LIBSYSCALLS_FLEXABLE_OR_NPARAMS_]; +}; + +/** + * System call description + */ +struct libsyscalls_syscall { + /** + * What system call is named + */ + const char *name; + + /** + * The ABI for the system call for architecture it was + * queried for + * + * May or may not be `NULL` if the system call is defined + * but not implemented + */ + struct libsyscalls_syscall_abi *actual_syscall; + + /** + * Like .actual_syscall except this is used for example when + * a 32-bit process is running on a 64-bit operating system + * + * If `NULL` use .actual_syscall + */ + struct libsyscalls_syscall_abi *actual_compat_syscall; +}; + +/** + * Named number (errors and signals) + */ +struct libsyscalls_named_number { + /** + * The value if the number, it is up to the + * application select signess + * + * It is usually safe to use unsigned (.u) + * as the numbers are usually positive but + * not so large that the sign bit would be + * set, unless the numbers are supposted to + * be unsigned + */ + union { + signed long long int s; + unsigned long long int u; + } number; + + /** + * The name of the number, including namespacing + * (e.g. "E" prefix for errno numbers and "SIG" + * or "_SIG" prefix for singals) + */ + const char *name; +}; + +/** + * Function that returns a name for a value + * + * This function is called multiple times to extract + * names of multiple subvalues, for example, for + * the system call access() second parameter, it + * will return the string "X_OK", "W_OK", "R_OK", + * and "F_OK", or a subset thereof; one per invocation + * + * The proper way to use this function, is: + * + * static void + * print_unsigned(libsyscalls_symbol_printer_function *function, + * LIBSYSCALLS_SYMBOL_PRINTER_DATA *data, + * unsigned long long int value, FILE *output) + * { + * const char *sym, *prefix = ""; + * char format[] = "%s%llu"; + * char *fallback = strchr(format, '\0') - 1; + * do { + * sym = (*function)(data, &value, &fallback); + * if (!sym) + * break; + * fprintf(output, "%s%s", prefix, sym); + * prefix = "|"; + * } while (value); + * if (value || !*prefix) + * fprintf(output, format, prefix, value); + * } + * + * @param data Data passed to the function (which that function + * has been paired with for the paramter/return), + * which it may require to known exactly what to do + * @param valuep The caller set a variable to the value pass in to + * the system call parameter (or the system call's + * return value), the value if any extract symbol + * will removed from from the variable. If the function + * return NULL, this value can be 0, in which case all + * values have been extract, otherwise (which it is not + * 0) there is some value (either invalid or not known + * to the library) that shall must be printed manually + * by the application (see `fallback_out` parameter). + * Note that, if the value 0 has a name, this function + * never return NULL if the variable reaches 0, instead + * it will repeated return the name of that value. + * @param fallback_out The caller set a variable to 0 and pointer to it, + * when this function return NULL, the variable MAY + * (even before that) have been set to 'x', 'o', or + * 'd', indicating a suggestion how any value left + * over in `*valuep` shall be displayed: 'x' for in + * hexadecimal, 'o' for octal, and 'd' for decimal + * (signness depends on the system call parameter's + * type's (or as the case may be, the system call's + * return type) signness). + * @return The name of some value in `*valuep`, or `NULL` if + * 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 *); + +/** + * Information about a system call parameter or return value + */ +struct libsyscalls_syscall_type_info { + /** + * Function for extracting names values from a variable + */ + libsyscalls_symbol_printer_function *function; + + /** + * First argument to pass to `.function` + */ + LIBSYSCALLS_SYMBOL_PRINTER_DATA *data; + + /** + * The data type used for the parameter or return value + * in the specific invocation of the system call + * + * If set to LIBSYSCALLS_TYPE_VOID for an optional + * parameter, that parameter was not used + */ + enum_libsyscalls_datatype type; + + char padding__[LIBSYSCALLS_PAD_(sizeof(long) / sizeof(char), sizeof(enum_libsyscalls_datatype) / sizeof(char) + 1)]; + unsigned char : CHAR_BIT - 1; + + /** + * Only used for the return value + * + * Same as `.expect_zero` in `struct libsyscalls_syscall_abi`, + * however if 0 in `struct libsyscalls_syscall_abi`, it can + * still be 1 here if if it is determined that for the specificly + * used system call arguments, the system call shall always + * return 0 (or not return) or an error + */ + unsigned char expect_zero : 1; +}; + +/** + * 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 + */ +struct libsyscalls_syscall_display_info { + /** + * The size of this structure, this can be used + * by the application to test what is available + * in the case it may have compiled against a + * newer version than used in the version of the + * library the application is linked with + * + * Data is stored beyond this, do not try to make + * a copy; that will not go well + */ + size_t size; + + /** + * Information about each system call parameter + * + * All positive integer within [0, .max_argument_count] + * for the `struct libsyscalls_syscall_abi` are valid, + * but no index beyond `.max_argument_count` is valid + */ + struct libsyscalls_syscall_type_info *params; + + /** + * Information about the system call's return value + */ + struct libsyscalls_syscall_type_info *retvalue; +}; + +/** + * Signed number representation + */ +enum libsyscalls_datatype_sign_representation { + /** + * The data type was LIBSYSCALLS_TYPE_UNKNOWN or + * LIBSYSCALLS_TYPE_DYNAMIC + */ + LIBSYSCALLS_SIGN_UNDETERMINED, + + /** + * Two's complement + * + * -x is ~x + 1, -0 is +0 + */ + LIBSYSCALLS_SIGN_TWOS_COMPLEMENT, + + /** + * One's cmplement + * + * -x is ~x, -0 is not +0 + */ + LIBSYSCALLS_SIGN_ONES_COMPLEMENT, + + /** + * Sign–magnitude + * + * -x is (x | most significant bit), -0 is not +0 + */ + LIBSYSCALLS_SIGN_SIGN_MAGNITUDE, + + /** + * Excess-K, with K being (unsigned maximum + 1)/2 + * + * 0 is represented with just the most significant bit set, + * any offset from 0 is added to this value, i.e., x is + * represented by ((unsigned maximum + 1)/2 + x); -0 is +0 + */ + LIBSYSCALLS_SIGN_EXCESS_HALF +}; + +/** + * Data type usage annotation + */ +enum libsyscalls_datatype_annotation { + /** + * The data type was LIBSYSCALLS_TYPE_UNKNOWN or + * LIBSYSCALLS_TYPE_DYNAMIC + */ + LIBSYSCALLS_ANNOTATION_UNDETERMINED, + + /** + * The value does not have usage annotation + */ + LIBSYSCALLS_ANNOTATION_NONE, + + /** + * 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) + */ + 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) + */ + LIBSYSCALLS_ANNOTATION_FD, + + /** + * 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) + */ + LIBSYSCALLS_ANNOTATION_ATFD +}; + +/** + * Register-split information for a data type + */ +enum libsyscalls_datatype_section { + /** + * The data type was LIBSYSCALLS_TYPE_UNKNOWN or + * LIBSYSCALLS_TYPE_DYNAMIC + */ + LIBSYSCALLS_SECTION_UNDETERMINED, + + /** + * The whole value is represented + * + * The value is contained within a single parameter + */ + 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 + */ +#define LIBSYSCALLS_IS_SECTION_HALF(S)\ + (((S) >= LIBSYSCALLS_SECTION_UPPER_HALF) &&\ + ((S) <= LIBSYSCALLS_SECTION_ODD_BYTES_AS_HALF)) + + /** + * The most significant half of the value is represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 32-bits — + * 0xFFFFFFFF00000000 if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with another neighbouring parameter + * (a LIBSYSCALLS_SECTION_LOWER_HALF) + */ + LIBSYSCALLS_SECTION_UPPER_HALF, + + /** + * The least significant half of the value is represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 32-bits — + * 0x00000000FFFFFFFF if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with another neighbouring parameter + * (a LIBSYSCALLS_SECTION_UPPER_HALF) + */ + LIBSYSCALLS_SECTION_LOWER_HALF, + + /** + * The second most and second least significant quarters + * of the value represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 32-bits — + * 0x0000FFFFFFFF0000 if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with another neighbouring parameter + * (a LIBSYSCALLS_SECTION_OUTER_HALF) + */ + LIBSYSCALLS_SECTION_INNER_HALF, + + /** + * The most and least significant quarters of the value + * represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 32-bits — + * 0xFFFF00000000FFFF if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with another neighbouring parameter + * (a LIBSYSCALLS_SECTION_INNER_HALF) + */ + LIBSYSCALLS_SECTION_OUTER_HALF, + + /** + * The second most and least significant quarters of the + * value represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 32-bits — + * 0x0000FFFF0000FFFF if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with another neighbouring parameter + * (a LIBSYSCALLS_SECTION_ODD_QUARTERS_AS_HALF) + */ + LIBSYSCALLS_SECTION_EVEN_QUARTERS_AS_HALF, + + /** + * The most and second least significant quarters of the + * value represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 32-bits — + * 0xFFFF0000FFFF0000 if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with another neighbouring parameter + * (a LIBSYSCALLS_SECTION_EVEN_QUARTERS_AS_HALF) + */ + LIBSYSCALLS_SECTION_ODD_QUARTERS_AS_HALF, + + /** + * The bytes that would be indexed (starting from 0) with + * an even number in big endian (how humans write numbers) + * are represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 32-bits — + * 0x00FF00FF00FF00FF if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with another neighbouring parameter + * (a LIBSYSCALLS_SECTION_EVEN_BYTES_AS_HALF) + */ + LIBSYSCALLS_SECTION_EVEN_BYTES_AS_HALF, + + /** + * The bytes that would be indexed (starting from 0) with + * an odd number in big endian (how humans write numbers) + * are represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 32-bits — + * 0xFF00FF00FF00FF00 if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with another neighbouring parameter + * (a LIBSYSCALLS_SECTION_ODD_BYTES_AS_HALF) + */ + 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 + */ +#define LIBSYSCALLS_IS_SECTION_QUARTER(S)\ + (((S) >= LIBSYSCALLS_SECTION_UPPER_QUARTER) &&\ + ((S) <= LIBSYSCALLS_SECTION_LOWER_QUARTER)) + + /** + * The most significant quarter of the value is represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 16-bits — + * 0xFFFF000000000000 if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with three neighbouring parameter + * (a LIBSYSCALLS_SECTION_UPPER_MID_QUARTER, + * a LIBSYSCALLS_SECTION_LOWER_MID_QUARTER, and + * a LIBSYSCALLS_SECTION_LOWER_QUARTER) + */ + LIBSYSCALLS_SECTION_UPPER_QUARTER, + + /** + * The second most significant quarter of the value is represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 16-bits — + * 0x0000FFFF00000000 if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with three neighbouring parameter + * (a LIBSYSCALLS_SECTION_UPPER_QUARTER, + * a LIBSYSCALLS_SECTION_LOWER_MID_QUARTER, and + * a LIBSYSCALLS_SECTION_LOWER_QUARTER) + */ + LIBSYSCALLS_SECTION_UPPER_MID_QUARTER, + + /** + * The least most significant quarter of the value is represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 16-bits — + * 0x00000000FFFF0000 if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with three neighbouring parameter + * (a LIBSYSCALLS_SECTION_UPPER_QUARTER, + * a LIBSYSCALLS_SECTION_UPPER_MID_QUARTER, and + * a LIBSYSCALLS_SECTION_LOWER_QUARTER) + */ + LIBSYSCALLS_SECTION_LOWER_MID_QUARTER, + + /** + * The least significant quarter of the value is represented + * + * Example: if the data type is 64-bits, the value stored + * in parameter whose type was queried is just 16-bits — + * 0x000000000000FFFF if the whole value is 0xFFFFFFFFFFFFFFFF, + * — and most combined with three neighbouring parameter + * (a LIBSYSCALLS_SECTION_UPPER_QUARTER, + * a LIBSYSCALLS_SECTION_UPPER_MID_QUARTER, and + * a LIBSYSCALLS_SECTION_LOWER_MID_QUARTER) + */ + LIBSYSCALLS_SECTION_LOWER_QUARTER + + /* + * Get the number of registers the data type was split into + * + * @param S:enum libsyscalls_datatype_section The data type section information + * @return :unsigned int The number registers 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) +}; + +/** + * Information on how an instance of data type is to be parsed + * + * Data types are usually either signed or unsigned, but there + * are a few exceptions: LIBSYSCALLS_TYPE_UNKNOWN and + * LIBSYSCALLS_TYPE_DYNAMIC are described as both signed and + * unsigned as their signness is unknown and could be either, + * or neither, which brings us to the next exception: some + * data types are neither signed nor unsigned; these are types + * that are not numerical, i.e. non-values (LIBSYSCALLS_TYPE_NO_RETURN + * and LIBSYSCALLS_TYPE_VOID), memory addresses + * (LIBSYSCALLS_TYPE_MEMORY_ADDRESS) and textual types + * (LIBSYSCALLS_TYPE_CHAR, LIBSYSCALLS_TYPE_STRING, and + * LIBSYSCALLS_TYPE_STRINGS_THEN_NULL), as well as arrays of + * such types (including LIBSYSCALLS_TYPE_BUFFER and + * LIBSYSCALLS_TYPE_BUFFER_UNKNOWN_FILL), and finally bitset + * arrays (currently only LIBSYSCALLS_TYPE_FD_SET) + */ +struct libsyscalls_datatype_description { + /** + * The number of bits used for the represented section + * of the data type + * + * 0 for LIBSYSCALLS_TYPE_NO_RETURN and LIBSYSCALLS_TYPE_VOID + * + * if .section is LIBSYSCALLS_SECTION_WHOLE, this is the + * number of bits in the entire data type, otherwise the data + * type may have been split (LIBSYSCALLS_SECTION_UNDETERMINED, + * guaranteed to be split otherwise) and this value is just + * the number of bits stored in the register + */ + unsigned width_in_bits; + + /** + * The size (in number of elements) of the array the data type + * is used in, or 1 if the data type was not an array or + * 0 if the array size is determined by another parameter + */ + unsigned array_size; + + /** + * Only used if .array_size is 0 + * + * The position of the arrays size in the parameter list + * relative to the array, e.g. 1 for the next parameter + * or -1 for the previous parameter + * + * If 0, use .absolute_position_of_array_size instead + */ + signed relative_position_of_array_size : 5; + + /** + * Only used if .array_size is 0 + * + * The position of the arrays size in the parameter list, + * indexed starting from 0 + * + * If -1, use .relative_position_of_array_size instead + */ + signed absolute_position_of_array_size : 5; + + /** + * Only used if .array_size is 0 + * + * Assuming the kernel writes into the array, if 1, the number + * of elements written to the array (starting from its + * beginning) is writting into the array size parameter if it + * is marked as an output parameter and return otherwise; if + * 0, the number of bits written must be infered from its + * contents, e.g. via null byte termination (how this is done + * depends on the system call) + */ + unsigned fill_is_known : 1; + + /** + * Whether the data type is signed + */ + unsigned is_signed : 1; + + /** + * Whether the data type is unsigned + */ + unsigned is_unsigned : 1; + + /** + * Only used if .is_signed is 1 and .sign_representation + * is not LIBSYSCALLS_SIGN_UNDETERMINED + * + * This value can be inferred from .sign_representation; + * its 1 if the data type's minimum value is the negative + * of its maximum value (which also means that -0 and +0 + * are distinct), and 0 otherwise, which means that the + * minimum value is the negative of (the minimum value + 1) + * (it also means that -0 and +0 are the identical) + */ + unsigned min_is_minus_max : 1; + + int padding__ : LIBSYSCALLS_PAD_(sizeof(int)/sizeof(char)*CHAR_BIT, 2*5 + 4*1); + + /** + * Only used if .is_signed is 1 + * + * How signed numbers are represented + */ + enum libsyscalls_datatype_sign_representation sign_representation; + + /** + * Additional information about what the value represents + */ + enum libsyscalls_datatype_annotation annotation; + + /** + * What part of the value is stored in the instance + */ + enum libsyscalls_datatype_section section; + + /** + * This is a ~0 terminated array describing the order + * of the bytes the the data type + * + * The lowest non-zero values contains the width of + * a byte (in bytes), however no such value exists + * in this array if the data type is just one byte + * (or none) + * + * For each unsigned byte in the data type, indexed + * I from 0, it shall be shifted left .byteorder[i] + * bits; the bitwise OR of the results is the + * unsigned value used in the instance of the data type + * + * Data types for register-splits ARE NOT shifted, + * there is always a value in .byteorder that is 0, + * unless .byteorder[0] is ~0 + */ + unsigned char byteorder[32]; +}; + + +/** + * Return a description of a libsyscalls error + * + * @param error The libsyscalls error + * @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); + +/** + * Print a line with a description of a + * libsyscalls error to standard error + * + * @param prefix Unless NULL or the empty string, the description + * will be prefixed with this string followed by ": " + * @param error The libsyscalls error + */ +void +libsyscalls_perror(const char *, enum libsyscalls_error); + +/** + * 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`) + * + * Beware that range is used system call numbers are [*min_out, *max_out] + * (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__) +enum libsyscalls_error +libsyscalls_get_syscall_range(enum libsyscalls_os, enum libsyscalls_arch, long long int *, long long int *); + +/** + * 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`) + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +enum libsyscalls_error +libsyscalls_get_syscall(enum libsyscalls_os, enum libsyscalls_arch, long long int, const struct libsyscalls_syscall **); + +/** + * Get the system call errors defined by an operating system + * + * If an error has multiple names, it is only listed once + * and the listed name is arbitrary + * + * 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) + * @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 + */ +enum libsyscalls_error +libsyscalls_get_syscall_errors(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_named_number **, size_t *); + +/** + * Get the system signals defined by an operating system + * + * If a signal has multiple names, it is only listed once + * and the listed name is arbitrary + * + * 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) + * @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 + */ +enum libsyscalls_error +libsyscalls_get_signals(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_named_number **, size_t *); + +/** + * 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 + * @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__) +enum libsyscalls_error +libsyscalls_get_syscall_display_info(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_syscall_abi *, + long long int, unsigned long long int *, struct libsyscalls_syscall_display_info **); + +/** + * Get information on how an instance of data type is to be parsed + * + * @param os The operating system the data type is used on + * @param arch The architecture the data type is used on + * @param datatype The datatype, `LIBSYSCALLS_TYPE_DYNAMIC` can + * 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 + * + * 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__) +enum libsyscalls_error +libsyscalls_get_datatype_description(enum libsyscalls_os, enum libsyscalls_arch, enum libsyscalls_datatype, + struct libsyscalls_datatype_description *); + + +#include "libsyscalls/internal-end.h" +#endif diff --git a/libsyscalls/advanced.h b/libsyscalls/advanced.h new file mode 100644 index 0000000..22ed3d0 --- /dev/null +++ b/libsyscalls/advanced.h @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBSYSCALLS_H +# error Do not include this header file directly +#endif + + +#define LIBSYSCALLS_TYPEOFFSET_SPECIAL_TYPES 0 /* does not use LIBSYSCALLS_TYPEBITSMASK */ +#define LIBSYSCALLS_TYPEOFFSET_SPLIT_PRIMITIVES 8 +#define LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES 48 +#define LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS 64 +#define LIBSYSCALLS_TYPEOFFSET_ANNOTATED_NUMERICALS 256 +#define LIBSYSCALLS_TYPEOFFSET_FIXED_ARRAYS 512 +#define LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS 1024 diff --git a/libsyscalls/internal-begin.h b/libsyscalls/internal-begin.h new file mode 100644 index 0000000..9741632 --- /dev/null +++ b/libsyscalls/internal-begin.h @@ -0,0 +1,76 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBSYSCALLS_H +# error Do not include this header file directly +#endif + + +#include <limits.h> +#include <stddef.h> + +/* a comma possible into a macro */ +#define LIBSYSCALLS_COMMA_ , + +/* used to make flexible arrays non-flexible if required for static instantiation */ +#ifndef LIBSYSCALLS_FLEXABLE_OR_NPARAMS_ +# define LIBSYSCALLS_FLEXABLE_OR_NPARAMS_ +#endif + +#if defined(__GNUC__) +# define LIBSYSCALLS_GCC_ATTRIBUTES_(...) __attribute__((__VA_ARGS__)) +#else +# define LIBSYSCALLS_GCC_ATTRIBUTES_(...) +#endif + +#define LIBSYSCALLS_PAD_(WANT, HAVE) (((WANT) - (HAVE) % (WANT)) % (WANT)) + + +/** + * Opaque type for symbol printer function identification + */ +typedef unsigned short int LIBSYSCALLS_SYMBOL_PRINTER; + +/** + * Opaque type for symbol printer function parameters + */ +typedef struct libsyscalls_symbol_printer_data LIBSYSCALLS_SYMBOL_PRINTER_DATA; + + +#define LIBSYSCALLS_LIST_ERRORS_X_(ENUM, STR) ENUM + +#define LIBSYSCALLS_DATATYPE_X_(NAME, ASSIGNMENT, ...) NAME ASSIGNMENT + +#define LIBSYSCALLS_TYPEBITS LIBSYSCALLS_TYPEBITS_SCALAR + +#define LIBSYSCALLS_MAKE_SPECIAL_TYPES_()\ + LIBSYSCALLS_LIST_SPECIAL_TYPES(LIBSYSCALLS_DATATYPE_X_,, LIBSYSCALLS_COMMA_,\ + = LIBSYSCALLS_TYPEOFFSET_SPECIAL_TYPES) + +#define LIBSYSCALLS_MAKE_SPLIT_PRIMITIVES_(SUFFIX)\ + LIBSYSCALLS_LIST_SPLIT_PRIMITIVES(LIBSYSCALLS_DATATYPE_X_, SUFFIX, LIBSYSCALLS_COMMA_,\ + = LIBSYSCALLS_TYPEOFFSET_SPLIT_PRIMITIVES\ + | LIBSYSCALLS_TYPEBITS##SUFFIX) + +#define LIBSYSCALLS_MAKE_COMPOSITE_PRIMITIVES_(SUFFIX)\ + LIBSYSCALLS_LIST_COMPOSITE_PRIMITIVES(LIBSYSCALLS_DATATYPE_X_, SUFFIX, LIBSYSCALLS_COMMA_,\ + = LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES\ + | LIBSYSCALLS_TYPEBITS##SUFFIX) + +#define LIBSYSCALLS_MAKE_UNANNOTATED_NUMERICALS_(SUFFIX)\ + LIBSYSCALLS_LIST_UNANNOTATED_NUMERICALS(LIBSYSCALLS_DATATYPE_X_, SUFFIX, LIBSYSCALLS_COMMA_,\ + = LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS\ + | LIBSYSCALLS_TYPEBITS##SUFFIX) + +#define LIBSYSCALLS_MAKE_ANNOTATED_NUMERICALS_(SUFFIX)\ + LIBSYSCALLS_LIST_ANNOTATED_NUMERICALS(LIBSYSCALLS_DATATYPE_X_, SUFFIX, LIBSYSCALLS_COMMA_,\ + = LIBSYSCALLS_TYPEOFFSET_ANNOTATED_NUMERICALS\ + | LIBSYSCALLS_TYPEBITS##SUFFIX) + +#define LIBSYSCALLS_MAKE_STRUCTS_AND_UNIONS_(SUFFIX)\ + LIBSYSCALLS_LIST_STRUCTS_AND_UNIONS(LIBSYSCALLS_DATATYPE_X_, SUFFIX, LIBSYSCALLS_COMMA_,\ + = LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS\ + | LIBSYSCALLS_TYPEBITS##SUFFIX) + +#define LIBSYSCALLS_MAKE_FIXED_ARRAYS_(SUFFIX)\ + LIBSYSCALLS_LIST_FIXED_ARRAYS(LIBSYSCALLS_DATATYPE_X_, SUFFIX, LIBSYSCALLS_COMMA_,\ + = LIBSYSCALLS_TYPEOFFSET_FIXED_ARRAYS\ + | LIBSYSCALLS_TYPEBITS##SUFFIX) diff --git a/libsyscalls/internal-end.h b/libsyscalls/internal-end.h new file mode 100644 index 0000000..ed7af58 --- /dev/null +++ b/libsyscalls/internal-end.h @@ -0,0 +1,21 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBSYSCALLS_H +# error Do not include this header file directly +#endif + + +#undef LIBSYSCALLS_COMMA_ +#undef LIBSYSCALLS_FLEXABLE_OR_NPARAMS_ +#undef LIBSYSCALLS_GCC_ATTRIBUTES_ +#undef LIBSYSCALLS_PAD_ + +#undef LIBSYSCALLS_LIST_ERRORS_X_ +#undef LIBSYSCALLS_DATATYPE_X_ +#undef LIBSYSCALLS_TYPEBITS +#undef LIBSYSCALLS_MAKE_SPECIAL_TYPES_ +#undef LIBSYSCALLS_MAKE_SPLIT_PRIMITIVES_ +#undef LIBSYSCALLS_MAKE_COMPOSITE_PRIMITIVES_ +#undef LIBSYSCALLS_MAKE_UNANNOTATED_NUMERICALS_ +#undef LIBSYSCALLS_MAKE_ANNOTATED_NUMERICALS_ +#undef LIBSYSCALLS_MAKE_STRUCTS_AND_UNIONS_ +#undef LIBSYSCALLS_MAKE_FIXED_ARRAYS_ diff --git a/libsyscalls_get_datatype_description.c b/libsyscalls_get_datatype_description.c new file mode 100644 index 0000000..1a4cb59 --- /dev/null +++ b/libsyscalls_get_datatype_description.c @@ -0,0 +1,418 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#include <stdlib.h> +#include <string.h> + + +#define COUNT_(...) 1 +#define COUNT(LIST_MACRO) (LIST_MACRO(COUNT_,, +,)) + +enum endian { + Big, + Little, +}; + +#define LIST_ARCH_SPECS(X, D) /* byte intptr size_t endian sign */\ + /* + X(LIBSYSCALLS_ARCH_ALPHA, 8, 64, 64, TODO(bi), TWOS_COMPLEMENT) D\ + */\ + X(LIBSYSCALLS_ARCH_AMD64, 8, 64, 64, Little, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_AMD64_X32, 8, 32, 32, Little, TWOS_COMPLEMENT) D /* amd64, 32-bit convesion*/\ + /* + X(LIBSYSCALLS_ARCH_ARM_OABI, 8, TODO, TODO, TODO(bi), TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_ARM_EABI, 8, TODO, TODO, TODO(bi), TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_IA64, 8, 64, 64, TODO, TWOS_COMPLEMENT) D\ + */\ + X(LIBSYSCALLS_ARCH_M68K, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + /* + X(LIBSYSCALLS_ARCH_MICROBLAZE, 8, TODO, TODO, TODO, TODO) D\ + X(LIBSYSCALLS_ARCH_MIPS_O32, 8, 32, 32, TODO(bi), TWOS_COMPLEMENT) D /* mips32 * /\ + X(LIBSYSCALLS_ARCH_MIPS_N32, 8, 32, 32, TODO(bi), TWOS_COMPLEMENT) D /* mips64, 32-bit convention * /\ + X(LIBSYSCALLS_ARCH_MIPS_N64, 8, 64, 64, TODO(bi), TWOS_COMPLEMENT) D /* mips64 * /\ + */\ + X(LIBSYSCALLS_ARCH_PARISC_32, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + X(LIBSYSCALLS_ARCH_PARISC_64, 8, 64, 64, Big, TWOS_COMPLEMENT) D\ + /* + X(LIBSYSCALLS_ARCH_POWERPC_32, 8, 32, 32, TODO(bi), TODO) D\ + X(LIBSYSCALLS_ARCH_POWERPC_64, 8, 64, 64, TODO(bi), TODO) D\ + X(LIBSYSCALLS_ARCH_POWERPC_NOSPU, 8, 64, 64, TODO(bi), TODO) D\ + X(LIBSYSCALLS_ARCH_POWERPC_SPU, 8, 64, 64, TODO(bi), TODO) D\ + X(LIBSYSCALLS_ARCH_S390_32, 8, 32, 32, Big, TODO) D\ + X(LIBSYSCALLS_ARCH_S390_64, 8, 64, 64, Big, TODO) D\ + X(LIBSYSCALLS_ARCH_SH, 8, 32, 32, TODO(bi), TODO) D /* not sh-5 * /\ + */\ + X(LIBSYSCALLS_ARCH_SPARC_32, 8, 32, 32, Big, TWOS_COMPLEMENT) D\ + /* + X(LIBSYSCALLS_ARCH_SPARC_64, 8, 64, 64, TODO(bi), TWOS_COMPLEMENT) D\ + */\ + X(LIBSYSCALLS_ARCH_I386, 8, 32, 32, Little, TWOS_COMPLEMENT) D\ + /* + X(LIBSYSCALLS_ARCH_XTENSA, 8, 32, 32, TODO, TODO) + */ + /* Don't forget to update SUPPORTED_ARCHES in Makefile */ + + +#include "generated/types.c" + +enum libsyscalls_error +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; + enum libsyscalls_error r; + unsigned class; + int half = 0; + enum endian endian; + size_t i, j, charbits; + int divide_array_size_with_type_size_out; + + if (!description_out) + description_out = &description_discard; + + if (datatype & ~(LIBSYSCALLS_TYPEBITSMASK | (LIBSYSCALLS_TYPEBITSMASK - 1))) + return LIBSYSCALLS_E_INVAL; + + datatype ^= class = datatype & LIBSYSCALLS_TYPEBITSMASK; + + if (class == LIBSYSCALLS_TYPEBITS_SCALAR) { + description_out->array_size = 1; + description_out->relative_position_of_array_size = 0; + description_out->absolute_position_of_array_size = -1; + description_out->fill_is_known = 1; + description_out->is_signed = 0; + description_out->is_unsigned = 0; + description_out->min_is_minus_max = 0; + description_out->padding__ = 0; + + } else if (class == LIBSYSCALLS_TYPEBITS_ARRAY) { + description_out->array_size = 0; + description_out->relative_position_of_array_size = +1; + description_out->absolute_position_of_array_size = -1; + description_out->fill_is_known = 1; + description_out->is_signed = 0; + description_out->is_unsigned = 0; + description_out->min_is_minus_max = 0; + description_out->padding__ = 0; + + } else if (class == LIBSYSCALLS_TYPEBITS_ARRAY_UNKNOWN_FILL) { + description_out->array_size = 0; + description_out->relative_position_of_array_size = +1; + description_out->absolute_position_of_array_size = -1; + description_out->fill_is_known = 0; + description_out->is_signed = 0; + description_out->is_unsigned = 0; + description_out->min_is_minus_max = 0; + description_out->padding__ = 0; + + } else { + return LIBSYSCALLS_E_INVAL; + } + + if (datatype >= LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS) + return LIBSYSCALLS_E_ISSTRUCT; + + memset(description_out->byteorder, ~0U, sizeof(description_out->byteorder)); + +#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, ENDIAN, SIGN)\ + case ARCH: description_out->sign_representation = LIBSYSCALLS_SIGN_##SIGN; break + switch ((int)arch) { + LIST_ARCH_SPECS(CASE, ;); + default: + return LIBSYSCALLS_E_ARCHNOSUP; + } +#undef CASE + + description_out->annotation = LIBSYSCALLS_ANNOTATION_NONE; + description_out->section = LIBSYSCALLS_SECTION_WHOLE; + + switch (description_out->sign_representation) { + case LIBSYSCALLS_SIGN_ONES_COMPLEMENT: + case LIBSYSCALLS_SIGN_SIGN_MAGNITUDE: + description_out->min_is_minus_max = 1; + break; + case LIBSYSCALLS_SIGN_TWOS_COMPLEMENT: + case LIBSYSCALLS_SIGN_EXCESS_HALF: + break; + } + + if (datatype >= LIBSYSCALLS_TYPEOFFSET_FIXED_ARRAYS) { + if (class != LIBSYSCALLS_TYPEBITS_SCALAR) + return LIBSYSCALLS_E_INVAL; + switch (datatype) { + case LIBSYSCALLS_TYPE_2_INTS: + datatype = LIBSYSCALLS_TYPE_INT; + description_out->array_size = 2; + break; + case LIBSYSCALLS_TYPE_2_INTS_FD: + datatype = LIBSYSCALLS_TYPE_INT; + description_out->annotation = LIBSYSCALLS_ANNOTATION_FD; + description_out->array_size = 2; + break; + case LIBSYSCALLS_TYPE_2_UINT32S: + datatype = LIBSYSCALLS_TYPE_UINT32; + description_out->array_size = 2; + break; + case LIBSYSCALLS_TYPE_FD_SET: + goto os_dependent; + default: + return LIBSYSCALLS_E_INVAL; + } + goto unannotated; + + } else if (datatype >= LIBSYSCALLS_TYPEOFFSET_ANNOTATED_NUMERICALS) { + switch (datatype) { + case LIBSYSCALLS_TYPE_INT_SIGNAL: + datatype = LIBSYSCALLS_TYPE_INT; + description_out->annotation = LIBSYSCALLS_ANNOTATION_SIGNAL; + break; + case LIBSYSCALLS_TYPE_INT_FD: + datatype = LIBSYSCALLS_TYPE_INT; + description_out->annotation = LIBSYSCALLS_ANNOTATION_FD; + break; + case LIBSYSCALLS_TYPE_INT_ATFD: + datatype = LIBSYSCALLS_TYPE_INT; + description_out->annotation = LIBSYSCALLS_ANNOTATION_ATFD; + break; + case LIBSYSCALLS_TYPE_LONG_FD: + datatype = LIBSYSCALLS_TYPE_LONG; + description_out->annotation = LIBSYSCALLS_ANNOTATION_FD; + break; + case LIBSYSCALLS_TYPE_LONG_ATFD: + datatype = LIBSYSCALLS_TYPE_LONG; + description_out->annotation = LIBSYSCALLS_ANNOTATION_ATFD; + break; + default: + return LIBSYSCALLS_E_INVAL; + } + goto unannotated; + + } else if (datatype >= LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS) { + unannotated: + if (datatype - LIBSYSCALLS_TYPEOFFSET_UNANNOTATED_NUMERICALS >= COUNT(LIBSYSCALLS_LIST_UNANNOTATED_NUMERICALS)) { + return LIBSYSCALLS_E_INVAL; + } else if (datatype == LIBSYSCALLS_TYPE_MEMORY_ADDRESS) { + datatype = LIBSYSCALLS_TYPE_INTPTR; + } else if (datatype == LIBSYSCALLS_TYPE_CHAR) { + datatype = LIBSYSCALLS_TYPE_SCHAR; + } else { + description_out->is_unsigned = (datatype - LIBSYSCALLS_TYPE_SCHAR) & 1; + description_out->is_signed = 1 ^ description_out->is_unsigned; + datatype &= ~1; + } + goto arch_or_os_dependent; + + } else if (datatype >= LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES) { + if (class != LIBSYSCALLS_TYPEBITS_SCALAR) + return LIBSYSCALLS_E_INVAL; + if (datatype - LIBSYSCALLS_TYPEOFFSET_COMPOSITE_PRIMITIVES >= COUNT(LIBSYSCALLS_LIST_COMPOSITE_PRIMITIVES)) + return LIBSYSCALLS_E_INVAL; + datatype = LIBSYSCALLS_TYPE_MEMORY_ADDRESS; + goto unannotated; + + } else if (datatype >= LIBSYSCALLS_TYPEOFFSET_SPLIT_PRIMITIVES) { + if (class != LIBSYSCALLS_TYPEBITS_SCALAR) + return LIBSYSCALLS_E_INVAL; + enum libsyscalls_datatype t = datatype; + switch (datatype) { + case LIBSYSCALLS_TYPE_UINT64_HIGH_32: + case LIBSYSCALLS_TYPE_UINT64_LOW_32: + case LIBSYSCALLS_TYPE_UINT64_FRONT_32: + case LIBSYSCALLS_TYPE_UINT64_BACK_32: + description_out->is_unsigned = 1; + datatype = LIBSYSCALLS_TYPE_UINT32; + break; + case LIBSYSCALLS_TYPE_INT64_HIGH_32: + case LIBSYSCALLS_TYPE_INT64_LOW_32: + case LIBSYSCALLS_TYPE_INT64_FRONT_32: + case LIBSYSCALLS_TYPE_INT64_BACK_32: + t -= LIBSYSCALLS_TYPE_INT64_HIGH_32; + t += LIBSYSCALLS_TYPE_UINT64_HIGH_32; + description_out->is_signed = 1; + datatype = LIBSYSCALLS_TYPE_INT32; + break; + default: + return LIBSYSCALLS_E_INVAL; + } + switch (t) { + case LIBSYSCALLS_TYPE_UINT64_HIGH_32: + description_out->section = LIBSYSCALLS_SECTION_UPPER_HALF; + break; + case LIBSYSCALLS_TYPE_UINT64_LOW_32: + description_out->section = LIBSYSCALLS_SECTION_LOWER_HALF; + break; + case LIBSYSCALLS_TYPE_UINT64_FRONT_32: + case LIBSYSCALLS_TYPE_UINT64_BACK_32: + half = t == LIBSYSCALLS_TYPE_UINT64_FRONT_32 ? -1 : +1; + r = libsyscalls_get_datatype_description(os, arch, LIBSYSCALLS_TYPE_UINT64, &larger_type); + if (r) + return r; + break; + default: + abort(); + } + goto unannotated; + + } else { + if (class) + return LIBSYSCALLS_E_INVAL; + switch (datatype) { + case LIBSYSCALLS_TYPE_UNKNOWN: + case LIBSYSCALLS_TYPE_DYNAMIC: + datatype = LIBSYSCALLS_TYPE_DYNAMIC; + description_out->is_signed = 1; + description_out->is_unsigned = 1; + description_out->sign_representation = LIBSYSCALLS_SIGN_UNDETERMINED; + description_out->annotation = LIBSYSCALLS_ANNOTATION_UNDETERMINED; + description_out->section = LIBSYSCALLS_SECTION_UNDETERMINED; + goto os_dependent; + case LIBSYSCALLS_TYPE_NO_RETURN: + case LIBSYSCALLS_TYPE_VOID: + description_out->width_in_bits = 0; + break; + default: + return LIBSYSCALLS_E_INVAL; + } + } + + return LIBSYSCALLS_E_OK; + +arch_or_os_dependent: + divide_array_size_with_type_size_out = 0; + +arch_dependent: + switch (datatype) { + /* Note that LIBSYSCALLS_TYPE_INTN does not have the same semantics + * as POSIX's intN_t: these are not necessarily two's complement + * encoded and can have any range of valid numbers as long as that + * type has the correct width */ + case LIBSYSCALLS_TYPE_INT8: + description_out->width_in_bits = 8; + goto not_os_dependent; + case LIBSYSCALLS_TYPE_INT16: + description_out->width_in_bits = 16; + goto not_os_dependent; + case LIBSYSCALLS_TYPE_INT32: + description_out->width_in_bits = 32; + goto not_os_dependent; + case LIBSYSCALLS_TYPE_INT64: + description_out->width_in_bits = 64; + goto not_os_dependent; + case LIBSYSCALLS_TYPE_INTPTR: + case LIBSYSCALLS_TYPE_PTRDIFF: +#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, ENDIAN, SIGN)\ + case ARCH: description_out->width_in_bits = INTPTR_BITS; break + switch ((int)arch) { + LIST_ARCH_SPECS(CASE, ;); + default: + abort(); + } + goto not_os_dependent; +#undef CASE + case LIBSYSCALLS_TYPE_SSIZE: +#define CASE(ARCH, CHARBITS, INTPTR_BITS, SIZE_BITS, ENDIAN, SIGN)\ + case ARCH: description_out->width_in_bits = SIZE_BITS; break + switch ((int)arch) { + LIST_ARCH_SPECS(CASE, ;); + default: + abort(); + } + goto not_os_dependent; +#undef CASE + default: + break; + } + +os_dependent: +#define CASE(UPPERCASE, LOWERCASE)\ + case LIBSYSCALLS_OS_##UPPERCASE:\ + r = get_##LOWERCASE##_datatype_description(arch, &datatype, description_out,\ + ÷_array_size_with_type_size_out);\ + break + + switch ((int)os) { + LIST_OSES(CASE, ;); + default: + return LIBSYSCALLS_E_OSNOSUP; + } + if (r) + return r; +#undef CASE + + switch (datatype) { + case LIBSYSCALLS_TYPE_INT8: + case LIBSYSCALLS_TYPE_INT16: + case LIBSYSCALLS_TYPE_INT32: + case LIBSYSCALLS_TYPE_INT64: + case LIBSYSCALLS_TYPE_INTPTR: + case LIBSYSCALLS_TYPE_PTRDIFF: + case LIBSYSCALLS_TYPE_SSIZE: + goto arch_dependent; + default: + break; + } + +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)\ + case ARCH: charbits = CHARBITS; endian = ENDIAN; break + switch ((int)arch) { + LIST_ARCH_SPECS(CASE, ;); + default: + abort(); + } +#undef CASE + + if (description_out->width_in_bits % charbits) + return LIBSYSCALLS_E_NOSUCHTYPE; + + if (description_out->width_in_bits > (size_t)UCHAR_MAX * sizeof(*description_out->byteorder) || + description_out->width_in_bits > sizeof(description_out->byteorder) / sizeof(*description_out->byteorder) * charbits) + abort(); + + switch (endian) { + case Big: + for (i = 0, j = description_out->width_in_bits; j;) + description_out->byteorder[i++] = j -= charbits; + break; + case Little: + for (i = 0, j = 0; j < description_out->width_in_bits; j += charbits) + description_out->byteorder[i++] = j; + break; + default: + abort(); + } + + if (half) { + unsigned long long int bytemask, coverage = 0; + unsigned long long int remmask; + unsigned char bytebits; + + for (i = 0; larger_type.byteorder[i]; i++) + if (!~larger_type.byteorder[i]) + abort(); + bytebits = larger_type.byteorder[i]; + bytemask = (1ULL << bytebits) - 1ULL; + remmask = 0xFFFFFFFFULL; /* we known from the code above that we are working with 32-bit sections */ + + for (i = 0; larger_type.byteorder[i]; i++) { + coverage |= (remmask & bytemask) << larger_type.byteorder[i]; + remmask >>= bytebits; + } + + /* we known from the code above that we are working with split 64-bit integers */ + 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(); + } + + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_get_signals.c b/libsyscalls_get_signals.c new file mode 100644 index 0000000..9c49760 --- /dev/null +++ b/libsyscalls_get_signals.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +#include "generated/signals.c" + +enum libsyscalls_error +libsyscalls_get_signals(enum libsyscalls_os os, enum libsyscalls_arch arch, + const struct libsyscalls_named_number **signals_out, size_t *num_signals_out) +{ + const struct libsyscalls_named_number *discard_signals; + size_t discard_num_signals; + + if (!signals_out) signals_out = &discard_signals; + if (!num_signals_out) num_signals_out = &discard_num_signals; + +#define CASE(UPPERCASE, LOWERCASE)\ + case LIBSYSCALLS_OS_##UPPERCASE:\ + return get_##LOWERCASE##_signals(arch, signals_out, num_signals_out) + + switch ((int)os) { + LIST_OSES(CASE, ;); + + /* if OS is known but does not have named numerical signal, + * get_##LOWERCASE##_signals shall return LIBSYSCALLS_E_NOSIGNALS */ + + default: + return LIBSYSCALLS_E_OSNOSUP; + } + +#undef CASE +} diff --git a/libsyscalls_get_syscall.c b/libsyscalls_get_syscall.c new file mode 100644 index 0000000..aea4d2f --- /dev/null +++ b/libsyscalls_get_syscall.c @@ -0,0 +1,37 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +enum libsyscalls_error +libsyscalls_get_syscall(enum libsyscalls_os os, enum libsyscalls_arch arch, long long int syscallnr, + const struct libsyscalls_syscall **syscall_out) +{ + const struct libsyscalls_syscall *syscalldesc; + static enum libsyscalls_error error; + long long int min, max; + + error = libsyscalls_get_syscall_range(os, arch, &min, &max); + if (error) + return error; + + if (syscallnr < min || syscallnr > max) + return LIBSYSCALLS_E_NOSUCHSYSCALL; + + /* buffer access is validated by libsyscalls_get_syscall_range() */ +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#endif + + syscalldesc = libsyscalls_syscalls_tables_[os][arch][syscallnr - min]; + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + + if (!syscalldesc) + return LIBSYSCALLS_E_NOSUCHSYSCALL; + if (syscall_out) + *syscall_out = syscalldesc; + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_get_syscall_display_info.c b/libsyscalls_get_syscall_display_info.c new file mode 100644 index 0000000..5b39284 --- /dev/null +++ b/libsyscalls_get_syscall_display_info.c @@ -0,0 +1,148 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#include <stdalign.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#define LOWEST_BIT(X) ((X) & ~((X) - 1)) +#define POST_HIGHEST_OF_CONSECUTIVELY_BITS(X) ((X) + LOWEST_BIT(X)) + + +static inline signed char +trailing_zeroes(unsigned long long int x) { + int r = 0; + if (x == 0) + return -1; + for (; (x & 1) == 0; x >>= 1) + r += 1; + return (signed char)r; +} + + +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; +} + + +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; +} + + +static const char * +extract_signal(enum libsyscalls_os os, enum libsyscalls_arch arch, + unsigned long long int *valuep, char *fallback_out, int is_signed) +{ + const struct libsyscalls_named_number *signals, *found; + size_t nsignals; + struct libsyscalls_named_number key = {.number.u = *valuep}; + + if (libsyscalls_get_signals(os, arch, &signals, &nsignals)) + return NULL; + + found = bsearch(&key, signals, nsignals, sizeof(key), + is_signed ? &signed_named_number_cmp : &unsigned_named_number_cmp); + if (!found) + return NULL; + + *valuep = 0; + return found->name; +} + + +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) +{ + struct libsyscalls_syscall_display_info *ret; + size_t size, dataoff, paramoff; + int i; + + size = sizeof(*ret); + + if (size & (data_align - 1)) { + size |= data_align - 1; + size += 1; + } + dataoff = size; + size += nsyms * data_size; + + if (size & (alignof(*ret->params) - 1)) { + size |= alignof(*ret->params) - 1; + size += 1; + } + paramoff = size; + size += (nargs + 1) * sizeof(*ret->params); + + ret = calloc(1, size); + if (!ret) + return NULL; + + ret->size = sizeof(*ret); + ret->params = (void *)&((char *)ret)[paramoff]; + ret->retvalue = &ret->params[nargs]; + + nsyms = 0; + for (i = 0; i < nargs; i++) { + 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 + nsyms * data_size]; + memcpy(ret->params[i].data, &((char *)data)[i * data_size], data_size); + nsyms++; + } + } + ret->retvalue->type = syscall->return_type; + ret->retvalue->expect_zero = syscall->expect_zero; + if (funcs[i]) { + ret->retvalue->function = funcs[i]; + ret->retvalue->data = (void *)&((char *)ret)[dataoff + nsyms * data_size]; + memcpy(ret->retvalue->data, &((char *)data)[i * data_size], data_size); + } + + return ret; +} + + +#include "generated/symbols.c" + + +enum libsyscalls_error +libsyscalls_get_syscall_display_info(enum libsyscalls_os os, enum libsyscalls_arch arch, + const struct libsyscalls_syscall_abi *syscall, + long long int syscall_number, + unsigned long long int *syscall_arguments, + struct libsyscalls_syscall_display_info **info_out) +{ + struct libsyscalls_syscall_display_info *info; + + if (!syscall || !syscall_arguments || !info_out) + return LIBSYSCALLS_E_INVAL; + +#define CASE(UPPERCASE, LOWERCASE)\ + case LIBSYSCALLS_OS_##UPPERCASE:\ + info = get_##LOWERCASE##_syscall_display_info(arch, syscall, syscall_number, syscall_arguments);\ + break + + switch ((int)os) { + LIST_OSES(CASE, ;); + default: + return LIBSYSCALLS_E_OSNOSUP; + } + +#undef CASE + + if (!info) + return LIBSYSCALLS_E_NOMEM; + *info_out = info; + return LIBSYSCALLS_E_OK; +} diff --git a/libsyscalls_get_syscall_errors.c b/libsyscalls_get_syscall_errors.c new file mode 100644 index 0000000..14b1e05 --- /dev/null +++ b/libsyscalls_get_syscall_errors.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +#include "generated/errors.c" + +enum libsyscalls_error +libsyscalls_get_syscall_errors(enum libsyscalls_os os, enum libsyscalls_arch arch, + const struct libsyscalls_named_number **errors_out, size_t *num_errors_out) +{ + const struct libsyscalls_named_number *discard_errors; + size_t discard_num_errors; + + if (!errors_out) errors_out = &discard_errors; + if (!num_errors_out) num_errors_out = &discard_num_errors; + +#define CASE(UPPERCASE, LOWERCASE)\ + case LIBSYSCALLS_OS_##UPPERCASE:\ + return get_##LOWERCASE##_syscall_errors(arch, errors_out, num_errors_out) + + switch ((int)os) { + LIST_OSES(CASE, ;); + + /* if OS is known but does not have named error numbers, + * get_##LOWERCASE##_syscall_errors shall return LIBSYSCALLS_E_NOERRORS; */ + + default: + return LIBSYSCALLS_E_OSNOSUP; + } + +#undef CASE +} diff --git a/libsyscalls_get_syscall_range.c b/libsyscalls_get_syscall_range.c new file mode 100644 index 0000000..eb9b11e --- /dev/null +++ b/libsyscalls_get_syscall_range.c @@ -0,0 +1,26 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +#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) +{ + long long int discarded; + + if (!min_out) min_out = &discarded; + if (!max_out) max_out = &discarded; + +#define CASE(UPPERCASE, LOWERCASE)\ + case LIBSYSCALLS_OS_##UPPERCASE:\ + return get_##LOWERCASE##_syscall_range(arch, min_out, max_out) + + switch ((int)os) { + LIST_OSES(CASE, ;); + default: + return LIBSYSCALLS_E_OSNOSUP; + } + +#undef CASE +} diff --git a/libsyscalls_perror.c b/libsyscalls_perror.c new file mode 100644 index 0000000..4b110c7 --- /dev/null +++ b/libsyscalls_perror.c @@ -0,0 +1,15 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +#include <stdio.h> + + +void +libsyscalls_perror(const char *prefix, enum libsyscalls_error error) +{ + const char *str = libsyscalls_strerror(error); + if (prefix && *prefix) + fprintf(stderr, "%s: %s\n", prefix, str); + else + fprintf(stderr, "%s\n", str); +} diff --git a/libsyscalls_strerror.c b/libsyscalls_strerror.c new file mode 100644 index 0000000..d54ed74 --- /dev/null +++ b/libsyscalls_strerror.c @@ -0,0 +1,18 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +const char * +libsyscalls_strerror(enum libsyscalls_error error) +{ +#define X(ENUM, STR)\ + case ENUM: return STR + + switch ((int)error) { + LIBSYSCALLS_LIST_ERRORS(X, ;); + default: + return "Unrecognised error"; + } + +#undef X +} diff --git a/libsyscalls_syscalls_tables_.c b/libsyscalls_syscalls_tables_.c new file mode 100644 index 0000000..403b1c7 --- /dev/null +++ b/libsyscalls_syscalls_tables_.c @@ -0,0 +1,10 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +const struct libsyscalls_syscall *const *const *const libsyscalls_syscalls_tables_[] = { +#define X(UPPERCASE, LOWERCASE)\ + [LIBSYSCALLS_OS_##UPPERCASE] = libsyscalls_##LOWERCASE##_syscalls_table_ + LIST_OSES(X, COMMA) +#undef X +}; |