Example #1
0
    def __state_switch(self, states):
        key = ''.join(sorted([str(i) for i in states]))
        if key in self.__switchers_cache:
            return self.__switchers_cache[key]['call']

        # Generate switch function
        name = 'ldv_switch_{}'.format(len(list(self.__switchers_cache.keys())))
        func = Function(name, 'int f(void)')
        func.definition_file = self._cmodel.entry_file

        # Generate switch body
        code = list()
        code.append('switch (ldv_undef_int()) {')
        for index in range(len(states)):
            code.append('\tcase {}: '.format(index) + '{')
            code.append('\t\treturn {};'.format(states[index]))
            code.append('\t\tbreak;')
            code.append('\t}')
        code.append('\tdefault: ldv_assume(0);')
        code.append('}')
        func.body.extend(code)

        # Add function
        self._cmodel.add_function_definition(func)

        invoke = '{}()'.format(name)
        self.__switchers_cache[key] = {'call': invoke, 'function': func}
        return invoke
Example #2
0
def __generate_alias(process, name, file, int_retval=False):
    new_name = "ldv_emg_{}".format(name)
    code = ["{}();".format("return {}".format(name) if int_retval else name)]
    # Add definition
    func = Function(
        new_name, "{}(void)".format("int {}".format(new_name) if int_retval
                                    else "void {}".format(new_name)))
    func.body = code
    process.add_definition(file, name, func.define())
    process.add_declaration(
        'environment model', name,
        'extern {} {}(void);\n'.format("int" if int_retval else "void",
                                       new_name))

    return new_name
Example #3
0
    def _control_function(self, automaton):
        """
        Generate control function. This function generates a FunctionDefinition object without a body. It is required
        to call control function within code blocks until all code blocks are translated and control function body
        can be generated.

        :param automaton: Automaton object.
        :return: FunctionDefinition object.
        """
        if automaton.identifier not in self._control_functions:
            # Check that this is an aspect function or not
            if automaton in self._model_fsa:
                name = 'ldv_emg_{}'.format(automaton.process.name)
                function_objs = self._source.get_source_functions(automaton.process.name)
                if len(function_objs) == 0:
                    raise ValueError("Unfortunately there is no function {!r} found by the source analysis".
                                     format(automaton.process.name))
                else:
                    # We ignore there that fact that functions can have different scopes
                    function_obj = function_objs[0]
                params = []
                for position, param in enumerate(function_obj.declaration.parameters):
                    if isinstance(param, str):
                        params.append(param)
                    else:
                        params.append(param.to_string('arg{}'.format(str(position)), typedef='complex_and_params'))

                if len(params) == 0:
                    param_types = ['void']
                else:
                    param_types = params

                declaration = '{0} f({1})'.format(
                    function_obj.declaration.return_value.to_string('', typedef='complex_and_params'),
                    ', '.join(param_types))
                cf = Function(name, declaration)
            else:
                name = 'ldv_{}_{}'.format(automaton.process.name, automaton.identifier)
                if not get_necessary_conf_property(self._conf, "direct control functions calls"):
                    declaration = 'void *f(void *data)'
                else:
                    declaration = 'void f(void *data)'
                cf = Function(name, declaration)
            cf.definition_file = self._cmodel.entry_file

            self._control_functions[automaton.identifier] = cf

        return self._control_functions[automaton.identifier]
Example #4
0
    def _add_function(self, func, scope, fs, deps, cfiles):
        fs_desc = fs[scope][func]
        if scope == 'unknown':
            key = list(fs_desc['declarations'].keys())[0]
            signature = fs_desc['declarations'][key]['signature']
            func_intf = Function(func, signature)
            # Do not set definition file since it is out of scope of the target program fragment
        else:
            signature = fs_desc.get('signature')
            func_intf = Function(func, signature)
            func_intf.definition_file = scope

        # Set static
        if fs_desc.get('type') == "static":
            func_intf.static = True
        else:
            func_intf.static = False

        # Add declarations
        files = {func_intf.definition_file
                 } if func_intf.definition_file else set()
        if fs_desc['declarations']:
            files.update({
                f
                for f in fs_desc['declarations']
                if f != 'unknown' and f in deps
            })
        for file in files:
            if file not in cfiles and file not in func_intf.header_files:
                func_intf.header_files.append(file)
            for cfile in deps[file]:
                self.set_source_function(func_intf, cfile)
                func_intf.declaration_files.add(cfile)
