Beispiel #1
0
 def create_control_flow_graphs():
     for function_name, edge_list in edges_in_control_flow_graphs.items():
         control_flow_graph = directed_graphs.ControlFlowGraph(function_name)
         # Add vertices to control flow graph representing basic blocks
         for an_edge in edge_list:
             pred_id = parse_int(an_edge[0])
             succ_id = parse_int(an_edge[1])
             if not control_flow_graph.has_vertex(pred_id):
                 control_flow_graph.add_vertex(ProgramPointVertex(pred_id, pred_id))
             if not control_flow_graph.has_vertex(succ_id):
                 control_flow_graph.add_vertex(ProgramPointVertex(succ_id, succ_id))
         # Add vertices to control flow graph representing transitions and
         # then link these to basic blocks
         for an_edge in edge_list:
             pred_id = parse_int(an_edge[0])
             succ_id = parse_int(an_edge[1])
             vertex = ProgramPointVertex(control_flow_graph.get_new_vertex_id(), (pred_id, succ_id))
             control_flow_graph.add_vertex(vertex)
             control_flow_graph.add_edge(control_flow_graph.get_vertex(pred_id), vertex)
             control_flow_graph.add_edge(vertex, control_flow_graph.get_vertex(succ_id))
         # Find entry and exit vertex, then add vertex representing an edge
         # from the exit vertex to the entry vertex
         control_flow_graph.set_entry_vertex()
         control_flow_graph.set_exit_vertex()
         control_flow_graph.add_exit_to_entry_edge()
         program[function_name] = control_flow_graph
         dot.make_file(control_flow_graph)
Beispiel #2
0
 def create_call_graph():
     for call_site_id, caller, callee in edges_in_call_graph:
         if program.call_graph.has_vertex_with_name(caller) and program.call_graph.has_vertex_with_name(callee):
             pred_call_vertex = program.call_graph.get_vertex_with_name(caller)
             succ_call_vertex = program.call_graph.get_vertex_with_name(callee)
             program.call_graph.add_edge(pred_call_vertex, succ_call_vertex, parse_int(call_site_id))
     dot.make_file(program.call_graph)
Beispiel #3
0
def generate_program():
    program = Program()
    for function_id in range(1, globals.args["subprograms"] + 1):
        function_name = "f{}".format(function_id)
        control_flow_graph = directed_graphs.create_control_flow_graph(function_name)
        program[function_name] = control_flow_graph
        dot.make_file(control_flow_graph)

    # For each control flow graph, work out which basic blocks can legitimately
    #  make calls.
    call_site_candidates = {}
    for control_flow_graph in program:
        depth_first_search = directed_graphs.DepthFirstSearch(
            control_flow_graph, control_flow_graph.entry_vertex, False
        )
        candidates_for_this_function = []
        for vertex in control_flow_graph:
            if vertex.number_of_successors() == 1:
                succ_vertex = control_flow_graph.get_vertex(vertex.get_ith_successor_edge(0).vertex_id)
                # Check that the sole successor is not a loop header.
                if (vertex, succ_vertex) not in depth_first_search.backedges:
                    candidates_for_this_function.append(vertex)
        call_site_candidates[control_flow_graph.name] = candidates_for_this_function

    # Sort the functions by the number of call sites.
    function_ordering = collections.OrderedDict(
        sorted(call_site_candidates.items(), key=lambda tup: len(tup[1]), reverse=True)
    )

    # Assign each function a level in the call graph.
    levels_in_call_graph = {}
    level = 0
    for function_name in function_ordering.keys():
        levels_in_call_graph.setdefault(level, []).append(function_name)
        if level == 0:
            level += 1
        elif bool(random.getrandbits(1)) and len(call_site_candidates[function_name]) > 0:
            level += 1

    #  Add acyclic call graph edges by finding a caller that is at a lower level
    # than the callee.
    for level in sorted(levels_in_call_graph.keys(), reverse=True):
        if level > 0:
            for callee in levels_in_call_graph[level]:
                if random.random() < 0.2:
                    level_lower_than_current = random.randint(0, level - 1)
                else:
                    level_lower_than_current = level - 1

                candidate_callers = levels_in_call_graph[level_lower_than_current]
                caller = candidate_callers[random.randint(0, len(candidate_callers) - 1)]
                call_site_index = random.randint(0, len(call_site_candidates[caller]) - 1)
                call_site_vertex = call_site_candidates[caller][call_site_index]
                call_site_candidates[caller].remove(call_site_vertex)
                program.call_graph.add_edge(
                    program.call_graph.get_vertex_with_name(caller),
                    program.call_graph.get_vertex_with_name(callee),
                    call_site_vertex.vertex_id,
                )
                if len(call_site_candidates[caller]) == 0:
                    candidate_callers.remove(caller)

    # Now that we have tried our best so that there is a path from a designated
    # root vertex to every function, add acyclic edges indiscriminately.
    for level in sorted(levels_in_call_graph.keys(), reverse=True):
        if level > 0:
            for callee in levels_in_call_graph[level]:
                if bool(random.getrandbits(1)):
                    while True:
                        level_lower_than_current = random.randint(0, level - 1)
                        candidate_callers = levels_in_call_graph[level_lower_than_current]
                        if candidate_callers:
                            caller = candidate_callers[random.randint(0, len(candidate_callers) - 1)]
                            call_site_index = random.randint(0, len(call_site_candidates[caller]) - 1)
                            call_site_vertex = call_site_candidates[caller][call_site_index]
                            call_site_candidates[caller].remove(call_site_vertex)
                            program.call_graph.add_edge(
                                program.call_graph.get_vertex_with_name(caller),
                                program.call_graph.get_vertex_with_name(callee),
                                call_site_vertex.vertex_id,
                            )
                            if len(call_site_candidates[caller]) == 0:
                                candidate_callers.remove(caller)
                        else:
                            break
    dot.make_file(program.call_graph)
    return program