cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

types.py (10742B)


      1"""
      2QAPI types generator
      3
      4Copyright IBM, Corp. 2011
      5Copyright (c) 2013-2018 Red Hat Inc.
      6
      7Authors:
      8 Anthony Liguori <aliguori@us.ibm.com>
      9 Michael Roth <mdroth@linux.vnet.ibm.com>
     10 Markus Armbruster <armbru@redhat.com>
     11
     12This work is licensed under the terms of the GNU GPL, version 2.
     13# See the COPYING file in the top-level directory.
     14"""
     15
     16from typing import List, Optional
     17
     18from .common import c_enum_const, c_name, mcgen
     19from .gen import QAPISchemaModularCVisitor, ifcontext
     20from .schema import (
     21    QAPISchema,
     22    QAPISchemaEnumMember,
     23    QAPISchemaFeature,
     24    QAPISchemaIfCond,
     25    QAPISchemaObjectType,
     26    QAPISchemaObjectTypeMember,
     27    QAPISchemaType,
     28    QAPISchemaVariants,
     29)
     30from .source import QAPISourceInfo
     31
     32
     33# variants must be emitted before their container; track what has already
     34# been output
     35objects_seen = set()
     36
     37
     38def gen_enum_lookup(name: str,
     39                    members: List[QAPISchemaEnumMember],
     40                    prefix: Optional[str] = None) -> str:
     41    ret = mcgen('''
     42
     43const QEnumLookup %(c_name)s_lookup = {
     44    .array = (const char *const[]) {
     45''',
     46                c_name=c_name(name))
     47    for memb in members:
     48        ret += memb.ifcond.gen_if()
     49        index = c_enum_const(name, memb.name, prefix)
     50        ret += mcgen('''
     51        [%(index)s] = "%(name)s",
     52''',
     53                     index=index, name=memb.name)
     54        ret += memb.ifcond.gen_endif()
     55
     56    ret += mcgen('''
     57    },
     58    .size = %(max_index)s
     59};
     60''',
     61                 max_index=c_enum_const(name, '_MAX', prefix))
     62    return ret
     63
     64
     65def gen_enum(name: str,
     66             members: List[QAPISchemaEnumMember],
     67             prefix: Optional[str] = None) -> str:
     68    # append automatically generated _MAX value
     69    enum_members = members + [QAPISchemaEnumMember('_MAX', None)]
     70
     71    ret = mcgen('''
     72
     73typedef enum %(c_name)s {
     74''',
     75                c_name=c_name(name))
     76
     77    for memb in enum_members:
     78        ret += memb.ifcond.gen_if()
     79        ret += mcgen('''
     80    %(c_enum)s,
     81''',
     82                     c_enum=c_enum_const(name, memb.name, prefix))
     83        ret += memb.ifcond.gen_endif()
     84
     85    ret += mcgen('''
     86} %(c_name)s;
     87''',
     88                 c_name=c_name(name))
     89
     90    ret += mcgen('''
     91
     92#define %(c_name)s_str(val) \\
     93    qapi_enum_lookup(&%(c_name)s_lookup, (val))
     94
     95extern const QEnumLookup %(c_name)s_lookup;
     96''',
     97                 c_name=c_name(name))
     98    return ret
     99
    100
    101def gen_fwd_object_or_array(name: str) -> str:
    102    return mcgen('''
    103
    104typedef struct %(c_name)s %(c_name)s;
    105''',
    106                 c_name=c_name(name))
    107
    108
    109def gen_array(name: str, element_type: QAPISchemaType) -> str:
    110    return mcgen('''
    111
    112struct %(c_name)s {
    113    %(c_name)s *next;
    114    %(c_type)s value;
    115};
    116''',
    117                 c_name=c_name(name), c_type=element_type.c_type())
    118
    119
    120def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
    121    ret = ''
    122    for memb in members:
    123        ret += memb.ifcond.gen_if()
    124        if memb.optional:
    125            ret += mcgen('''
    126    bool has_%(c_name)s;
    127''',
    128                         c_name=c_name(memb.name))
    129        ret += mcgen('''
    130    %(c_type)s %(c_name)s;
    131''',
    132                     c_type=memb.type.c_type(), c_name=c_name(memb.name))
    133        ret += memb.ifcond.gen_endif()
    134    return ret
    135
    136
    137def gen_object(name: str, ifcond: QAPISchemaIfCond,
    138               base: Optional[QAPISchemaObjectType],
    139               members: List[QAPISchemaObjectTypeMember],
    140               variants: Optional[QAPISchemaVariants]) -> str:
    141    if name in objects_seen:
    142        return ''
    143    objects_seen.add(name)
    144
    145    ret = ''
    146    for var in variants.variants if variants else ():
    147        obj = var.type
    148        if not isinstance(obj, QAPISchemaObjectType):
    149            continue
    150        ret += gen_object(obj.name, obj.ifcond, obj.base,
    151                          obj.local_members, obj.variants)
    152
    153    ret += mcgen('''
    154
    155''')
    156    ret += ifcond.gen_if()
    157    ret += mcgen('''
    158struct %(c_name)s {
    159''',
    160                 c_name=c_name(name))
    161
    162    if base:
    163        if not base.is_implicit():
    164            ret += mcgen('''
    165    /* Members inherited from %(c_name)s: */
    166''',
    167                         c_name=base.c_name())
    168        ret += gen_struct_members(base.members)
    169        if not base.is_implicit():
    170            ret += mcgen('''
    171    /* Own members: */
    172''')
    173    ret += gen_struct_members(members)
    174
    175    if variants:
    176        ret += gen_variants(variants)
    177
    178    # Make sure that all structs have at least one member; this avoids
    179    # potential issues with attempting to malloc space for zero-length
    180    # structs in C, and also incompatibility with C++ (where an empty
    181    # struct is size 1).
    182    if (not base or base.is_empty()) and not members and not variants:
    183        ret += mcgen('''
    184    char qapi_dummy_for_empty_struct;
    185''')
    186
    187    ret += mcgen('''
    188};
    189''')
    190    ret += ifcond.gen_endif()
    191
    192    return ret
    193
    194
    195def gen_upcast(name: str, base: QAPISchemaObjectType) -> str:
    196    # C makes const-correctness ugly.  We have to cast away const to let
    197    # this function work for both const and non-const obj.
    198    return mcgen('''
    199
    200static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)
    201{
    202    return (%(base)s *)obj;
    203}
    204''',
    205                 c_name=c_name(name), base=base.c_name())
    206
    207
    208def gen_variants(variants: QAPISchemaVariants) -> str:
    209    ret = mcgen('''
    210    union { /* union tag is @%(c_name)s */
    211''',
    212                c_name=c_name(variants.tag_member.name))
    213
    214    for var in variants.variants:
    215        if var.type.name == 'q_empty':
    216            continue
    217        ret += var.ifcond.gen_if()
    218        ret += mcgen('''
    219        %(c_type)s %(c_name)s;
    220''',
    221                     c_type=var.type.c_unboxed_type(),
    222                     c_name=c_name(var.name))
    223        ret += var.ifcond.gen_endif()
    224
    225    ret += mcgen('''
    226    } u;
    227''')
    228
    229    return ret
    230
    231
    232def gen_type_cleanup_decl(name: str) -> str:
    233    ret = mcgen('''
    234
    235void qapi_free_%(c_name)s(%(c_name)s *obj);
    236G_DEFINE_AUTOPTR_CLEANUP_FUNC(%(c_name)s, qapi_free_%(c_name)s)
    237''',
    238                c_name=c_name(name))
    239    return ret
    240
    241
    242def gen_type_cleanup(name: str) -> str:
    243    ret = mcgen('''
    244
    245void qapi_free_%(c_name)s(%(c_name)s *obj)
    246{
    247    Visitor *v;
    248
    249    if (!obj) {
    250        return;
    251    }
    252
    253    v = qapi_dealloc_visitor_new();
    254    visit_type_%(c_name)s(v, NULL, &obj, NULL);
    255    visit_free(v);
    256}
    257''',
    258                c_name=c_name(name))
    259    return ret
    260
    261
    262class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
    263
    264    def __init__(self, prefix: str):
    265        super().__init__(
    266            prefix, 'qapi-types', ' * Schema-defined QAPI types',
    267            ' * Built-in QAPI types', __doc__)
    268
    269    def _begin_builtin_module(self) -> None:
    270        self._genc.preamble_add(mcgen('''
    271#include "qemu/osdep.h"
    272#include "qapi/dealloc-visitor.h"
    273#include "qapi/qapi-builtin-types.h"
    274#include "qapi/qapi-builtin-visit.h"
    275'''))
    276        self._genh.preamble_add(mcgen('''
    277#include "qapi/util.h"
    278'''))
    279
    280    def _begin_user_module(self, name: str) -> None:
    281        types = self._module_basename('qapi-types', name)
    282        visit = self._module_basename('qapi-visit', name)
    283        self._genc.preamble_add(mcgen('''
    284#include "qemu/osdep.h"
    285#include "qapi/dealloc-visitor.h"
    286#include "%(types)s.h"
    287#include "%(visit)s.h"
    288''',
    289                                      types=types, visit=visit))
    290        self._genh.preamble_add(mcgen('''
    291#include "qapi/qapi-builtin-types.h"
    292'''))
    293
    294    def visit_begin(self, schema: QAPISchema) -> None:
    295        # gen_object() is recursive, ensure it doesn't visit the empty type
    296        objects_seen.add(schema.the_empty_object_type.name)
    297
    298    def _gen_type_cleanup(self, name: str) -> None:
    299        self._genh.add(gen_type_cleanup_decl(name))
    300        self._genc.add(gen_type_cleanup(name))
    301
    302    def visit_enum_type(self,
    303                        name: str,
    304                        info: Optional[QAPISourceInfo],
    305                        ifcond: QAPISchemaIfCond,
    306                        features: List[QAPISchemaFeature],
    307                        members: List[QAPISchemaEnumMember],
    308                        prefix: Optional[str]) -> None:
    309        with ifcontext(ifcond, self._genh, self._genc):
    310            self._genh.preamble_add(gen_enum(name, members, prefix))
    311            self._genc.add(gen_enum_lookup(name, members, prefix))
    312
    313    def visit_array_type(self,
    314                         name: str,
    315                         info: Optional[QAPISourceInfo],
    316                         ifcond: QAPISchemaIfCond,
    317                         element_type: QAPISchemaType) -> None:
    318        with ifcontext(ifcond, self._genh, self._genc):
    319            self._genh.preamble_add(gen_fwd_object_or_array(name))
    320            self._genh.add(gen_array(name, element_type))
    321            self._gen_type_cleanup(name)
    322
    323    def visit_object_type(self,
    324                          name: str,
    325                          info: Optional[QAPISourceInfo],
    326                          ifcond: QAPISchemaIfCond,
    327                          features: List[QAPISchemaFeature],
    328                          base: Optional[QAPISchemaObjectType],
    329                          members: List[QAPISchemaObjectTypeMember],
    330                          variants: Optional[QAPISchemaVariants]) -> None:
    331        # Nothing to do for the special empty builtin
    332        if name == 'q_empty':
    333            return
    334        with ifcontext(ifcond, self._genh):
    335            self._genh.preamble_add(gen_fwd_object_or_array(name))
    336        self._genh.add(gen_object(name, ifcond, base, members, variants))
    337        with ifcontext(ifcond, self._genh, self._genc):
    338            if base and not base.is_implicit():
    339                self._genh.add(gen_upcast(name, base))
    340            # TODO Worth changing the visitor signature, so we could
    341            # directly use rather than repeat type.is_implicit()?
    342            if not name.startswith('q_'):
    343                # implicit types won't be directly allocated/freed
    344                self._gen_type_cleanup(name)
    345
    346    def visit_alternate_type(self,
    347                             name: str,
    348                             info: Optional[QAPISourceInfo],
    349                             ifcond: QAPISchemaIfCond,
    350                             features: List[QAPISchemaFeature],
    351                             variants: QAPISchemaVariants) -> None:
    352        with ifcontext(ifcond, self._genh):
    353            self._genh.preamble_add(gen_fwd_object_or_array(name))
    354        self._genh.add(gen_object(name, ifcond, None,
    355                                  [variants.tag_member], variants))
    356        with ifcontext(ifcond, self._genh, self._genc):
    357            self._gen_type_cleanup(name)
    358
    359
    360def gen_types(schema: QAPISchema,
    361              output_dir: str,
    362              prefix: str,
    363              opt_builtins: bool) -> None:
    364    vis = QAPISchemaGenTypeVisitor(prefix)
    365    schema.visit(vis)
    366    vis.write(output_dir, opt_builtins)