Example #5
0
def __generate_insmod_process(logger, conf, source, inits, exits,
                              kernel_initializations):
    logger.info(
        "Generate artificial process description to call Init and Exit module functions 'insmod'"
    )
    ep = Process("insmod")
    ep.category = 'linux'
    ep.comment = "Initialize or exit module."
    ep.self_parallelism = False
    ep.identifier = 0
    ep.process = ''
    ep.pretty_id = 'linux/initialization'

    if len(kernel_initializations) > 0:
        body = ["int ret;"]
        label_name = 'ldv_kernel_initialization_exit'

        # Generate kernel initializations
        for name, calls in kernel_initializations:
            for filename, func_name in calls:
                func = source.get_source_function(func_name, filename)
                if func:
                    retval = False if func.declaration.return_value.identifier == 'void' else True
                else:
                    raise RuntimeError(
                        "Cannot resolve function {!r} in file {!r}".format(
                            name, filename))
                new_name = __generate_alias(ep, func_name, filename, retval)
                statements = [
                    model_comment('callback', func_name,
                                  {'call': "{}();".format(func_name)}),
                ]
                if retval:
                    statements.extend([
                        "ret = {}();".format(new_name),
                        "ret = ldv_post_init(ret);", "if (ret)",
                        "\tgoto {};".format(label_name)
                    ])
                else:
                    statements.append("{}();".format(new_name))

                body.extend(statements)
        body.extend(["{}:".format(label_name), "return ret;"])
        func = Function('ldv_kernel_init', 'int ldv_kernel_init(void)')
        func.body = body
        addon = func.define()
        ep.add_definition('environment model', 'ldv_kernel_init', addon)
        ki_subprocess = ep.add_condition('kernel_initialization', [],
                                         ["%ret% = ldv_kernel_init();"],
                                         'Kernel initialization stage.')
        ki_subprocess.trace_relevant = True
        ki_success = ep.add_condition('kerninit_success', ["%ret% == 0"], [],
                                      "Kernel initialization is successful.")
        ki_failed = ep.add_condition('kerninit_failed', ["%ret% != 0"], [],
                                     "Kernel initialization is unsuccessful.")
    if len(inits) > 0:
        # Generate init subprocess
        for filename, init_name in inits:
            new_name = __generate_alias(ep, init_name, filename, True)
            init_subprocess = Condition(init_name)
            init_subprocess.comment = 'Initialize the module after insmod with {!r} function.'.format(
                init_name)
            init_subprocess.statements = [
                model_comment('callback', init_name,
                              {'call': "{}();".format(init_name)}),
                "%ret% = {}();".format(new_name),
                "%ret% = ldv_post_init(%ret%);"
            ]
            init_subprocess.trace_relevant = True
            logger.debug("Found init function {}".format(init_name))
            ep.actions[init_subprocess.name] = init_subprocess

    # Add ret label
    ep.add_label('ret', import_declaration("int label"))

    # Generate exit subprocess
    if len(exits) == 0:
        logger.debug("There is no exit function found")
    else:
        for filename, exit_name in exits:
            new_name = __generate_alias(ep, exit_name, filename, False)
            exit_subprocess = Condition(exit_name)
            exit_subprocess.comment = 'Exit the module before its unloading with {!r} function.'.format(
                exit_name)
            exit_subprocess.statements = [
                model_comment('callback', exit_name,
                              {'call': "{}();".format(exit_name)}),
                "{}();".format(new_name)
            ]
            exit_subprocess.trace_relevant = True
            logger.debug("Found exit function {}".format(exit_name))
            ep.actions[exit_subprocess.name] = exit_subprocess

    # Generate conditions
    success = ep.add_condition('init_success', ["%ret% == 0"], [],
                               "Module has been initialized.")
    ep.actions[success.name] = success
    # Generate else branch
    failed = ep.add_condition('init_failed', ["%ret% != 0"], [],
                              "Failed to initialize the module.")
    ep.actions[failed.name] = failed

    # Add subprocesses finally
    process = ''
    for i, pair in enumerate(inits):
        process += "<{0}>.(<init_failed>".format(pair[1])
        for j, pair2 in enumerate(exits[::-1]):
            if pair2[0] == pair[0]:
                break
        j = 1
        for _, exit_name in exits[:j - 1:-1]:
            process += ".<{}>".format(exit_name)
        process += "|<init_success>."

    for _, exit_name in exits:
        process += "<{}>.".format(exit_name)
    # Remove the last dot
    process = process[:-1]

    process += ")" * len(inits)

    if len(kernel_initializations) > 0 and len(inits) > 0:
        ep.process += "<{}>.(<{}> | <{}>.({}))".format(ki_subprocess.name,
                                                       ki_failed.name,
                                                       ki_success.name,
                                                       process)
    elif len(kernel_initializations) == 0 and len(inits) > 0:
        ep.process += process
    elif len(kernel_initializations) > 0 and len(inits) == 0:
        ep.process += "<{}>.(<{}> | <{}>)".format(ki_subprocess.name,
                                                  ki_failed.name,
                                                  ki_success.name, process)
    else:
        raise NotImplementedError(
            "There is no both kernel initilization functions and module initialization functions"
        )
    return ep
