Ping -- any comments on
https://patchew.org/QEMU/cover.1597129029.git....@google.com/e0754f52180aee6418eae8b3b8aa5981fcac12fd.1597129029.git....@google.com/

On Tue, Aug 11, 2020 at 2:39 PM Shu-Chun Weng <s...@google.com> wrote:

> 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