summaryrefslogtreecommitdiffstats
path: root/libsyscalls_get_datatype_description.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2023-12-03 19:23:35 +0100
committerMattias Andrée <maandree@kth.se>2023-12-03 19:23:35 +0100
commitc131f122778c62f920a99bbf854ced4a37ee8b03 (patch)
tree14c933f98f4d64dffb0a594bc40dd5121c6c5a8e /libsyscalls_get_datatype_description.c
downloadlibsyscalls-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.c418
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,\
+ &divide_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;
+}