Example #6
0
def __generate_call(emg, conf, ep, func, obj):
    # Add declaration of caller
    caller_func = Function("ldv_emg_{}_caller".format(func), "void a(void)")
    ep.add_declaration("environment model", caller_func.name,
                       caller_func.declare(True)[0])
    expression = ""
    body = []
    initializations = []

    # Check retval and cast to void call
    if obj.declaration.return_value and obj.declaration.return_value.identifier != 'void':
        expression += "(void) "

    # Get arguments and allocate memory for them
    args = []
    free_args = []
    for index, arg in enumerate(obj.declaration.parameters):
        if not isinstance(arg, str):
            argvar = Variable("ldv_arg_{}".format(index), arg)
            body.append(argvar.declare() + ";")
            args.append(argvar.name)
            if isinstance(arg, Pointer):
                elements = get_conf_property(
                    conf, "initialize strings as null terminated")
                if elements and arg.identifier == 'char **':
                    if isinstance(elements, int) or elements.isnumeric():
                        elements = int(elements)
                    else:
                        elements = 'ldv_undef_int()'
                    argvar_len = Variable(argvar.name + '_len', 'int')
                    # Define explicitly number of arguments, since undef value is too difficult sometimes
                    initializations.append("int {} = {};".format(
                        argvar_len.name, elements))
                    initializations.append(
                        "{} = (char **) ldv_xmalloc({} * sizeof(char *));".
                        format(argvar.name, argvar_len.name))
                    # Initialize all elements but the last one
                    initializations.append(
                        "for (int i = 0; i < {} - 1; i++)".format(
                            argvar_len.name))
                    # Some undefined data
                    initializations.append(
                        "\t{}[i] = (char *) external_allocated_data();".format(
                            argvar.name))
                    # The last element is a string
                    initializations.append("{}[{}] = (char * ) 0;".format(
                        argvar.name, elements - 1))
                    free_args.append(argvar.name)
                elif get_necessary_conf_property(
                        emg.conf["translation options"], "allocate external"):
                    value = "external_allocated_data();"
                    initializations.append("{} = {}".format(
                        argvar.name, value))
                else:
                    if get_necessary_conf_property(
                            emg.conf["translation options"],
                            "allocate with sizeof"):
                        apt = arg.points.to_string(
                            '', typedef='complex_and_params')
                        value = "ldv_xmalloc(sizeof({}));".\
                            format(apt if apt != 'void' else apt + '*')
                    else:
                        value = "ldv_xmalloc_unknown_size(0);"
                    free_args.append(argvar.name)
                    initializations.append("{} = {}".format(
                        argvar.name, value))

    # Generate call
    expression += "{}({});".format(func, ", ".join(args))

    # Generate function body
    body += initializations + [expression]

    # Free memory
    for arg in free_args:
        body.append("ldv_free({});".format(arg))

    caller_func.body = body

    # Add definition of caller
    ep.add_definition(obj.definition_file, caller_func.name,
                      caller_func.define() + ["\n"])

    # Return call expression
    return "{}();".format(caller_func.name)
