Forgot to [email protected] when generating v2. On Tue, Aug 11, 2020 at 12:10 AM Shu-Chun Weng <[email protected]> wrote:
> Flexible arrays may appear in the last field of a struct and are heavily
> used in the ioctl(SIOCETHTOOL) system call on Linux. E.g.
>
> struct ethtool_regs {
> __u32 cmd;
> __u32 version; /* driver-specific, indicates different chips/revs
> */
> __u32 len; /* bytes */
> __u8 data[0];
> };
>
> where number of elements in `data` is specified in `len`. It is translated
> into:
>
> STRUCT(ethtool_regs,
> TYPE_INT, /* cmd */
> TYPE_INT, /* version */
> TYPE_INT, /* len */
> MK_FLEXIBLE_ARRAY(TYPE_CHAR, 2)) /* data[0]: len */
>
> where the "2" passed to `MK_FLEXIBLE_ARRAY` means the number of element
> is specified by field number 2 (0-index).
>
> Signed-off-by: Shu-Chun Weng <[email protected]>
> ---
> v1 -> v2:
> Fix style problems.
>
> include/exec/user/thunk.h | 24 ++++++
> thunk.c | 152 +++++++++++++++++++++++++++++++++++++-
> 2 files changed, 174 insertions(+), 2 deletions(-)
>
> diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h
> index 7992475c9f..d0d7c83f1f 100644
> --- a/include/exec/user/thunk.h
> +++ b/include/exec/user/thunk.h
> @@ -39,12 +39,21 @@ typedef enum argtype {
> TYPE_ARRAY,
> TYPE_STRUCT,
> TYPE_OLDDEVT,
> + TYPE_FLEXIBLE_ARRAY,
> } argtype;
>
> #define MK_PTR(type) TYPE_PTR, type
> #define MK_ARRAY(type, size) TYPE_ARRAY, size, type
> #define MK_STRUCT(id) TYPE_STRUCT, id
>
> +/*
> + * Should only appear as the last element of a TYPE_STRUCT.
> `len_field_idx` is
> + * the index into the fields in the enclosing struct that specify the
> length of
> + * the flexibly array. The length field MUST be a TYPE_INT field.
> + */
> +#define MK_FLEXIBLE_ARRAY(type, len_field_idx) \
> + TYPE_FLEXIBLE_ARRAY, (len_field_idx), type
> +
> #define THUNK_TARGET 0
> #define THUNK_HOST 1
>
> @@ -55,6 +64,8 @@ typedef struct {
> int *field_offsets[2];
> /* special handling */
> void (*convert[2])(void *dst, const void *src);
> + int (*thunk_size[2])(const void *src);
> +
> int size[2];
> int align[2];
> const char *name;
> @@ -75,6 +86,11 @@ const argtype *thunk_convert(void *dst, const void *src,
> const argtype *type_ptr, int to_host);
> const argtype *thunk_print(void *arg, const argtype *type_ptr);
>
> +bool thunk_type_has_flexible_array(const argtype *type_ptr);
> +/* thunk_type_size but can handle TYPE_FLEXIBLE_ARRAY */
> +int thunk_type_size_with_src(const void *src, const argtype *type_ptr,
> + int is_host);
> +
> extern StructEntry *struct_entries;
>
> int thunk_type_size_array(const argtype *type_ptr, int is_host);
> @@ -137,6 +153,12 @@ static inline int thunk_type_size(const argtype
> *type_ptr, int is_host)
> case TYPE_STRUCT:
> se = struct_entries + type_ptr[1];
> return se->size[is_host];
> + case TYPE_FLEXIBLE_ARRAY:
> + /*
> + * Flexible arrays do not count toward sizeof(). Users of
> structures
> + * containing them need to calculate it themselves.
> + */
> + return 0;
> default:
> g_assert_not_reached();
> }
> @@ -187,6 +209,8 @@ static inline int thunk_type_align(const argtype
> *type_ptr, int is_host)
> case TYPE_STRUCT:
> se = struct_entries + type_ptr[1];
> return se->align[is_host];
> + case TYPE_FLEXIBLE_ARRAY:
> + return thunk_type_align_array(type_ptr + 2, is_host);
> default:
> g_assert_not_reached();
> }
> diff --git a/thunk.c b/thunk.c
> index c5d9719747..d9c6cba3bd 100644
> --- a/thunk.c
> +++ b/thunk.c
> @@ -50,6 +50,8 @@ static inline const argtype *thunk_type_next(const
> argtype *type_ptr)
> return thunk_type_next_ptr(type_ptr + 1);
> case TYPE_STRUCT:
> return type_ptr + 1;
> + case TYPE_FLEXIBLE_ARRAY:
> + return thunk_type_next_ptr(type_ptr + 1);
> default:
> return NULL;
> }
> @@ -122,6 +124,34 @@ void thunk_register_struct_direct(int id, const char
> *name,
> se->name = name;
> }
>
> +static const argtype *
> +thunk_convert_flexible_array(void *dst, const void *src,
> + const uint8_t *dst_struct,
> + const uint8_t *src_struct, const argtype
> *type_ptr,
> + const StructEntry *se, int to_host) {
> + int len_field_idx, dst_size, src_size, i;
> + uint32_t array_length;
> + uint8_t *d;
> + const uint8_t *s;
> +
> + assert(*type_ptr == TYPE_FLEXIBLE_ARRAY);
> + type_ptr++;
> + len_field_idx = *type_ptr++;
> + array_length =
> + *(const uint32_t *)(to_host ?
> + dst_struct +
> se->field_offsets[1][len_field_idx] :
> + src_struct +
> se->field_offsets[0][len_field_idx]);
> + dst_size = thunk_type_size(type_ptr, to_host);
> + src_size = thunk_type_size(type_ptr, to_host);
> + d = dst;
> + s = src;
> + for (i = 0; i < array_length; i++) {
> + thunk_convert(d, s, type_ptr, to_host);
> + d += dst_size;
> + s += src_size;
> + }
> + return thunk_type_next(type_ptr);
> +}
>
> /* now we can define the main conversion functions */
> const argtype *thunk_convert(void *dst, const void *src,
> @@ -246,7 +276,7 @@ const argtype *thunk_convert(void *dst, const void
> *src,
>
> assert(*type_ptr < max_struct_entries);
> se = struct_entries + *type_ptr++;
> - if (se->convert[0] != NULL) {
> + if (se->convert[to_host] != NULL) {
> /* specific conversion is needed */
> (*se->convert[to_host])(dst, src);
> } else {
> @@ -256,7 +286,18 @@ const argtype *thunk_convert(void *dst, const void
> *src,
> src_offsets = se->field_offsets[1 - to_host];
> d = dst;
> s = src;
> - for(i = 0;i < se->nb_fields; i++) {
> + for (i = 0; i < se->nb_fields; i++) {
> + if (*field_types == TYPE_FLEXIBLE_ARRAY) {
> + field_types = thunk_convert_flexible_array(
> + d + dst_offsets[i],
> + s + src_offsets[i],
> + d,
> + s,
> + field_types,
> + se,
> + to_host);
> + continue;
> + }
> field_types = thunk_convert(d + dst_offsets[i],
> s + src_offsets[i],
> field_types, to_host);
> @@ -264,6 +305,11 @@ const argtype *thunk_convert(void *dst, const void
> *src,
> }
> }
> break;
> + case TYPE_FLEXIBLE_ARRAY:
> + fprintf(stderr,
> + "Invalid flexible array (type 0x%x) outside of a
> structure\n",
> + type);
> + break;
> default:
> fprintf(stderr, "Invalid type 0x%x\n", type);
> break;
> @@ -271,6 +317,45 @@ const argtype *thunk_convert(void *dst, const void
> *src,
> return type_ptr;
> }
>
> +static const argtype *
> +thunk_print_flexible_array(void *arg, const uint8_t *arg_struct,
> + const argtype *type_ptr, const StructEntry
> *se) {
> + int array_length, len_field_idx, arg_size, i;
> + uint8_t *a;
> + int is_string = 0;
> +
> + assert(*type_ptr == TYPE_FLEXIBLE_ARRAY);
> + type_ptr++;
> + len_field_idx = *type_ptr++;
> +
> + array_length = tswap32(
> + *(const uint32_t *)(arg_struct +
> se->field_offsets[0][len_field_idx]));
> + arg_size = thunk_type_size(type_ptr, 0);
> + a = arg;
> +
> + if (*type_ptr == TYPE_CHAR) {
> + qemu_log("\"");
> + is_string = 1;
> + } else {
> + qemu_log("[");
> + }
> +
> + for (i = 0; i < array_length; i++) {
> + if (i > 0 && !is_string) {
> + qemu_log(",");
> + }
> + thunk_print(a, type_ptr);
> + a += arg_size;
> + }
> +
> + if (is_string) {
> + qemu_log("\"");
> + } else {
> + qemu_log("]");
> + }
> + return thunk_type_next(type_ptr);
> +}
> +
> const argtype *thunk_print(void *arg, const argtype *type_ptr)
> {
> int type;
> @@ -414,17 +499,80 @@ const argtype *thunk_print(void *arg, const argtype
> *type_ptr)
> if (i > 0) {
> qemu_log(",");
> }
> + if (*field_types == TYPE_FLEXIBLE_ARRAY) {
> + field_types = thunk_print_flexible_array(
> + a + arg_offsets[i], a, field_types, se);
> + continue;
> + }
> field_types = thunk_print(a + arg_offsets[i],
> field_types);
> }
> qemu_log("}");
> }
> break;
> + case TYPE_FLEXIBLE_ARRAY:
> + fprintf(stderr,
> + "Invalid flexible array (type 0x%x) outside of a
> structure\n",
> + type);
> + break;
> default:
> g_assert_not_reached();
> }
> return type_ptr;
> }
>
> +bool thunk_type_has_flexible_array(const argtype *type_ptr)
> +{
> + int i;
> + const StructEntry *se;
> + const argtype *field_types;
> + if (*type_ptr != TYPE_STRUCT) {
> + return false;
> + }
> + se = struct_entries + type_ptr[1];
> + field_types = se->field_types;
> + for (i = 0; i < se->nb_fields; i++) {
> + if (*field_types == TYPE_FLEXIBLE_ARRAY) {
> + return true;
> + }
> + field_types = thunk_type_next(type_ptr);
> + }
> + return false;
> +}
> +
> +int thunk_type_size_with_src(const void *src, const argtype *type_ptr,
> + int is_host)
> +{
> + switch (*type_ptr) {
> + case TYPE_STRUCT: {
> + int i;
> + const StructEntry *se = struct_entries + type_ptr[1];
> + const argtype *field_types;
> + if (se->thunk_size[is_host] != NULL) {
> + return (*se->thunk_size[is_host])(src);
> + }
> +
> + field_types = se->field_types;
> + for (i = 0; i < se->nb_fields; i++) {
> + if (*field_types == TYPE_FLEXIBLE_ARRAY) {
> + uint32_t array_length = *(const uint32_t *)(
> + (const uint8_t *)src +
> + se->field_offsets[is_host][field_types[1]]);
> + if (!is_host) {
> + array_length = tswap32(array_length);
> + }
> + return se->size[is_host] +
> + array_length *
> + thunk_type_size(field_types + 2, is_host);
> + }
> + field_types = thunk_type_next(type_ptr);
> + }
> + return se->size[is_host];
> + }
> + default:
> + return thunk_type_size(type_ptr, is_host);
> + }
> +}
> +
> /* from em86 */
>
> /* Utility function: Table-driven functions to translate bitmasks
> --
> 2.28.0.220.ged08abb693-goog
>
>
smime.p7s
Description: S/MIME Cryptographic Signature
