Beispiel #1
0
    def do(self, g: graph.PyGraph, nodes=None, entry=None):
        if nodes is not None:
            self.nodes = nodes
        else:
            print("no abbs were commited to the dominance tree analysis")

        start_nodes, dom = self.find_dominators()

        #check if the entry argument is a real start abb
        check = None
        for start_node in start_nodes:
            if start_node.get_seed() == entry.get_seed():
                check = start_node

        assert check != None

        self.immdom_tree = dict()

        for x in start_nodes:
            if x.get_seed() == check.get_seed():
                self.immdom_tree[x.get_seed()] = None
            else:
                self.immdom_tree[x.get_seed()] = check

        self.immdom_tree_keys = []
        for start_node in start_nodes:
            #print("start_node:",start_node.get_name())
            self.immdom_tree[start_node.get_seed()] = None

        for abb_seed in dom:

            continue_flag = False

            abb = g.get_vertex(abb_seed)
            for tmp_abb in start_nodes:
                if abb.get_seed() == tmp_abb.get_seed():
                    continue_flag = True
            #print("abb  node:",abb.get_name())
            if continue_flag == True:
                #print("continued start node")
                continue

            visited = set()

            dominators = []

            for element in dom[abb.get_seed()]:
                if element.get_seed() != abb.get_seed():
                    #print("dominator node:",element.get_name())
                    dominators.append(element)

            #print(dom[abb.get_seed()])
            imdom = self.find_imdom(abb, dominators, visited, abb)
            #print("indom name:" , imdom.get_name())
            assert abb.get_seed() != imdom.get_seed() and imdom != None

            self.immdom_tree[abb.get_seed()] = imdom
            self.immdom_tree_keys.append(abb.get_name())
Beispiel #2
0
 def merge_loops(self,g: graph.PyGraph):
     anyChanges = True
     while anyChanges:
         anyChanges = False
         for abb in g.get_type_vertices("ABB"):
             mc = self.find_loops_to_merge(abb)
             if mc and self.can_be_merged(mc.entry_abb, mc.exit_abb, mc.inner_abbs):
                 self.do_merge(g,mc.entry_abb, mc.exit_abb, mc.inner_abbs)
                 anyChanges = True
Beispiel #3
0
Datei: oil.py Projekt: luhsra/ara
    def run(self, g: graph.PyGraph):
        # load the json outputstructure with json
        self._log.info(f"Reading oil file {self._config['oilfile']}")
        with open(self._config['oilfile']) as f:
            oil = json.load(f)
        assert("cpu" in oil)
        oil = oil["cpu"]

        # TODO validate json

        # prepare graph functions:
        funcs = g.get_type_vertices("Function")
        self.functions = dict([(x.get_name(), x) for x in funcs])
        for f in self.functions:
            print(f, self.functions[f])

        counter_m = {'maxallowedvalue': graph.Counter.set_max_allowed_value,
                     'ticksperbase': graph.Counter.set_ticks_per_base,
                     'mincycle': graph.Counter.set_min_cycle}

        task_m = {'priority': graph.Task.set_priority,
                  'autostart': graph.Task.set_autostart,
                  'schedule': graph.Task.set_scheduler,
                  'activation': graph.Task.set_activation}
        event_m = {'mask': OilStep.event_set_mask}
        resources_m = {'type': OilStep.resource_type}
        alarm_m = {'action': OilStep.alarm_action}
        isr_m = {'category': graph.ISR.set_category,
                 'priority': graph.ISR.set_priority}

        fill_graph = partial(self.fill_graph, g, oil)

        # fill the graph, according to the OIL specification some dependencies
        # must be met:
        # FOO -> BAR: FOO depends on BAR
        # alarm -> counter
        # alarm -> task
        # ISR -> resource
        fill_graph('events', graph.Event, attrs=event_m,
                   inits=[self.event_init])
        fill_graph('counters', graph.Counter, attrs=counter_m)
        fill_graph('tasks', graph.Task, attrs=task_m,
                   inits=[self.task_init])
        fill_graph('alarms', graph.Timer, attrs=alarm_m,
                   inits=[self.alarm_init])
        fill_graph('resources', graph.Mutex, attrs=resources_m,
                   inits=[OilStep.resource_init])
        fill_graph('isrs', graph.ISR, attrs=isr_m,
                   inits=[self.isr_init])