Example #7
0
    def compose_entry_point(self, given_body):
        """
        Generate an entry point function for the environment model.

        :param given_body: Body of the main function provided by a translator.
        :return: List of C statements of the generated function body.
        """
        ep = Function(self.entry_name, "int {}(void)".format(self.entry_name))
        ep.definition_file = self.entry_file
        body = [
            '/* LDV {' +
            '"thread": 1, "type": "CONTROL_FUNCTION_BEGIN", "comment": "Entry point \'{0}\'", '
            '"function": "{0}"'.format(self.entry_name) + '} */'
        ]

        # Init external allocated pointers
        cnt = 0
        functions = []
        if len(self.__external_allocated.keys()) > 0:
            for file in sorted([
                    f for f in self.__external_allocated.keys()
                    if len(self.__external_allocated[f]) > 0
            ]):
                func = Function(
                    'ldv_allocate_external_{}'.format(cnt),
                    "void ldv_allocate_external_{}(void)".format(cnt))
                func.declaration_files.add(file)
                func.definition_file = file

                init = [
                    "{} = {}();".format(var.name, 'external_allocated_data')
                    for var in self.__external_allocated[file]
                ]
                func.body = init

                self.add_function_definition(func)
                self.add_function_declaration(self.entry_file,
                                              func,
                                              extern=True)
                functions.append(func)
                cnt += 1

            gl_init = Function('ldv_initialize_external_data',
                               'void ldv_initialize_external_data(void)')
            gl_init.declaration_files.add(self.entry_file)
            gl_init.definition_file = self.entry_file
            init_body = ['{}();'.format(func.name) for func in functions]
            gl_init.body = init_body
            self.add_function_definition(gl_init)
            body.extend([
                '/* Initialize external data */',
                'ldv_initialize_external_data();'
            ])

        if get_conf_property(self._conf, "initialize requirements"):
            body += [
                '/* LDV {"action": "INIT", "type": "CALL_BEGIN", "callback": true, '
                '"comment": "Initialize requirement models."} */',
                'ldv_initialize();',
                '/* LDV {"action": "INIT", "type": "CALL_END"} */'
            ]

        body += ['/* LDV {"action": "SCENARIOS", "type": "CONDITION_BEGIN", '
                 '"comment": "Begin Environment model scenarios."} */'] + given_body + \
                ['/* LDV {"action": "SCENARIOS", "type": "CONDITION_END"} */']

        if get_conf_property(self._conf, "check final state"):
            body += [
                '/* LDV {"action": "FINAL", "callback": true, "type": "CALL_BEGIN", '
                '"comment": "Check requirement model final state at the exit if required."} */',
                'ldv_check_final_state();',
                '/* LDV {"action": "FINAL", "type": "CALL_END"} */'
            ]

        body.append('return 0;')
        body.append(
            '/* LDV {' +
            '"comment": "Exit entry point \'{0}\'", "type": "CONTROL_FUNCTION_END",'
            ' "function": "{0}"'.format(self.entry_name) + '} */')

        ep.body = body
        self.add_function_definition(ep)

        return body
