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

common.py (7674B)


      1#
      2# QAPI helper library
      3#
      4# Copyright IBM, Corp. 2011
      5# Copyright (c) 2013-2018 Red Hat Inc.
      6#
      7# Authors:
      8#  Anthony Liguori <aliguori@us.ibm.com>
      9#  Markus Armbruster <armbru@redhat.com>
     10#
     11# This work is licensed under the terms of the GNU GPL, version 2.
     12# See the COPYING file in the top-level directory.
     13
     14import re
     15from typing import (
     16    Any,
     17    Dict,
     18    Match,
     19    Optional,
     20    Sequence,
     21    Union,
     22)
     23
     24
     25#: Magic string that gets removed along with all space to its right.
     26EATSPACE = '\033EATSPACE.'
     27POINTER_SUFFIX = ' *' + EATSPACE
     28
     29
     30def camel_to_upper(value: str) -> str:
     31    """
     32    Converts CamelCase to CAMEL_CASE.
     33
     34    Examples::
     35
     36        ENUMName -> ENUM_NAME
     37        EnumName1 -> ENUM_NAME1
     38        ENUM_NAME -> ENUM_NAME
     39        ENUM_NAME1 -> ENUM_NAME1
     40        ENUM_Name2 -> ENUM_NAME2
     41        ENUM24_Name -> ENUM24_NAME
     42    """
     43    c_fun_str = c_name(value, False)
     44    if value.isupper():
     45        return c_fun_str
     46
     47    new_name = ''
     48    length = len(c_fun_str)
     49    for i in range(length):
     50        char = c_fun_str[i]
     51        # When char is upper case and no '_' appears before, do more checks
     52        if char.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
     53            if i < length - 1 and c_fun_str[i + 1].islower():
     54                new_name += '_'
     55            elif c_fun_str[i - 1].isdigit():
     56                new_name += '_'
     57        new_name += char
     58    return new_name.lstrip('_').upper()
     59
     60
     61def c_enum_const(type_name: str,
     62                 const_name: str,
     63                 prefix: Optional[str] = None) -> str:
     64    """
     65    Generate a C enumeration constant name.
     66
     67    :param type_name: The name of the enumeration.
     68    :param const_name: The name of this constant.
     69    :param prefix: Optional, prefix that overrides the type_name.
     70    """
     71    if prefix is not None:
     72        type_name = prefix
     73    return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
     74
     75
     76def c_name(name: str, protect: bool = True) -> str:
     77    """
     78    Map ``name`` to a valid C identifier.
     79
     80    Used for converting 'name' from a 'name':'type' qapi definition
     81    into a generated struct member, as well as converting type names
     82    into substrings of a generated C function name.
     83
     84    '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
     85    protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
     86
     87    :param name: The name to map.
     88    :param protect: If true, avoid returning certain ticklish identifiers
     89                    (like C keywords) by prepending ``q_``.
     90    """
     91    # ANSI X3J11/88-090, 3.1.1
     92    c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
     93                     'default', 'do', 'double', 'else', 'enum', 'extern',
     94                     'float', 'for', 'goto', 'if', 'int', 'long', 'register',
     95                     'return', 'short', 'signed', 'sizeof', 'static',
     96                     'struct', 'switch', 'typedef', 'union', 'unsigned',
     97                     'void', 'volatile', 'while'])
     98    # ISO/IEC 9899:1999, 6.4.1
     99    c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
    100    # ISO/IEC 9899:2011, 6.4.1
    101    c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
    102                     '_Noreturn', '_Static_assert', '_Thread_local'])
    103    # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
    104    # excluding _.*
    105    gcc_words = set(['asm', 'typeof'])
    106    # C++ ISO/IEC 14882:2003 2.11
    107    cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
    108                     'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
    109                     'namespace', 'new', 'operator', 'private', 'protected',
    110                     'public', 'reinterpret_cast', 'static_cast', 'template',
    111                     'this', 'throw', 'true', 'try', 'typeid', 'typename',
    112                     'using', 'virtual', 'wchar_t',
    113                     # alternative representations
    114                     'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
    115                     'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
    116    # namespace pollution:
    117    polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386'])
    118    name = re.sub(r'[^A-Za-z0-9_]', '_', name)
    119    if protect and (name in (c89_words | c99_words | c11_words | gcc_words
    120                             | cpp_words | polluted_words)
    121                    or name[0].isdigit()):
    122        return 'q_' + name
    123    return name
    124
    125
    126class Indentation:
    127    """
    128    Indentation level management.
    129
    130    :param initial: Initial number of spaces, default 0.
    131    """
    132    def __init__(self, initial: int = 0) -> None:
    133        self._level = initial
    134
    135    def __repr__(self) -> str:
    136        return "{}({:d})".format(type(self).__name__, self._level)
    137
    138    def __str__(self) -> str:
    139        """Return the current indentation as a string of spaces."""
    140        return ' ' * self._level
    141
    142    def increase(self, amount: int = 4) -> None:
    143        """Increase the indentation level by ``amount``, default 4."""
    144        self._level += amount
    145
    146    def decrease(self, amount: int = 4) -> None:
    147        """Decrease the indentation level by ``amount``, default 4."""
    148        assert amount <= self._level
    149        self._level -= amount
    150
    151
    152#: Global, current indent level for code generation.
    153indent = Indentation()
    154
    155
    156def cgen(code: str, **kwds: object) -> str:
    157    """
    158    Generate ``code`` with ``kwds`` interpolated.
    159
    160    Obey `indent`, and strip `EATSPACE`.
    161    """
    162    raw = code % kwds
    163    pfx = str(indent)
    164    if pfx:
    165        raw = re.sub(r'^(?!(#|$))', pfx, raw, flags=re.MULTILINE)
    166    return re.sub(re.escape(EATSPACE) + r' *', '', raw)
    167
    168
    169def mcgen(code: str, **kwds: object) -> str:
    170    if code[0] == '\n':
    171        code = code[1:]
    172    return cgen(code, **kwds)
    173
    174
    175def c_fname(filename: str) -> str:
    176    return re.sub(r'[^A-Za-z0-9_]', '_', filename)
    177
    178
    179def guardstart(name: str) -> str:
    180    return mcgen('''
    181#ifndef %(name)s
    182#define %(name)s
    183
    184''',
    185                 name=c_fname(name).upper())
    186
    187
    188def guardend(name: str) -> str:
    189    return mcgen('''
    190
    191#endif /* %(name)s */
    192''',
    193                 name=c_fname(name).upper())
    194
    195
    196def gen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]],
    197               cond_fmt: str, not_fmt: str,
    198               all_operator: str, any_operator: str) -> str:
    199
    200    def do_gen(ifcond: Union[str, Dict[str, Any]],
    201               need_parens: bool) -> str:
    202        if isinstance(ifcond, str):
    203            return cond_fmt % ifcond
    204        assert isinstance(ifcond, dict) and len(ifcond) == 1
    205        if 'not' in ifcond:
    206            return not_fmt % do_gen(ifcond['not'], True)
    207        if 'all' in ifcond:
    208            gen = gen_infix(all_operator, ifcond['all'])
    209        else:
    210            gen = gen_infix(any_operator, ifcond['any'])
    211        if need_parens:
    212            gen = '(' + gen + ')'
    213        return gen
    214
    215    def gen_infix(operator: str, operands: Sequence[Any]) -> str:
    216        return operator.join([do_gen(o, True) for o in operands])
    217
    218    if not ifcond:
    219        return ''
    220    return do_gen(ifcond, False)
    221
    222
    223def cgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str:
    224    return gen_ifcond(ifcond, 'defined(%s)', '!%s', ' && ', ' || ')
    225
    226
    227def docgen_ifcond(ifcond: Optional[Union[str, Dict[str, Any]]]) -> str:
    228    # TODO Doc generated for conditions needs polish
    229    return gen_ifcond(ifcond, '%s', 'not %s', ' and ', ' or ')
    230
    231
    232def gen_if(cond: str) -> str:
    233    if not cond:
    234        return ''
    235    return mcgen('''
    236#if %(cond)s
    237''', cond=cond)
    238
    239
    240def gen_endif(cond: str) -> str:
    241    if not cond:
    242        return ''
    243    return mcgen('''
    244#endif /* %(cond)s */
    245''', cond=cond)
    246
    247
    248def must_match(pattern: str, string: str) -> Match[str]:
    249    match = re.match(pattern, string)
    250    assert match is not None
    251    return match