Beispiel #4
0
def validate_osek_task_termination(g: graph.PyGraph):
    task_list = g.get_type_vertices("Task")

    #iterate about the tasks
    for task in task_list:
        #get last outgoing syscall
        edges = task.get_outgoing_edges()
        if not edges:
            continue
        last_syscall = edges[-1]
        #get abb reference from syscall
        abb_reference = last_syscall.get_abb_reference()
        if abb_reference is not None:
            #check if last outgoing syscall is a termination or chain task syscall
            syscall_type = abb_reference.get_syscall_type()
            if syscall_type is not graph.syscall_definition_type.destroy and syscall_type is not graph.syscall_definition_type.chain:
                print(
                    "Warning: No termination or chain as last syscall in task",
                    task.get_name())
Beispiel #5
0
 def merge_branches(self,g: graph.PyGraph):
     """
     Try to merge if - else branches with the following pattern:
             O      O
             / \     |\
             O  O     |O
             \/      |/
             O       O
     """
     anyChanges = True
     while anyChanges:
         anyChanges = False
         for abb in g.get_type_vertices("ABB"):
             mc = self.find_branches_to_merge(abb)
             #if mc and mc.entry_abb and mc.exit_abb:
             #	print("branch entry", mc.entry_abb.get_name(), "branch exit",mc.exit_abb.get_name())
             if mc and self.can_be_merged(mc.entry_abb, mc.exit_abb, mc.inner_abbs):
             #	print("can be merged")
                 self.do_merge(g,mc.entry_abb, mc.exit_abb, mc.inner_abbs)
                 anyChanges = True
Beispiel #6
0
    def merge_linear_abbs(self,g: graph.PyGraph):
        anyChanges = True
        while anyChanges:
            anyChanges = False
            # copy original dict

            abb_list = g.get_type_vertices("ABB")

            for abb in abb_list:

                # Iterate over list of abbs dict KeysView
                #if abb.has_single_successor(E.function_level):
                #    successor = abb.definite_after(E.function_level)
                #print("abb",abb.get_name())

                for successor in abb.get_successors():
                    #print(successor.get_name())
                    #print("successor",successor.get_name())
                    #print("check merge",print(type(abb)),print(type(successor)))
                    if successor and self.can_be_merged(abb, successor):
                        self.do_merge(g,abb, successor)
                        anyChanges = True
Beispiel #7
0
    def run(self, g: graph.PyGraph):


        print("Run abb merge")

        function_list = g.get_type_vertices("Function")
        initial_abb_list = g.get_type_vertices("ABB")


        #iterate about the functions
        for function in function_list:


            if function.get_has_syscall() == False:
                #iterate about the abbs of the function
                already_visited = []
                function_list = []


                #DFS for function
                function_list.append(function)

                #do DFS until the function self and all called functions are analyzed
                while len(function_list) > 0:

                    tmp_function = function_list[-1]
                    del function_list[-1]
                    success = False

                    #check if the tmp function was not visited yet
                    if not tmp_function.get_seed() in already_visited:
                        already_visited.append(tmp_function.get_seed())

                        abb_list = tmp_function.get_atomic_basic_blocks()

                        #iterate about the abbs
                        for abb in abb_list:

                            #check if abb has function call
                            if abb.get_call_type() == graph.call_definition_type.func_call:
                                #append function in functions to analyze list
                                called_functions = abb.get_called_functions()
                                for called_function in called_functions:
                                    function_list.append(called_function)

                            elif abb.get_call_type() == graph.call_definition_type.sys_call:
                                #syscall was detected-> set has syscall and break search for this function
                                function.set_has_syscall(True)
                                success = True
                                break

                    if success == True:
                        #syscall was detected, so continue with next function
                        break


        printer = DotFileParser(g)

        printer.print_bb_functions(g,"bbs_before_merge")

        printer.print_functions(g,"before_merge")

        current_size = None

        initial_abb_count = len(initial_abb_list)
        print(initial_abb_count)
        #merge dominance regions
        self.merge_dominance(g)

        initial_abb_list = g.get_type_vertices("ABB")

        initial_abb_count = len(initial_abb_list)

        print(initial_abb_count)
        printer.print_functions(g,"after_dominance_merge")

        while current_size != initial_abb_count:

            tmp_abb_list = g.get_type_vertices("ABB")
            initial_abb_count = len(tmp_abb_list)

            # linear merging:
            self.merge_linear_abbs(g)

            # try to merge if-else branches
            self.merge_branches(g)

            # merge loop regions
            self.merge_loops(g)

            tmp_abb_list = g.get_type_vertices("ABB")
            current_size = len(tmp_abb_list)

        print(len(g.get_type_vertices("ABB")))
        printer.print_functions(g,"after_merge")