Example #8
0
    def _dispatch(self, state, automaton):
        """
        Generate a code block for a dispatch action of the process for which the automaton is generated. A dispatch code
        block is always generated in a fixed form: as a function call of auxiliary function. Such a function contains
        switch or if operator to choose one of available optional receivers to send the signal. Implementation of
        particular dispatch to particular receiver is configurable and can be implemented differently in various
        translators.

        :param state: State object.
        :param automaton: Automaton object which contains the dispatch.
        :return: [list of strings with lines of C code statements of the code block],
                 [list of strings with new local variable declarations required for the block],
                 [list of strings with boolean conditional expressions which guard code block entering],
                 [list of strings with model comments which embrace the code block]
        """
        code, v_code, conditions, comments = list(), list(), list(), list()

        # Determine peers to receive the signal
        automata_peers = dict()
        if len(state.action.peers) > 0:
            # Do call only if model which can be called will not hang
            extract_relevant_automata(self._event_fsa + self._model_fsa + [self._entry_fsa],
                                      automata_peers, state.action.peers, Receive)
        else:
            # Generate comment
            code.append("/* Dispatch {!r} is not expected by any process, skipping the action */".
                        format(state.action.name))

        # Make comments
        if len(automata_peers) > 0:
            category = list(automata_peers.values())[0]['automaton'].process.category.upper()
            comment = state.action.comment.format(category)
        else:
            comment = 'Skip the action, since no callbacks has been found.'
        comments.append(action_model_comment(state.action, comment, begin=True))
        comments.append(action_model_comment(state.action, None, begin=False))

        # Add given conditions from a spec
        conditions = []
        if state.action.condition and len(state.action.condition) > 0:
            for statement in state.action.condition:
                cn = self._cmodel.text_processor(automaton, statement)
                conditions.extend(cn)

        if len(automata_peers) > 0:
            # Add conditions on base of dispatches
            checks = self._relevant_checks(automata_peers)
            if len(checks) > 0:
                if automaton in self._model_fsa:
                    conditions.append("({})".format(' || '.join(checks)))
                else:
                    # Convert conditions into assume, because according to signals semantics process could not proceed
                    # until it sends a signal and condition describes precondition to prevent signal sending to a
                    # wrong process.
                    if len(checks) > 0:
                        code.append('ldv_assume({});'.format(' || '.join(checks)))

            # Generate artificial function
            body = []

            if not get_conf_property(self._conf, 'direct control functions calls'):
                body = ['int ret;']

            # Check dispatch type
            replicative = False
            for name in automata_peers:
                for st in automata_peers[name]['states']:
                    if st.action.replicative:
                        replicative = True
                        break

            # Determine parameters
            df_parameters = []
            function_parameters = []

            # Add parameters
            for index in range(len(state.action.parameters)):
                # Determine dispatcher parameter
                # We expect strictly one
                dispatcher_access = automaton.process.resolve_access(state.action.parameters[index])[0]
                variable = automaton.determine_variable(dispatcher_access.label)
                function_parameters.append(variable.declaration)
                df_parameters.append(variable.name)

            # Generate blocks on each receive to another process
            # You can implement your own modelTranslator with different implementations of the function
            pre, blocks, post = self._dispatch_blocks(state, automaton, function_parameters, automata_peers,
                                                      replicative)
            if len(blocks) > 0:
                body.extend(pre)

                # Print body of a dispatching function
                if state.action.broadcast:
                    for block in blocks:
                        body.extend(block)
                else:
                    body.append('switch (ldv_undef_int()) {')
                    for index in range(len(blocks)):
                        body.append('\tcase {}: '.format(index) + '{')
                        body.extend(['\t\t' + stm for stm in blocks[index]])
                        body.append('\t\tbreak;')
                        body.append('\t};')
                    if get_conf_property(self._conf, 'do not skip signals'):
                        body.append('\tdefault: ldv_assume(0);')
                    body.append('};')

                if len(function_parameters) > 0:
                    df = Function(
                        "ldv_dispatch_{}_{}_{}".format(state.action.name, automaton.identifier, state.identifier),
                        "void f({})".format(', '.
                                            join([function_parameters[index].to_string('arg{}'.format(index),
                                                                                       typedef='complex_and_params')
                                                  for index in range(len(function_parameters))])))
                else:
                    df = Function(
                        "ldv_dispatch_{}_{}_{}".format(state.action.name, automaton.identifier, state.identifier),
                        "void f(void)")
                df.definition_file = self._cmodel.entry_file
                body.extend(post)
                body.append('return;')
                df.body.extend(body)

                # Add function definition
                self._cmodel.add_function_definition(df)

                code.extend([
                    '{}({});'.format(df.name, ', '.join(df_parameters))
                ])
            else:
                # This is becouse translators can have specific restrictions
                code.append('/* Skip the dispatch because there is no process to receive the signal */')
        else:
            code.append('/* Skip the dispatch because there is no process to receive the signal */')

        return code, v_code, conditions, comments