/* 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 (LIBSYSCALLS_IS_BYTEORDER_END(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;
}