Beispiel #8
0
    def merge_dominance(self,g: graph.PyGraph):

        #for func in g.get_type_vertices("Function"):
            ## Filter some functions

            #function_abbs = func.get_atomic_basic_blocks()

            ##TODO
            ##if func.get_has_syscall() == False:
            ##	continue


            #if len(function_abbs) <= 3 or func.get_exit_abb() == None:
                #continue

            ## Forward analysis

            ##print("dom" , func.get_entry_abb())
            #dom = DominanceAnalysis(forward = True)
            #dom.do(g,nodes=function_abbs,entry =func.get_entry_abb())

            ## Backward analysis
            ##print("post_dom" , func.get_exit_abb())
            #post_dom = DominanceAnalysis(forward = False)
            #post_dom.do(g,nodes=function_abbs,entry =func.get_exit_abb())
            #removed = set()
            ##print("HELLO")
            ##print(dom.immdom_tree)
            ##print(post_dom.immdom_tree)

            #for abb in function_abbs:
                #if abb.get_seed() in removed:
                    #continue

                ##if func.get_entry_abb().get_seed == abb.get_seed():
                ##	continue

                ##print( dom.immdom_tree)

                ##start = dom.immdom_tree[abb.get_seed()]
                ##end   = post_dom.immdom_tree[abb.get_seed()]


                #start = abb.get_dominator();
                #end = abb.get_postdominator();

                ##print("abb", abb.get_name())

                ##if not start:
                    ##print("no dominator")
                ##else:
                    ##print("dominator", start.get_name())


                ##if not end:
                    ##print("no postdominator")
                ##else:
                    ##print("postdominator", end.get_name())

                #if start and end and start != end:

                    #region = self.find_region(start, end)


                    #inner = set()

                    #for element in region:
                        #if element.get_seed() != start.get_seed() and element.get_seed() != end.get_seed():
                            #inner.add(element)


                    ## Was there already some subset removed?
                    #if start.get_seed() in removed or end.get_seed() in removed:
                        #continue

                    #tmp_inner = inner
                    #inner = set()

                    #for inner_element in tmp_inner:
                        ##print("tmp inner" , inner_element.get_name())
                        #if not inner_element.get_seed() in removed:
                            #inner.add(inner_element)



                    ##print("start",start.get_name(),"end", end.get_name())

                    ##for element in inner:
                        ##print("inner",element.get_name())

                    #if self.can_be_merged(start, end, inner):

                        #self.do_merge(g,start, end, inner)
                        ## Mark as removed
                        #removed.add(end.get_seed())
                        ##print(end.get_name())
                        ##print(start.get_name())
                        #for element in inner:
                            ##print(element.get_name())
                            #removed.add(element.get_seed())

        ##self.merge_stats.after_dominance_merge = len(self.system_graph.abbs)


                  #for abb in function_abbs:

                    #start = abb.get_dominator();
                    #end = abb.get_postdominator();

                    #inner = set()

                    #if start and end and start != end:
                        #region = self.find_region(start, end)

                        #for element in region:
                            #if element.get_seed() != start.get_seed() and element.get_seed() != end.get_seed():
                                #inner.add(element)

                    #elif start and not end:
                        #end = abb

                    #elif end and not start:
                        #start = abb

                    #if start and end and start != end:
                        #if self.can_be_merged(start, end, inner):

                            #self.do_merge(g,start, end, inner)
                            #changes = True

        for func in g.get_type_vertices("Function"):
            # Filter some functions

            function_abbs = func.get_atomic_basic_blocks()

            #TODO
            #if func.get_has_syscall() == False:
            #	continue


            if func.get_exit_abb() == None:
                continue

            # Forward analysis

            for abb in function_abbs:

                start = abb.get_dominator();
                end = abb.get_postdominator();

                inner = set()

                if start and end and start != end:
                    region = self.find_region(start, end)

                    for element in region:
                        if element.get_seed() != start.get_seed() and element.get_seed() != end.get_seed():
                            inner.add(element)

                elif start and not end:
                    end = abb

                elif end and not start:
                    start = abb

                if start and end and start != end:
                    if self.can_be_merged(start, end, inner):

                        self.do_merge(g,start, end, inner)
                        changes = True
