Forgot to +riku.voi...@iki.fi when generating v2.

On Tue, Aug 11, 2020 at 12:10 AM Shu-Chun Weng <s...@google.com> 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 <s...@google.com>
> ---
> 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
>
>

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature

Reply via email to