/* See LICENSE file for copyright and license details. */ #include "common.h" #include #include #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; }