Beispiel #9
0
    def do_merge( self,g: graph.PyGraph,entry_abb, exit_abb, inner_abbs = set()):
        #print("merge entry abb" , entry_abb.get_name())
        #print("merge exit abb" , exit_abb.get_name())
        #entry_abb.print_information()
        #exit_abb.print_information()
        #if entry_abb.get_name() == "BB351":
            #print('Trying to merge:')
            #print("entry" ,entry_abb.get_name())

            #for inner_abb in inner_abbs:
                #print("inner",inner_abb.get_name())

            #print("exit",exit_abb.get_name())


        assert not entry_abb.get_seed() == exit_abb.get_seed(), 'Entry ABB cannot merge itself into itself'
        #assert not entry_abb in inner_abbs

        #assert not entry_abb.relevant_callees and not exit_abb.relevant_callees, 'Mergeable ABBs may not call relevant functions'

        parent_function = entry_abb.get_parent_function()


        # adopt basic blocks and call sites
        for abb in (inner_abbs | {exit_abb}) - {entry_abb}:
            if abb.get_seed() != entry_abb.get_seed():

                if entry_abb.append_basic_blocks(abb) == False:
                    print("ERROR: abb to merge not in graph")

                # Collect all call sites
                entry_abb.expend_call_sites(abb)




        # We merge everything into the entry block of a region.
        # Therefore, we just update the exit node of the entry to
        # preserve a correct entry/exit region
        entry_abb.adapt_exit_bb(exit_abb)




        # adopt outgoing edges
        for successor in exit_abb.get_successors():
            exit_abb.remove_successor(successor)
            seed = successor.get_seed()
            if not seed == entry_abb.get_seed(): # omit self loop
                entry_abb.set_successor(successor)
                successor.set_predecessor(entry_abb)
                successor.remove_predecessor(exit_abb)


        # Remove edges between entry and inner_abbs/exit
        for abb in inner_abbs | {entry_abb}:
            for successor in abb.get_successors():
                seed = successor.get_seed()
                for element in inner_abbs | {exit_abb}:
                    if element.get_seed() == seed:
                        abb.remove_successor(successor)
                        successor.remove_predecessor(abb)



        # remove conflict when entry abb has the exit abb as predecessor
        for predecessor in entry_abb.get_predecessors():
            seed = predecessor.get_seed()
            if exit_abb.get_seed() == seed:
                entry_abb.remove_predecessor(exit_abb)

        for abb in (inner_abbs | {exit_abb}):
            # Adapt exit ABB in corresponding function
            function_exit_abb = parent_function.get_exit_abb()

            if function_exit_abb != None and function_exit_abb.get_seed() == abb.get_seed():
                parent_function.set_exit_abb(entry_abb)


        # Remove merged successors from any existing list
        for abb in (inner_abbs | {exit_abb}) - {entry_abb}:

            parent_function.remove_abb(abb.get_seed())
            #if not parent_function.remove_abb(abb.get_seed()):
             #  print("Probem")
               #sys.exit("abb could not removed from function"+abb.get_name().decode("utf-8") )
            g.remove_vertex(abb.get_seed())
