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

visit.py (11966B)


      1"""
      2QAPI visitor generator
      3
      4Copyright IBM, Corp. 2011
      5Copyright (C) 2014-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.
     13See the COPYING file in the top-level directory.
     14"""
     15
     16from typing import List, Optional
     17
     18from .common import (
     19    c_enum_const,
     20    c_name,
     21    indent,
     22    mcgen,
     23)
     24from .gen import QAPISchemaModularCVisitor, ifcontext
     25from .schema import (
     26    QAPISchema,
     27    QAPISchemaEnumMember,
     28    QAPISchemaEnumType,
     29    QAPISchemaFeature,
     30    QAPISchemaIfCond,
     31    QAPISchemaObjectType,
     32    QAPISchemaObjectTypeMember,
     33    QAPISchemaType,
     34    QAPISchemaVariants,
     35)
     36from .source import QAPISourceInfo
     37
     38
     39def gen_visit_decl(name: str, scalar: bool = False) -> str:
     40    c_type = c_name(name) + ' *'
     41    if not scalar:
     42        c_type += '*'
     43    return mcgen('''
     44
     45bool visit_type_%(c_name)s(Visitor *v, const char *name,
     46                 %(c_type)sobj, Error **errp);
     47''',
     48                 c_name=c_name(name), c_type=c_type)
     49
     50
     51def gen_visit_members_decl(name: str) -> str:
     52    return mcgen('''
     53
     54bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp);
     55''',
     56                 c_name=c_name(name))
     57
     58
     59def gen_visit_object_members(name: str,
     60                             base: Optional[QAPISchemaObjectType],
     61                             members: List[QAPISchemaObjectTypeMember],
     62                             variants: Optional[QAPISchemaVariants]) -> str:
     63    ret = mcgen('''
     64
     65bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
     66{
     67''',
     68                c_name=c_name(name))
     69
     70    if base:
     71        ret += mcgen('''
     72    if (!visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, errp)) {
     73        return false;
     74    }
     75''',
     76                     c_type=base.c_name())
     77
     78    for memb in members:
     79        deprecated = 'deprecated' in [f.name for f in memb.features]
     80        ret += memb.ifcond.gen_if()
     81        if memb.optional:
     82            ret += mcgen('''
     83    if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
     84''',
     85                         name=memb.name, c_name=c_name(memb.name))
     86            indent.increase()
     87        if deprecated:
     88            ret += mcgen('''
     89    if (!visit_deprecated_accept(v, "%(name)s", errp)) {
     90        return false;
     91    }
     92    if (visit_deprecated(v, "%(name)s")) {
     93''',
     94                         name=memb.name)
     95            indent.increase()
     96        ret += mcgen('''
     97    if (!visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, errp)) {
     98        return false;
     99    }
    100''',
    101                     c_type=memb.type.c_name(), name=memb.name,
    102                     c_name=c_name(memb.name))
    103        if deprecated:
    104            indent.decrease()
    105            ret += mcgen('''
    106    }
    107''')
    108        if memb.optional:
    109            indent.decrease()
    110            ret += mcgen('''
    111    }
    112''')
    113        ret += memb.ifcond.gen_endif()
    114
    115    if variants:
    116        tag_member = variants.tag_member
    117        assert isinstance(tag_member.type, QAPISchemaEnumType)
    118
    119        ret += mcgen('''
    120    switch (obj->%(c_name)s) {
    121''',
    122                     c_name=c_name(tag_member.name))
    123
    124        for var in variants.variants:
    125            case_str = c_enum_const(tag_member.type.name, var.name,
    126                                    tag_member.type.prefix)
    127            ret += var.ifcond.gen_if()
    128            if var.type.name == 'q_empty':
    129                # valid variant and nothing to do
    130                ret += mcgen('''
    131    case %(case)s:
    132        break;
    133''',
    134                             case=case_str)
    135            else:
    136                ret += mcgen('''
    137    case %(case)s:
    138        return visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, errp);
    139''',
    140                             case=case_str,
    141                             c_type=var.type.c_name(), c_name=c_name(var.name))
    142
    143            ret += var.ifcond.gen_endif()
    144        ret += mcgen('''
    145    default:
    146        abort();
    147    }
    148''')
    149
    150    ret += mcgen('''
    151    return true;
    152}
    153''')
    154    return ret
    155
    156
    157def gen_visit_list(name: str, element_type: QAPISchemaType) -> str:
    158    return mcgen('''
    159
    160bool visit_type_%(c_name)s(Visitor *v, const char *name,
    161                 %(c_name)s **obj, Error **errp)
    162{
    163    bool ok = false;
    164    %(c_name)s *tail;
    165    size_t size = sizeof(**obj);
    166
    167    if (!visit_start_list(v, name, (GenericList **)obj, size, errp)) {
    168        return false;
    169    }
    170
    171    for (tail = *obj; tail;
    172         tail = (%(c_name)s *)visit_next_list(v, (GenericList *)tail, size)) {
    173        if (!visit_type_%(c_elt_type)s(v, NULL, &tail->value, errp)) {
    174            goto out_obj;
    175        }
    176    }
    177
    178    ok = visit_check_list(v, errp);
    179out_obj:
    180    visit_end_list(v, (void **)obj);
    181    if (!ok && visit_is_input(v)) {
    182        qapi_free_%(c_name)s(*obj);
    183        *obj = NULL;
    184    }
    185    return ok;
    186}
    187''',
    188                 c_name=c_name(name), c_elt_type=element_type.c_name())
    189
    190
    191def gen_visit_enum(name: str) -> str:
    192    return mcgen('''
    193
    194bool visit_type_%(c_name)s(Visitor *v, const char *name,
    195                 %(c_name)s *obj, Error **errp)
    196{
    197    int value = *obj;
    198    bool ok = visit_type_enum(v, name, &value, &%(c_name)s_lookup, errp);
    199    *obj = value;
    200    return ok;
    201}
    202''',
    203                 c_name=c_name(name))
    204
    205
    206def gen_visit_alternate(name: str, variants: QAPISchemaVariants) -> str:
    207    ret = mcgen('''
    208
    209bool visit_type_%(c_name)s(Visitor *v, const char *name,
    210                 %(c_name)s **obj, Error **errp)
    211{
    212    bool ok = false;
    213
    214    if (!visit_start_alternate(v, name, (GenericAlternate **)obj,
    215                               sizeof(**obj), errp)) {
    216        return false;
    217    }
    218    if (!*obj) {
    219        /* incomplete */
    220        assert(visit_is_dealloc(v));
    221        ok = true;
    222        goto out_obj;
    223    }
    224    switch ((*obj)->type) {
    225''',
    226                c_name=c_name(name))
    227
    228    for var in variants.variants:
    229        ret += var.ifcond.gen_if()
    230        ret += mcgen('''
    231    case %(case)s:
    232''',
    233                     case=var.type.alternate_qtype())
    234        if isinstance(var.type, QAPISchemaObjectType):
    235            ret += mcgen('''
    236        if (!visit_start_struct(v, name, NULL, 0, errp)) {
    237            break;
    238        }
    239        if (visit_type_%(c_type)s_members(v, &(*obj)->u.%(c_name)s, errp)) {
    240            ok = visit_check_struct(v, errp);
    241        }
    242        visit_end_struct(v, NULL);
    243''',
    244                         c_type=var.type.c_name(),
    245                         c_name=c_name(var.name))
    246        else:
    247            ret += mcgen('''
    248        ok = visit_type_%(c_type)s(v, name, &(*obj)->u.%(c_name)s, errp);
    249''',
    250                         c_type=var.type.c_name(),
    251                         c_name=c_name(var.name))
    252        ret += mcgen('''
    253        break;
    254''')
    255        ret += var.ifcond.gen_endif()
    256
    257    ret += mcgen('''
    258    case QTYPE_NONE:
    259        abort();
    260    default:
    261        assert(visit_is_input(v));
    262        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
    263                   "%(name)s");
    264        /* Avoid passing invalid *obj to qapi_free_%(c_name)s() */
    265        g_free(*obj);
    266        *obj = NULL;
    267    }
    268out_obj:
    269    visit_end_alternate(v, (void **)obj);
    270    if (!ok && visit_is_input(v)) {
    271        qapi_free_%(c_name)s(*obj);
    272        *obj = NULL;
    273    }
    274    return ok;
    275}
    276''',
    277                 name=name, c_name=c_name(name))
    278
    279    return ret
    280
    281
    282def gen_visit_object(name: str) -> str:
    283    return mcgen('''
    284
    285bool visit_type_%(c_name)s(Visitor *v, const char *name,
    286                 %(c_name)s **obj, Error **errp)
    287{
    288    bool ok = false;
    289
    290    if (!visit_start_struct(v, name, (void **)obj, sizeof(%(c_name)s), errp)) {
    291        return false;
    292    }
    293    if (!*obj) {
    294        /* incomplete */
    295        assert(visit_is_dealloc(v));
    296        ok = true;
    297        goto out_obj;
    298    }
    299    if (!visit_type_%(c_name)s_members(v, *obj, errp)) {
    300        goto out_obj;
    301    }
    302    ok = visit_check_struct(v, errp);
    303out_obj:
    304    visit_end_struct(v, (void **)obj);
    305    if (!ok && visit_is_input(v)) {
    306        qapi_free_%(c_name)s(*obj);
    307        *obj = NULL;
    308    }
    309    return ok;
    310}
    311''',
    312                 c_name=c_name(name))
    313
    314
    315class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
    316
    317    def __init__(self, prefix: str):
    318        super().__init__(
    319            prefix, 'qapi-visit', ' * Schema-defined QAPI visitors',
    320            ' * Built-in QAPI visitors', __doc__)
    321
    322    def _begin_builtin_module(self) -> None:
    323        self._genc.preamble_add(mcgen('''
    324#include "qemu/osdep.h"
    325#include "qapi/error.h"
    326#include "qapi/qapi-builtin-visit.h"
    327'''))
    328        self._genh.preamble_add(mcgen('''
    329#include "qapi/visitor.h"
    330#include "qapi/qapi-builtin-types.h"
    331
    332'''))
    333
    334    def _begin_user_module(self, name: str) -> None:
    335        types = self._module_basename('qapi-types', name)
    336        visit = self._module_basename('qapi-visit', name)
    337        self._genc.preamble_add(mcgen('''
    338#include "qemu/osdep.h"
    339#include "qapi/error.h"
    340#include "qapi/qmp/qerror.h"
    341#include "%(visit)s.h"
    342''',
    343                                      visit=visit))
    344        self._genh.preamble_add(mcgen('''
    345#include "qapi/qapi-builtin-visit.h"
    346#include "%(types)s.h"
    347
    348''',
    349                                      types=types))
    350
    351    def visit_enum_type(self,
    352                        name: str,
    353                        info: Optional[QAPISourceInfo],
    354                        ifcond: QAPISchemaIfCond,
    355                        features: List[QAPISchemaFeature],
    356                        members: List[QAPISchemaEnumMember],
    357                        prefix: Optional[str]) -> None:
    358        with ifcontext(ifcond, self._genh, self._genc):
    359            self._genh.add(gen_visit_decl(name, scalar=True))
    360            self._genc.add(gen_visit_enum(name))
    361
    362    def visit_array_type(self,
    363                         name: str,
    364                         info: Optional[QAPISourceInfo],
    365                         ifcond: QAPISchemaIfCond,
    366                         element_type: QAPISchemaType) -> None:
    367        with ifcontext(ifcond, self._genh, self._genc):
    368            self._genh.add(gen_visit_decl(name))
    369            self._genc.add(gen_visit_list(name, element_type))
    370
    371    def visit_object_type(self,
    372                          name: str,
    373                          info: Optional[QAPISourceInfo],
    374                          ifcond: QAPISchemaIfCond,
    375                          features: List[QAPISchemaFeature],
    376                          base: Optional[QAPISchemaObjectType],
    377                          members: List[QAPISchemaObjectTypeMember],
    378                          variants: Optional[QAPISchemaVariants]) -> None:
    379        # Nothing to do for the special empty builtin
    380        if name == 'q_empty':
    381            return
    382        with ifcontext(ifcond, self._genh, self._genc):
    383            self._genh.add(gen_visit_members_decl(name))
    384            self._genc.add(gen_visit_object_members(name, base,
    385                                                    members, variants))
    386            # TODO Worth changing the visitor signature, so we could
    387            # directly use rather than repeat type.is_implicit()?
    388            if not name.startswith('q_'):
    389                # only explicit types need an allocating visit
    390                self._genh.add(gen_visit_decl(name))
    391                self._genc.add(gen_visit_object(name))
    392
    393    def visit_alternate_type(self,
    394                             name: str,
    395                             info: Optional[QAPISourceInfo],
    396                             ifcond: QAPISchemaIfCond,
    397                             features: List[QAPISchemaFeature],
    398                             variants: QAPISchemaVariants) -> None:
    399        with ifcontext(ifcond, self._genh, self._genc):
    400            self._genh.add(gen_visit_decl(name))
    401            self._genc.add(gen_visit_alternate(name, variants))
    402
    403
    404def gen_visit(schema: QAPISchema,
    405              output_dir: str,
    406              prefix: str,
    407              opt_builtins: bool) -> None:
    408    vis = QAPISchemaGenVisitVisitor(prefix)
    409    schema.visit(vis)
    410    vis.write(output_dir, opt_builtins)