Example #1
0
    def __generate_call(self, ep, func, obj, identifier):
        # Add declaration of caller
        caller_func = Function("emg_{}_caller_{}".format(func, identifier),
                               "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("emg_arg_{}".format(index), arg)
                body.append(argvar.declare() + ";")
                args.append(argvar.name)
                if isinstance(arg, Pointer):
                    elements = self.conf.get(
                        "initialize strings as null terminated")
                    if elements and arg == '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 self.conf.get("allocate external", True):
                        value = "external_allocated_data();"
                        initializations.append("{} = {}".format(
                            argvar.name, value))
                    else:
                        if self.conf.get("allocate with sizeof", True):
                            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
        if func != "main":
            expression += "int ret = "
        expression += "{}({});".format(func, ", ".join(args))

        # Generate function body
        body += initializations + [expression]
        if func != "main":
            body += ["ldv_assume(ret==0);"]

        # 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 #2
0
    def _dispatch_blocks(self, action, automaton, function_parameters,
                         automata_peers, replicative):
        pre = []
        post = []
        blocks = []

        for a_peer in (a for a in automata_peers
                       if automata_peers[a]['actions']):
            decl = self._get_cf_struct(automaton, function_parameters)
            cf_param = 'cf_arg_{}'.format(str(a_peer))
            vf_param_var = Variable(cf_param, decl.take_pointer)
            pre.append(vf_param_var.declare() + ';')

            if replicative:
                for r_action in automata_peers[a_peer]['actions']:
                    block = list()
                    block.append('{} = {}(sizeof({}));'.format(
                        vf_param_var.name,
                        self._cmodel.mem_function_map["ALLOC"], str(decl)))
                    for index in range(len(function_parameters)):
                        block.append('{}->arg{} = arg{};'.format(
                            vf_param_var.name, index, index))
                    if r_action.replicative:
                        call = self._call_cf(a_peer, cf_param)
                        if self._conf.get('direct control functions calls'):
                            block.append(call)
                        else:
                            if a_peer.self_parallelism and self._conf.get("self parallel processes") and \
                                    self._conf.get('pure pthread interface'):
                                thread_vars = self.__thread_variable(
                                    a_peer, var_type='pair')
                                for v in thread_vars:
                                    # Expect that for this particular case the first argument is unset
                                    block.extend([
                                        'ret = {}'.format(
                                            call.format("& " + v.name)),
                                        'ldv_assume(ret == 0);'
                                    ])
                            else:
                                block.extend([
                                    'ret = {}'.format(call),
                                    'ldv_assume(ret == 0);'
                                ])
                        blocks.append(block)
                        break
                    else:
                        self._logger.warning(
                            'Cannot generate dispatch based on labels for receive {} in process {} with category {}'
                            .format(r_action.name, a_peer.process.name,
                                    a_peer.process.category))
            # todo: Pretty ugly, but works
            elif action.name.find('dereg') != -1:
                block = list()
                call = self._join_cf(automata_peers[a_peer]['automaton'])
                if not self._conf.get('direct control functions calls'):
                    if automata_peers[a_peer]['automaton'].self_parallelism and self._conf.get("self parallel processes")\
                            and self._conf.get('pure pthread interface'):
                        thread_vars = self.__thread_variable(
                            automata_peers[a_peer]['automaton'],
                            var_type='pair')
                        for v in thread_vars:
                            # Expect that for this particular case the first argument is unset
                            block.extend([
                                'ret = {}'.format(call.format(v.name)),
                                'ldv_assume(ret == 0);'
                            ])
                    else:
                        block.extend(
                            ['ret = {}'.format(call), 'ldv_assume(ret == 0);'])
                    blocks.append(block)

        return pre, blocks, post
Example #3
0
def _import_code_analysis(logger, conf, clade, dependencies, collection):
    # Import typedefs if there are provided
    logger.info("Extract complete types definitions")
    typedef = clade.get_typedefs(
        set(dependencies.keys()).union(collection.cfiles))
    if typedef:
        import_typedefs(typedef, dependencies)

    variables = clade.get_variables(set(collection.cfiles))
    if variables:
        logger.info("Import global variables initializations")
        for path, vals in variables.items():
            for variable in vals:
                variable_name = extract_name(variable['declaration'])
                if not variable_name:
                    raise ValueError('Global variable without a name')
                var = Variable(variable_name, variable['declaration'])

                # Here we know, that if we met a variable in an another file then it is an another variable because
                # a program should contain a single global variable initialization
                collection.set_source_variable(var, path)
                var.declaration_files.add(path)
                var.initialization_file = path

                if 'value' in variable:
                    var.value = variable['value']

    # Variables which are used in variables initializations
    logger.info("Import source functions")
    vfunctions = clade.get_used_in_vars_functions()

    # Get functions defined in dependencies and in the main functions and have calls
    cg = clade.get_callgraph(set(dependencies.keys()))

    # Function scope definitions
    # todo: maybe this should be fixed in Clade
    # As we will not get definitions for library functions if there are in compiled parts we should add all scopes
    # that are given for all function called from outside of the code we analyze
    for scope in (s for s in collection.cfiles if s in cg):
        for func in (f for f in cg[scope] if cg[scope][f].get('calls')):
            for dep in cg[scope][func].get('calls'):
                dependencies.setdefault(dep, sortedcontainers.SortedSet())
                dependencies[dep].add(scope)
    fs = clade.get_functions_by_file(
        set(dependencies.keys()).union(collection.cfiles))

    # Add called functions
    for scope in cg:
        for func in cg[scope]:
            desc = cg[scope][func]
            if scope in collection.cfiles:
                # Definition of the function is in the code of interest
                try:
                    collection.add_function(func, scope, fs, dependencies,
                                            collection.cfiles)
                except ValueError:
                    pass
                # Add called functions
                for def_scope, cf_desc in desc.get('calls', dict()).items():
                    if def_scope not in collection.cfiles:
                        for called_func in (
                                f for f in cf_desc
                                if def_scope in fs and f in fs[def_scope]):
                            collection.add_function(called_func, def_scope, fs,
                                                    dependencies,
                                                    collection.cfiles)

            elif ('called_in' in desc
                  and set(desc['called_in'].keys()).intersection(
                      collection.cfiles)) or func in vfunctions:
                if scope in fs and func in fs[scope]:
                    # Function is called in the target code but defined in dependencies
                    collection.add_function(func, scope, fs, dependencies,
                                            collection.cfiles)
                elif scope != 'unknown':
                    logger.warning(
                        "There is no information on declarations of function {!r} from {!r} scope"
                        .format(func, scope))
    # Add functions missed in the call graph
    for scope in (s for s in fs if s in collection.cfiles):
        for func in fs[scope]:
            func_intf = collection.get_source_function(func, scope)
            if not func_intf:
                try:
                    collection.add_function(func, scope, fs, dependencies,
                                            collection.cfiles)
                except ValueError:
                    pass

    for func in collection.source_functions:
        for obj in collection.get_source_functions(func):
            scopes = set(obj.declaration_files).union(set(obj.header_files))
            if not obj.definition_file:
                # It is likely be this way
                scopes.add('unknown')
            for scope in (s for s in scopes if cg.get(s, dict()).get(func)):
                for cscope, desc in ((s, d) for s, d in cg[scope][func].get(
                        'called_in', {}).items() if s in collection.cfiles):
                    for caller in desc:
                        for line in desc[caller]:
                            params = desc[caller][line].get('args')
                            caller_intf = collection.get_source_function(
                                caller, cscope)
                            obj.add_call(caller, cscope)

                            if params:
                                # Here can be functions which are not defined or visible
                                for _, passed_func in list(params):
                                    passed_obj = collection.get_source_function(
                                        passed_func, cscope)
                                    if not passed_obj:
                                        passed_scope = collection.search_function(
                                            passed_func, cscope, fs)
                                        if passed_scope:
                                            collection.add_function(
                                                passed_func, passed_scope, fs,
                                                dependencies,
                                                collection.cfiles)
                                        else:
                                            logger.warning(
                                                "Cannot find function {!r} from scope {!r}"
                                                .format(passed_func, cscope))
                                            # Ignore this call since model will not be correct without signature
                                            params = None
                                            break
                                caller_intf.call_in_function(obj, params)
            if obj.definition_file and obj.definition_file in scopes and obj.definition_file in cg and \
                    func in cg[obj.definition_file]:
                for called_def_scope in cg[obj.definition_file][func].get(
                        'calls', dict()):
                    for called_func in cg[obj.definition_file][func]['calls'][
                            called_def_scope]:
                        called_obj = collection.get_source_function(
                            called_func, paths={obj.definition_file})
                        if called_obj:
                            called_obj.add_call(func, obj.definition_file)

    logger.debug("The following functions were imported: {}".format(', '.join(
        collection.source_functions)))

    macros_file = conf.get('macros white list',
                           'linux/emg/macros white list.json')
    if macros_file:
        macros_file = find_file_or_dir(logger, conf['main working directory'],
                                       macros_file)
        with open(macros_file, 'r', encoding='utf-8') as fp:
            white_list = sorted(ujson.load(fp))
        if white_list:
            macros = clade.get_macros_expansions(sorted(collection.cfiles),
                                                 white_list)
            for path, macros in macros.items():
                for macro, desc in macros.items():
                    obj = collection.get_macro(macro)
                    if not obj:
                        obj = Macro(macro)
                    for call in desc.get('args', []):
                        obj.add_parameters(path, call)
                    collection.set_macro(obj)
Example #4
0
    def _receive(self, action, automaton):
        code, v_code, conditions, comments = super(LabelTranslator,
                                                   self)._receive(
                                                       action, automaton)

        automata_peers = {}
        if len(action.peers) > 0:
            # Do call only if model which can be called will not hang
            extract_relevant_automata(
                self._logger,
                self._event_fsa + self._model_fsa + [self._entry_fsa],
                automata_peers, action.peers, Dispatch)

            # Add additional condition
            if action.replicative:
                param_declarations = []
                param_expressions = []

                if len(action.parameters) > 0:
                    for index, param in enumerate(action.parameters):
                        receiver_access = automaton.process.resolve_access(
                            param)
                        var = automaton.determine_variable(
                            receiver_access.label)
                        param_declarations.append(var.declaration)
                        param_expressions.append(var.name)

                if action.condition and len(action.condition) > 0:
                    # Arguments comparison is not supported in label-based model
                    for statement in action.condition:
                        # Replace first $ARG expressions
                        s = statement
                        for index, _ in enumerate(param_expressions):
                            replacement = 'data->arg{}'.format(index)
                            s = s.replace("$ARG{}".format(index + 1),
                                          replacement)
                        cn = self._cmodel.text_processor(automaton, s)
                        conditions.extend(cn)

                # This should be before precondition because it may check values unpacked in this section
                if len(param_declarations) > 0:
                    decl = self._get_cf_struct(
                        automaton, [val for val in param_declarations])
                    var = Variable('data', decl.take_pointer)
                    v_code += [
                        '/* Received labels */', '{} = ({}*) arg0;'.format(
                            var.declare(), decl.to_string('',
                                                          typedef='complex')),
                        ''
                    ]

                    code += ['/* Assign recieved labels */',
                             'if (data) {'] + \
                            ['\t{} = data->arg{};'.format(v, i) for i, v in enumerate(param_expressions)] + \
                            ['\t{}({});'.format(self._cmodel.free_function_map["FREE"], 'data'), '}']
                else:
                    code.append('{}({});'.format(
                        self._cmodel.free_function_map["FREE"], 'arg0'))
            else:
                code.append(
                    '/* Skip a non-replicative signal receiving %s */' %
                    action.name)
                # Ignore conditions
                conditions = []
        else:
            # Generate comment
            code.append(
                "/* Signal receive {!r} does not expect any signal from existing processes */"
                .format(action.name))

        return code, v_code, conditions, comments