diff options
author | Mattias Andrée <maandree@kth.se> | 2023-12-03 19:23:35 +0100 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2023-12-03 19:23:35 +0100 |
commit | c131f122778c62f920a99bbf854ced4a37ee8b03 (patch) | |
tree | 14c933f98f4d64dffb0a594bc40dd5121c6c5a8e /libsyscalls_get_datatype_description.c | |
download | libsyscalls-c131f122778c62f920a99bbf854ced4a37ee8b03.tar.gz libsyscalls-c131f122778c62f920a99bbf854ced4a37ee8b03.tar.bz2 libsyscalls-c131f122778c62f920a99bbf854ced4a37ee8b03.tar.xz |
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'libsyscalls_get_datatype_description.c')
-rw-r--r-- | libsyscalls_get_datatype_description.c | 418 |
1 files changed, 418 insertions, 0 deletions
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; +} |