Beispiel #10
0
def validate_osek_syscalls_in_different_abstractions(g: graph.PyGraph):

    isr_list = g.get_type_vertices("ISR")

    #iterate about the isrs
    for isr in isr_list:

        #different syscalls allwoend in isrs from different type
        if isr.get_category() == 1:

            #list of all valid syscalls
            valid_calls = [(graph.get_type_hash("RTOS"),
                            graph.syscall_definition_type.enable),
                           (graph.get_type_hash("RTOS"),
                            graph.syscall_definition_type.disable),
                           (graph.get_type_hash("RTOS"),
                            graph.syscall_definition_type.suspend),
                           (graph.get_type_hash("RTOS"),
                            graph.syscall_definition_type.resume)]
            validate_syscalls(valid_calls, isr, False)

        elif isr.get_category() == 2:

            #list of all invalid syscalls
            valid_calls = [(graph.get_type_hash("RTOS"),
                            graph.syscall_definition_type.start_scheduler),
                           (graph.get_type_hash("Event"),
                            graph.syscall_definition_type.receive),
                           (graph.get_type_hash("Event"),
                            graph.syscall_definition_type.destroy),
                           (graph.get_type_hash("Task"),
                            graph.syscall_definition_type.chain)(
                                graph.get_type_hash("Task"),
                                graph.syscall_definition_type.destroy),
                           (graph.get_type_hash("RTOS"),
                            graph.syscall_definition_type.schedule)]
            validate_syscalls(valid_calls, isr, True)

    task_list = g.get_type_vertices("Task")

    #iterate about the tasks
    for task in task_list:

        #list of all invalid syscalls
        valid_calls = [
            (graph.get_type_hash("RTOS"),
             graph.syscall_definition_type.start_scheduler),
        ]
        validate_syscalls(valid_calls, task, True)

    hook_list = g.get_type_vertices("Hook")

    #iterate about the hooks
    for hook in hook_list:

        if hook.get_hook_type() != graph.hook_type.no_hook:
            #list of all valid syscalls
            valid_calls = [(graph.get_type_hash("RTOS"),
                            graph.syscall_definition_type.start_scheduler),
                           (graph.get_type_hash("Event"),
                            graph.syscall_definition_type.receive),
                           (graph.get_type_hash("Alarm"),
                            graph.syscall_definition_type.receive)(
                                graph.get_type_hash("RTOS"),
                                graph.syscall_definition_type.suspend),
                           (graph.get_type_hash("RTOS"),
                            graph.syscall_definition_type.receive)]
            validate_syscalls(valid_calls, hook, False)
Beispiel #11
0
    def run(self, g: graph.PyGraph):
        print("I'm an SyscallStep")
        #get information which os is used
        os =  self._config["os"]

        if os == "osek":
            g.set_os_type(graph.os_type.OSEK)
        elif os == "freertos":
            g.set_os_type(graph.os_type.FreeRTOS)

        self.select_syscalls(os)


        #iterate about the functions of the graph
        function_list = g.get_type_vertices("Function")

        for function in function_list:

            #iterate about the abbs of the functions
            abb_list = function.get_atomic_basic_blocks()

            #iterate about the abbs of the function
            for abb in abb_list:

                #check if abb has a call
                if abb.get_call_type() == graph.call_definition_type.has_call:

                    #get call name
                    call_name = abb.get_call_name()


                    #check if call is a function call or a sys call
                    syscall = self.syscall_dict.get(call_name.decode('ascii'), "error")
                    if syscall != "error":


                        assert abb.convert_call_to_syscall(call_name) == True, "could not convert call to syscall"


                        function.set_has_syscall(True)

                        expected_argument_types = graph.cast_expected_syscall_argument_types(syscall[0])

                        #different_calles_argument_types = abb.get_call_argument_types()

                        #assert len(different_calles_argument_types) <= 1, "more than one call in initial atomic basic block"


                        #specific_call_argument_types = different_calles_argument_types[0]

                        specific_call_argument_types = abb.get_call_argument_types()

                        success = True
                        counter = 0



                        #verify the typeid_hash_values of the syscall arguments
                        if len(expected_argument_types) != len(specific_call_argument_types):
                            success = False

                        else:



                            #iterate about the expected call types list
                            for expected_type in expected_argument_types:
                                #get argument types for this argument
                                argument_types = specific_call_argument_types[counter]

                                #iterate about the types
                                for argument_type in argument_types:
                                    tmp_success = False
                                    #check if type is in expected types

                                    if isinstance(expected_type, Iterable):
                                        for tmp_expected_type in expected_type:
                                            #check if argument type is equal to expected type
                                            if tmp_expected_type == argument_type:

                                                tmp_success = True
                                                break
                                    else:
                                        if expected_type == argument_type:
                                            tmp_success = True



                                    success = tmp_success
                                    if success == False:
                                        break

                                if success == False:
                                    break

                                counter+=1



                        #check if lists dont match
                        if success == False:
                            print("TODO",call_name,counter)
                            #sys.exit("unexpected argument type")
                            #abb.print_information();

                        abb.set_call_type(graph.call_definition_type.sys_call)
                        abb.set_syscall_type(syscall[1])
                        abb.set_call_target_instance(syscall[2])
                        abb.set_handler_argument_index(syscall[3])


                    #no syscall
                    else:
                            #set type to func call
                            abb.set_call_type(graph.call_definition_type.func_call)