예제 #1
0
def build_instrumentation_point_graphs(program : Program):
    instrumentation_point_graphs = {}
    depth_first_search_tree = DepthFirstSearch(program.call_graph,
                                               program.call_graph.root_function,
                                               False)
    # Traverse call graph in reverse topological order
    for call_vertex in depth_first_search_tree.post_order:
        verbose_message("Analysing function '{}'".format(call_vertex.name), __name__)
        caller_ipg = InstrumentationPointGraph.instrument_as_per_user_instruction\
            (program[call_vertex.name])
        instrumentation_point_graphs[call_vertex.name] = caller_ipg

        # Process every call made by this function
        for call_edge in call_vertex.successor_edge_iterator():
            callee_vertex = program.call_graph.get_vertex(call_edge.vertex_id)
            verbose_message("@ callee {}".format(callee_vertex.name), __name__)
            callee_ipg = instrumentation_point_graphs[callee_vertex.name]
            # Grab each instrumentation point from the callee that may be executed
            # first when the function begins
            entry_sign_posts = []
            if not callee_ipg.entry_vertex.abstract:
                entry_sign_posts.append(callee_ipg.entry_vertex)
            else:
                for succ_edge in callee_ipg.entry_vertex.successor_edge_iterator():
                    entry_sign_posts.append(callee_ipg.get_vertex(succ_edge.vertex_id))
            # Grab each instrumentation point from the callee that may be executed
            # last before the function returns
            exit_sign_posts = []
            if not callee_ipg.exit_vertex.abstract:
                exit_sign_posts.append(callee_ipg.exit_vertex)
            else:
                for pred_edge in callee_ipg.exit_vertex.predecessor_edge_iterator():
                    exit_sign_posts.append(callee_ipg.get_vertex(pred_edge.vertex_id))

            for call_site in call_edge.call_sites:
                verbose_message("@ call site {}".format(call_site), __name__)
                # Inline the sign posts to callee entry
                inlined_entry_program_points = set()
                for vertex in entry_sign_posts:
                    vertex_copy = ProgramPointVertex(caller_ipg.get_new_vertex_id(),
                                                     vertex.program_point,
                                                     abstract=True)
                    inlined_entry_program_points.add(vertex_copy)
                    caller_ipg.add_vertex(vertex_copy)
                # Inline the sign posts to callee exit
                inlined_exit_program_points = set()
                for vertex in exit_sign_posts:
                    vertex_copy = ProgramPointVertex(caller_ipg.get_new_vertex_id(),
                                                     vertex.program_point,
                                                     abstract=True)
                    inlined_exit_program_points.add(vertex_copy)
                    caller_ipg.add_vertex(vertex_copy)

                # Link the inlined instrumentation points
                for pred_vertex in inlined_entry_program_points:
                    for succ_vertex in inlined_exit_program_points:
                        caller_ipg.add_edge(pred_vertex, succ_vertex, None)

                # Relink the call site vertex
                edges_to_purge = set()
                call_site_vertex = caller_ipg.get_vertex_for_program_point(call_site)
                for pred_vertex in inlined_exit_program_points:
                    for redundant_succ_edge in call_site_vertex.successor_edge_iterator():
                        succ_vertex = caller_ipg.get_vertex(redundant_succ_edge.vertex_id)
                        caller_ipg.add_edge(pred_vertex, succ_vertex, None)
                        edges_to_purge.add((call_site_vertex, succ_vertex))
                        if redundant_succ_edge.backedge:
                            pred_edge = succ_vertex.get_predecessor_edge(pred_vertex.vertex_id)
                            succ_edge = pred_vertex.get_successor_edge(succ_vertex.vertex_id)
                            pred_edge.backedge = True
                            succ_edge.backedge = True

                for edge in edges_to_purge:
                    caller_ipg.remove_edge(*edge)

                for succ_vertex in inlined_entry_program_points:
                    caller_ipg.add_edge(call_site_vertex, succ_vertex, None)
        dot.make_file(caller_ipg)
    return instrumentation_point_graphs