diff options
Diffstat (limited to 'libsyscalls.h')
-rw-r--r-- | libsyscalls.h | 369 |
1 files changed, 328 insertions, 41 deletions
diff --git a/libsyscalls.h b/libsyscalls.h index caf4a4b..382022b 100644 --- a/libsyscalls.h +++ b/libsyscalls.h @@ -31,7 +31,8 @@ X(LIBSYSCALLS_E_NOMEM, "Failed to allocate required memory") D\ X(LIBSYSCALLS_E_INVAL, "Invalid arguments passed to function") D\ X(LIBSYSCALLS_E_NOSUCHTYPE, "Type does not exist on the selected operating system or architecture") D\ - X(LIBSYSCALLS_E_ISSTRUCT, "Type is a structure or union") + X(LIBSYSCALLS_E_ISSTRUCT, "Type is a structure or union") D\ + X(LIBSYSCALLS_E_ISNOTSTRUCT, "Type is not a structure or union") /** * libsyscall error numbers @@ -51,30 +52,49 @@ enum libsyscalls_os { * Architectures */ enum libsyscalls_arch { - LIBSYSCALLS_ARCH_ALPHA, + LIBSYSCALLS_ARCH_ALPHA_LE, + LIBSYSCALLS_ARCH_ALPHA_BE, LIBSYSCALLS_ARCH_AMD64, - LIBSYSCALLS_ARCH_AMD64_X32, /* 32-bit ABI, not traditional 32-bit x86 ISA */ - LIBSYSCALLS_ARCH_ARM_OABI, - LIBSYSCALLS_ARCH_ARM_EABI, - LIBSYSCALLS_ARCH_IA64, + LIBSYSCALLS_ARCH_AMD64_X32, /* 32-bit ABI on 64-bit ISA */ + LIBSYSCALLS_ARCH_ARM_OABI_LE, + LIBSYSCALLS_ARCH_ARM_OABI_BE, + LIBSYSCALLS_ARCH_ARM_EABI_LE, + LIBSYSCALLS_ARCH_ARM_EABI_BE, + LIBSYSCALLS_ARCH_IA64_LE, /* 64-bit pointers */ + LIBSYSCALLS_ARCH_IA64_BE, /* 64-bit pointers */ + LIBSYSCALLS_ARCH_IA64_P32_LE, /* 32-bit pointers */ + LIBSYSCALLS_ARCH_IA64_P32_BE, /* 32-bit pointers */ LIBSYSCALLS_ARCH_M68K, - LIBSYSCALLS_ARCH_MICROBLAZE, - LIBSYSCALLS_ARCH_MIPS_O32, - LIBSYSCALLS_ARCH_MIPS_N32, - LIBSYSCALLS_ARCH_MIPS_N64, + LIBSYSCALLS_ARCH_MICROBLAZE_32_LE, + LIBSYSCALLS_ARCH_MICROBLAZE_32_BE, + LIBSYSCALLS_ARCH_MICROBLAZE_64_LE, + LIBSYSCALLS_ARCH_MICROBLAZE_64_BE, + LIBSYSCALLS_ARCH_MIPS_O32_LE, + LIBSYSCALLS_ARCH_MIPS_O32_BE, + LIBSYSCALLS_ARCH_MIPS_N32_LE, /* 32-bit ABI on 64-bit ISA */ + LIBSYSCALLS_ARCH_MIPS_N32_BE, /* 32-bit ABI on 64-bit ISA */ + LIBSYSCALLS_ARCH_MIPS_N64_LE, + LIBSYSCALLS_ARCH_MIPS_N64_BE, LIBSYSCALLS_ARCH_PARISC_32, LIBSYSCALLS_ARCH_PARISC_64, - LIBSYSCALLS_ARCH_POWERPC_32, - LIBSYSCALLS_ARCH_POWERPC_64, - LIBSYSCALLS_ARCH_POWERPC_NOSPU, - LIBSYSCALLS_ARCH_POWERPC_SPU, + LIBSYSCALLS_ARCH_POWERPC_32_LE, + LIBSYSCALLS_ARCH_POWERPC_32_BE, + LIBSYSCALLS_ARCH_POWERPC_64_LE, + LIBSYSCALLS_ARCH_POWERPC_64_BE, + LIBSYSCALLS_ARCH_POWERPC_NOSPU_LE, + LIBSYSCALLS_ARCH_POWERPC_NOSPU_BE, + LIBSYSCALLS_ARCH_POWERPC_SPU_LE, + LIBSYSCALLS_ARCH_POWERPC_SPU_BE, LIBSYSCALLS_ARCH_S390_32, LIBSYSCALLS_ARCH_S390_64, - LIBSYSCALLS_ARCH_SH, + LIBSYSCALLS_ARCH_SH_LE, /* does not cover SH-5 */ + LIBSYSCALLS_ARCH_SH_BE, /* does not cover SH-5 */ LIBSYSCALLS_ARCH_SPARC_32, - LIBSYSCALLS_ARCH_SPARC_64, + LIBSYSCALLS_ARCH_SPARC_64_LE, + LIBSYSCALLS_ARCH_SPARC_64_BE, LIBSYSCALLS_ARCH_I386, - LIBSYSCALLS_ARCH_XTENSA + LIBSYSCALLS_ARCH_XTENSA_LE, + LIBSYSCALLS_ARCH_XTENSA_BE }; /** @@ -174,18 +194,23 @@ enum libsyscalls_datatype { #define LIBSYSCALLS_LIST_STRUCTS_AND_UNIONS(X, SUFFIX, D, FIRST)\ X(LIBSYSCALLS_TYPE_STRUCT_AIO_SIGSET ## SUFFIX, FIRST, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_COMPAT_AIO_SIGSET ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_CACHESTAT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_CACHESTAT_RANGE ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_CLONE_ARGS ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_EPOLL_EVENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_OABI_EPOLL_EVENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_FILE_HANDLE ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_FUTEX_WAITV ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_IOB ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_IOVEC ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_IO_EVENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_IO_URING_PARAMS ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_ITIMERVAL ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_ITIMERSPEC ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_ITIMERSPEC64 ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_KEXEC_SEGMENT ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_COMPAT_KEXEC_SEGMENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_LANDLOCK_RULESET_ATTR ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_LINUX_DIRENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_LINUX_DIRENT64 ## SUFFIX,, "struct") D\ @@ -214,6 +239,7 @@ enum libsyscalls_datatype { X(LIBSYSCALLS_TYPE_STRUCT_POLLFD ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_RLIMIT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_RLIMIT64 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_COMPAT_RLIMIT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_ROBUST_LIST_HEAD ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_RSEQ ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_RUSAGE ## SUFFIX,, "struct") D\ @@ -227,7 +253,7 @@ enum libsyscalls_datatype { X(LIBSYSCALLS_TYPE_STRUCT_SIGALTSTACK ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_SIGEVENT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_SIGINFO ## SUFFIX,, "struct") D\ - X(LIBSYSCALLS_TYPE_STRUCT_SOCKADDR ## SUFFIX,, "struct") D /* size is always in the next argument */\ + X(LIBSYSCALLS_TYPE_STRUCT_SOCKADDR ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_STAT ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_STAT64 ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_STATFS ## SUFFIX,, "struct") D\ @@ -235,6 +261,8 @@ enum libsyscalls_datatype { X(LIBSYSCALLS_TYPE_STRUCT_STATX ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_SYSINFO ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_TIMESPEC ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_TIMESPEC64 ## SUFFIX,, "struct") D\ + X(LIBSYSCALLS_TYPE_STRUCT_TIMEVAL ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_TIMEX ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_TIMEZONE ## SUFFIX,, "struct") D\ X(LIBSYSCALLS_TYPE_STRUCT_TMS ## SUFFIX,, "struct") D\ @@ -246,7 +274,9 @@ enum libsyscalls_datatype { X(LIBSYSCALLS_TYPE_2_INTS ## SUFFIX, FIRST, "int[2]") D\ X(LIBSYSCALLS_TYPE_2_INTS_FD ## SUFFIX,, "int[2]") D\ X(LIBSYSCALLS_TYPE_2_UINT32S ## SUFFIX,, "uint32[2]") D\ - X(LIBSYSCALLS_TYPE_FD_SET ## SUFFIX,, "unsigned long[]") /* size depends on OS, (1024 / CHAR_BIT / sizeof(long)) in Linux */ + X(LIBSYSCALLS_TYPE_FD_SET ## SUFFIX,, "unsigned long[]") /* size depends on OS, (1024/CHAR_BIT/sizeof(long)) in Linux */ D\ + X(LIBSYSCALLS_TYPE_BUFFER_9 ## SUFFIX,, "char[9]") D\ + X(LIBSYSCALLS_TYPE_BUFFER_65 ## SUFFIX,, "char[65]") /* these don't have any suffix */ LIBSYSCALLS_MAKE_SPECIAL_TYPES_(), @@ -256,7 +286,7 @@ enum libsyscalls_datatype { LIBSYSCALLS_MAKE_ANNOTATED_NUMERICALS_(), LIBSYSCALLS_MAKE_STRUCTS_AND_UNIONS_(), - /* the following are always pointers unless returned */ + /* the following are always pointers if used as a parameter */ /* size in next parameter (or the previous parameter if there is no next parameter), * updated with fill if possible, otherwise returned (these use the suffix _ARRAY) */ @@ -2074,7 +2104,7 @@ struct libsyscalls_datatype_description { * guaranteed to be split otherwise) and this value is just * the number of bits stored in the register or struct field * - * It is possible for the datatype to contain unused dummy + * It is possible for the data type to contain unused dummy * bits in order to make it a power of 2 or a multiple of * a smaller data type. For example, on x86, `long double` * uses 128 bits, even though the value only uses 80 bits. @@ -2194,7 +2224,9 @@ struct libsyscalls_datatype_description { * `sizeof(x.byteorder) / sizeof(*x.byteorder)` * elements are read (where x is the instance of the * structure) (you should definitely have your own - * macro for that one) + * macro for that one). As an alternative to + * `LIBSYSCALLS_IS_BYTEORDER_END`, you may use the + * LIBSYSCALLS_IS_BYTEORDER_END_AT macro */ unsigned char byteorder[32]; @@ -2214,6 +2246,14 @@ struct libsyscalls_datatype_description { # define LIBSYSCALLS_IS_BYTEORDER_END(SHIFT)\ (!~((SHIFT) | ~LIBSYSCALLS_FIELD_MASK_(1ULL, struct libsyscalls_datatype_description, byteorder[0]))) #endif + + /** + * Test whether `DESC->byteorder[INDEX]` is + * the (post-last) end of `DESC->byteorder` + */ +#define LIBSYSCALLS_IS_BYTEORDER_END_AT(DESC, INDEX)\ + ((size_t)(INDEX) == sizeof((DESC)->byteorder) / sizeof(*(DESC)->byteorder) || \ + LIBSYSCALLS_IS_BYTEORDER_END((DESC)->byteorder[INDEX])) }; /** @@ -2262,6 +2302,51 @@ struct libsyscalls_structure_field { unsigned short int symbolic_field : 1; /** + * Only used with .input_field set to 1 + * + * If 1, it is probably not an error if the + * field is partially initialised as long as all + * its memory is allocated + * + * In the case that a field is split using for + * example one field with the type + * LIBSYSCALLS_TYPE_UINT64_FRONT_32 and another + * field with the type + * LIBSYSCALLS_TYPE_UINT64_BACK_32 (these two + * (for some split types, their may be more than + * two fields) fields will have the same name), + * it is one is partially initialised and the + * other completely uninitialised. Generally, + * as long as at least one of the parts are + * partially initialised, the application should + * not, unless it has more detailed knowledge + * about the system call, assume that there is + * an error. This happens because kernel's version + * of the library uses a scalar field, where as + * the userspace version (usually libc's version) + * uses a union of differently sized field. It + * is not necessarily the case that it can be + * known which field in the union is used: for + * example in epoll_ctl(2), it is completely up + * to the application, and the application has + * no way of telling the kernel which is used, + * and the kernel will in epoll_wait(2) simply + * return the union's value as it was set, meaning + * that some bits may be effectively uninitialised. + * Even if the field is complete uninitialised, + * it may still be the case that this is not an + * error, however, it probably is an error; for + * example in the case of epoll(7), it is completely + * possible, albeit unlikely (because it's silly), + * that the user calls epoll_ctl(2) without the + * `.data` field set, because it doesn't look at + * in when epoll_wait(2) returns, but insteads + * just does unblocking I/O one each file + * descriptor it has added to the epoll(7). + */ + unsigned short int partial_init_ok : 1; + + /** * If 1, the field is a pointer that the reads from * * Note that there are types that fundamentally are @@ -2281,7 +2366,16 @@ struct libsyscalls_structure_field { */ unsigned short int output_pointer : 1; - unsigned short int padding1__ : 16 - (6*1); + /** + * If 1, it has been determined that the field is + * not being used (usually because that it's not + * the active field in a `union` or because a + * flag somewhere in the `struct` is either set or + * cleared) + */ + unsigned short int unused : 1; + + unsigned short int padding1__ : 16 - (8*1); #if LIBSYSCALLS_IS_PADDING_REQUIRED_(3, 16, LIBSYSCALLS_POINTER_BIT_) # if !LIBSYSCALLS_CAN_ALIGN_(3, 16, CHAR_BIT) @@ -2289,6 +2383,30 @@ struct libsyscalls_structure_field { # endif char padding2__[LIBSYSCALLS_PAD_(sizeof(void *)/sizeof(char), (3*16)/CHAR_BIT)]; #endif + + /** + * Data type description + * + * The application is free to make changes, however, + * however the pointers themselves must not be touched + */ + union { + /** + * Description to use if `.type` refers to a + * `struct` or `union`; that is, if + * `(.type & ~LIBSYSCALLS_TYPEBITSMASK) >= + * LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS` + */ + struct libsyscalls_structure_description *structure; + + /** + * Description to use if `.type` does not refer + * to a `struct` or `union`; that is, if + * `(.type & ~LIBSYSCALLS_TYPEBITSMASK) < + * LIBSYSCALLS_TYPEOFFSET_STRUCTS_AND_UNIONS` + */ + struct libsyscalls_datatype_description *nonstructure; + } type_description; }; /** @@ -2320,6 +2438,12 @@ struct libsyscalls_structure_description { unsigned short int num_fields : 14; /** + * If 1, the data type is a `union`, + * if 0, the data type is a `struct` + */ + unsigned short int is_union : 1; + + /** * Only used if .array_size is 0 * * Assuming the kernel writes into the array, if 1, the number @@ -2333,18 +2457,12 @@ struct libsyscalls_structure_description { unsigned short int fill_is_known : 1; /** - * If 1, the data type is a `union`, - * if 0, the data type is a `struct` - */ - unsigned short int is_union : 1; - - /** * The size (in number of elements) of the array the data type * is used in, or 1 if the data type was not an array or * 0 if the array size is determined by another parameter/field * * If 1, .relative_position_of_size will be set to 0, - * and .absolute_position_of_size -1, hoever if that is not + * and .absolute_position_of_size -1, however if that is not * the case and this field is set to 1, then .size (which may * or may not be 0 at this point) is determined by the indicated * parameter @@ -2441,7 +2559,7 @@ libsyscalls_perror(const char *, enum libsyscalls_error); * (not [*min_out, *max_out - 1]) but there may still be numbers within * this range that does not correspond to a system call */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 3), __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_syscall_range(enum libsyscalls_os, enum libsyscalls_arch, long long int *, long long int *); @@ -2468,7 +2586,7 @@ libsyscalls_get_syscall_range(enum libsyscalls_os, enum libsyscalls_arch, long l * of operating system (`os`) and architecture (`arch`) is * unsupported */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_syscall(enum libsyscalls_os, enum libsyscalls_arch, long long int, const struct libsyscalls_syscall **); @@ -2498,6 +2616,7 @@ libsyscalls_get_syscall(enum libsyscalls_os, enum libsyscalls_arch, long long in * is not supported, however it may be successful even if the * architecture (`arch`) not supported */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 3), __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_syscall_errors(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_named_number **, size_t *); @@ -2527,6 +2646,7 @@ libsyscalls_get_syscall_errors(enum libsyscalls_os, enum libsyscalls_arch, const * is not supported, however it may be successful even if the * architecture (`arch`) not supported */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 3), __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_signals(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_named_number **, size_t *); @@ -2542,7 +2662,11 @@ libsyscalls_get_signals(enum libsyscalls_os, enum libsyscalls_arch, const struct * @param syscall_arguments The values store in register (as upon system call entry) * the used for the system call, in the order the registers * are used as system call arguments - * @param info_out Output parameter for the additional system call information + * @param info_out Output parameter for the additional system call information; + * the caller responsible for deallocating the `*info_out` + * with free(3) when it is no longer needed. Be aware that + * `*info_out` will only be set when LIBSYSCALLS_E_OK is + * returned. * @return LIBSYSCALLS_E_OK - On success * LIBSYSCALLS_E_OSNOSUP - The library is not compiled with support for * the selected operating system (`os`) @@ -2552,17 +2676,23 @@ libsyscalls_get_signals(enum libsyscalls_os, enum libsyscalls_arch, const struct * LIBSYSCALLS_E_NOMEM - Failed to allocate memory for `*info_out` * LIBSYSCALLS_E_INVAL - One of the arguments was NULL */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __nonnull__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __nonnull__, __access__(__read_only__, 3), __access__(__write_only__, 6)) enum libsyscalls_error libsyscalls_get_syscall_display_info(enum libsyscalls_os, enum libsyscalls_arch, const struct libsyscalls_syscall_abi *, - long long int, unsigned long long int *, struct libsyscalls_syscall_display_info **); + long long int, const unsigned long long int *, struct libsyscalls_syscall_display_info **); /** - * Get information on how an instance of data type is to be parsed + * Get information on how an instance of non-struct, non-union + * data type is to be parsed + * + * Do not use for data types inside structures, + * instead, use `.type_description.nonstructure` + * in the structure's field, as it may contain + * important adjustments * * @param os The operating system the data type is used on * @param arch The architecture the data type is used on - * @param datatype The datatype, `LIBSYSCALLS_TYPE_DYNAMIC` can + * @param datatype The data type, `LIBSYSCALLS_TYPE_DYNAMIC` can * be used to get the size of the registers used * as system call parameters * @param description_out Output parameter for the type description @@ -2575,13 +2705,14 @@ libsyscalls_get_syscall_display_info(enum libsyscalls_os, enum libsyscalls_arch, * LIBSYSCALLS_E_INVAL - `datatype` is not a valid data type * LIBSYSCALLS_E_NOSUCHTYPE - `datatype` does not exist on the selected * operating system (`os`) or architecture (`arch`) - * LIBSYSCALLS_E_ISSTRUCT - `datatype` represents a structure + * LIBSYSCALLS_E_ISSTRUCT - `datatype` represents a structure or union, + * or an array of a structure or union * * The function may complete successfully for some data * types even if it for other data types would return * LIBSYSCALLS_E_OSNOSUP or LIBSYSCALLS_E_ARCHNOSUP */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_datatype_description(enum libsyscalls_os, enum libsyscalls_arch, enum libsyscalls_datatype, struct libsyscalls_datatype_description *); @@ -2625,11 +2756,167 @@ libsyscalls_get_datatype_description(enum libsyscalls_os, enum libsyscalls_arch, * return LIBSYSCALLS_E_ARCHNOSUP, in such cases, the result * is indeed reliable */ -LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__) +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__write_only__, 4)) enum libsyscalls_error libsyscalls_get_integer_alignment(enum libsyscalls_os, enum libsyscalls_arch, unsigned, unsigned *); -/* TODO add libsyscalls_get_struct_description */ +/** + * Parse a string of bits as a signed integer + * + * In case `representation` is LIBSYSCALLS_SIGN_UNDETERMINED, + * the bits are parsed as an unsigned integer + * + * @param value_in The bits to parse as a signed integer + * @param representation The sign representation used on the interger + * @param bits The number of bits in the integer + * @param value_out Output parameter for the absolute value of the signed integer (may be NULL) + * @param negative_out Output parameter for whether the signed integer is negative (may be NULL) + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - `representation` is not recognised by the library + * LIBSYSCALLS_E_INVAL - `bits` is 0 + * LIBSYSCALLS_E_INVAL - `bits` is greater than `sizeof(long long int) * CHAR_BIT` + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 4), __access__(__write_only__, 5)) +enum libsyscalls_error +libsyscalls_parse_signed_integer(unsigned long long int, enum libsyscalls_datatype_sign_representation, + size_t, unsigned long long int *, int *); + +/** + * Create a string of bits representing a signed integer + * + * In case `representation` is LIBSYSCALLS_SIGN_UNDETERMINED, + * the bit string will represent an unsigned integer + * + * @param value_in The absolute value if the signed integer + * @param negative Whether the signed integer is negative + * @param representation The sign representation used on the interger + * @param bits The number of bits in the integer + * @param value_out Output parameter for the bit string (may be NULL) + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - `representation` is not recognised by the library + * LIBSYSCALLS_E_INVAL - `bits` is 0 + * LIBSYSCALLS_E_INVAL - `bits` is greater than `sizeof(long long int) * CHAR_BIT` + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 5)) +enum libsyscalls_error +libsyscalls_make_signed_integer(unsigned long long int, int, enum libsyscalls_datatype_sign_representation, + size_t, unsigned long long int *); + +/** + * Take bits from a section of a split value + * and shift its bit into place, so that the OR + * of the result for each section creates the + * original unsplit value + * + * If `section` is LIBSYSCALLS_SECTION_UNDETERMINED, + * no changes will be made + * + * @param value_in The contiguous bits in the section of the value + * @param bits The number of bits in the section of the value + * @param section The section of the value + * @param value_out Output parameter for the value with its bits shifted into place (may be NULL) + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - `representation` is not recognised by the library + * LIBSYSCALLS_E_INVAL - `bits` is invalid for `section` + * LIBSYSCALLS_E_INVAL - `bits` is greater than `sizeof(long long int) * CHAR_BIT` + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 4)) +enum libsyscalls_error +libsyscalls_unsection_value(unsigned long long int, size_t, enum libsyscalls_datatype_section, unsigned long long int *); + +/** + * Create a split section from a value + * + * If `section` is LIBSYSCALLS_SECTION_UNDETERMINED, + * no changes will be made + * + * @param value_in The whole value + * @param bits The number of bits in the whole value + * @param section The section of the value to return + * @param value_out Output parameter for bits in the section value shifted into contiguity (may be NULL) + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - `representation` is not recognised by the library + * LIBSYSCALLS_E_INVAL - `bits` is invalid for `section` + * LIBSYSCALLS_E_INVAL - `bits` is greater than `sizeof(long long int) * CHAR_BIT` + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__access__(__write_only__, 4)) +enum libsyscalls_error +libsyscalls_section_value(unsigned long long int, size_t, enum libsyscalls_datatype_section, unsigned long long int *); + +/** + * Converts a value from the tracee's endian to the tracer's endian + * + * @param value_in Buffer containing the value to convert (does not need to be aligned) + * @param offset_in Offset in `value_in`, in bits + * @param type Details about the data type + * @param value_out Output parameter for the value in the tracer's endian + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - Either parameter is NULL + * LIBSYSCALLS_E_INVAL - The data type is too wide + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__nonnull__, __access__(__read_only__, 1), __access__(__read_only__, 3), __access__(__write_only__, 4)) +enum libsyscalls_error +libsyscalls_to_tracer_endian(const void *, size_t, const struct libsyscalls_datatype_description *, unsigned long long int *); + +/** + * Converts a value from the tracer's endian to the tracee's endian + * + * @param value_in Buffer containing the value to convert + * @param type Details about the data type + * @param value_out Output parameter for the value in the tracee's + * endian (does not need to be aligned); preexisting + * bits that do not overlap with the position of the + * value will be retained + * @param out_offset Offset in `value_out`, in bits + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_INVAL - Either parameter is NULL + * LIBSYSCALLS_E_INVAL - The data type is too wide + */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__nonnull__, __access__(__read_only__, 2), __access__(__read_write__, 3)) +enum libsyscalls_error +libsyscalls_to_tracee_endian(unsigned long long int, const struct libsyscalls_datatype_description *, void *, size_t); + +/** + * Get information on how an instance of struct or union is to be parsed + * + * Do not use for structures inside other structures, + * instead, use `.type_description.structure` in the + * structure's field, as it may contain important + * adjustments + * + * @param os The operating system the data type is used on + * @param arch The architecture the data type is used on + * @param datatype The data type + * @param data The data that is to be parsed (may be `NULL` if `data_size` is 0) + * @param data_size The number of bytes available in `data`, may be short or in excess + * @param description_out Output parameter for the type description; + * the caller responsible for deallocating the `*info_out` + * with free(3) when it is no longer needed. Be aware that + * `*info_out` will only be set when LIBSYSCALLS_E_OK is + * returned. + * @return LIBSYSCALLS_E_OK - On success + * LIBSYSCALLS_E_OSNOSUP - The library is not compiled with support for + * the selected operating system (`os`) + * LIBSYSCALLS_E_ARCHNOSUP - The library is not compiled with support for + * the selected architecture (`arch`) on the + * selected operating system (`os`) + * LIBSYSCALLS_E_INVAL - `datatype` is not a valid data type + * LIBSYSCALLS_E_NOSUCHTYPE - `datatype` does not exist on the selected + * operating system (`os`) or architecture (`arch`) + * LIBSYSCALLS_E_ISNOTSTRUCT - `datatype` does not represent a structure or + * union, nor an array of structure or union + * + * The function may complete successfully for some data + * types even if it for other data types would return + * LIBSYSCALLS_E_ARCHNOSUP + */ +#if 0 /* work in progress */ +LIBSYSCALLS_GCC_ATTRIBUTES_(__warn_unused_result__, __access__(__read_only__, 4, 5), __access__(__write_only__, 6)) +enum libsyscalls_error +libsyscalls_get_struct_description(enum libsyscalls_os, enum libsyscalls_arch, enum libsyscalls_datatype, + const void *, size_t, struct libsyscalls_structure_description **); +#endif + /* TODO add libsyscalls_get_struct_display_info */ |