def execute(self, *args, **kwargs): self.global_variables = self.init_global_variables() # calculate summaries for functions for node in gcc.get_callgraph_nodes(): if not self.is_analyzed(node): self.analyze_node(node) # find thread entry points and concretize summaries self.find_races()
def to_dot(self): result = 'digraph Callgraph {\n' #result += ' subgraph cluster_callgraph {\n' result += ' node [shape=box];\n' for cgn in gcc.get_callgraph_nodes(): result += (' %s [label=<%s>];\n' % (self.node_id(cgn), self.node_to_dot_label(cgn))) for edge in cgn.callers: result += self.edge_to_dot(edge) #result += ' }\n' result += '}\n' return result
def sorted_callgraph(): """ Return the callgraph, in topologically-sorted order """ return topological_sort(gcc.get_callgraph_nodes(), get_srcs=lambda n: [edge.caller for edge in n.callers # Strip out recursive calls: if edge.caller != n], get_dsts=lambda n: [edge.callee for edge in n.callees # Strip out recursive calls: if edge.callee != n])
def get_graph(self, medges): graph = {} for cgn in gcc.get_callgraph_nodes(): fname = self.gcc_node_to_str(cgn) callees = [] if medges else set() callers = [] if medges else set() for edge in cgn.callees: add = callees.append if medges else callees.add add(self.gcc_node_to_str(edge.callee)) for edge in cgn.callers: add = callers.append if medges else callers.add add(self.gcc_node_to_str(edge.caller)) graph[fname] = Node(callers, callees) self.clean_lib_functions(graph) return graph
def to_dot(self): result = 'digraph Callgraph {\n' result += ' node [shape=ellipse];\n' # Consolidate duplicate edges together counts = { } for cgn in gcc.get_callgraph_nodes(): for edge in cgn.callers: edge_name = self.edge_to_dot(edge) counts[edge_name] = counts.get(edge_name, 0.0) + 0.001 # Print the accumulated edges for edge_name in counts: result += (' %s ' % edge_name) result += ('[ label = %.3f ];\n' % counts[edge_name]) result += '}\n' return result
def on_pass_execution(p, fn): #if p.name == '*warn_function_return': if p.name == '*free_lang_data': if 0: dot = callgraph_to_dot() invoke_dot(dot) for cgn in gcc.get_callgraph_nodes(): print('cgn:') # print(dir(cgn)) print(' cgn.decl: %r' % cgn.decl) print(' cgn.callers: %r' % cgn.callers) print(' cgn.callees: %r' % cgn.callees) for e in cgn.callers: print(e) print('e.caller: %r' % e.caller) print('e.callee: %r' % e.callee) print('e.call_stmt: %r %s' % (e.call_stmt, e.call_stmt))
def on_pass_execution(p, fn): if p.name == '*free_lang_data': sf = StateFinder() # Locate uses of such variables: for node in gcc.get_callgraph_nodes(): fun = node.decl.function if fun: cfg = fun.cfg if cfg: for bb in cfg.basic_blocks: stmts = bb.gimple if stmts: for stmt in stmts: stmt.walk_tree(sf.find_state_users, stmt.loc) # Flush the data that was found: sf.flush()
def get_node_by_name(self, name): # Returns node if exists, otherwise - None for node in gcc.get_callgraph_nodes(): if node.decl.name == name: return node return None
def on_pass_execution(p, fn): if p.name == '*free_lang_data': global publisher fname = "" arguments = {} tvars = {} data = {} callees_list = [] callers_list = [] parent_types_list = [] restr1 = r'[A-Z]\.[0-9]+' restr2 = r'_[0-9]+' rexp1 = re.compile(restr1) rexp2 = re.compile(restr2) for node in gcc.get_callgraph_nodes(): try: fn = node.decl.function cl = node.callees cr = node.callers parent = str(fn.decl.name) + '@' + str(fn.decl.location.file) \ + '_L' + str(fn.decl.location.line) + '_C' \ + str(fn.decl.location.column) data['parent'] = parent parent_type = str(fn.decl.type.type) data['parent_type'] = parent_type for edge in cl: callees_list.append(str(edge.call_stmt.fn) + '@' \ + str(edge.call_stmt.loc.file) + '_L' \ + str(edge.call_stmt.loc.line) + '_C' \ + str(edge.call_stmt.loc.column)) data['callees'] = callees_list for edge in cr: callers_list.append(str(edge.caller.decl.name) + '@' \ + str(edge.caller.decl.location.file) + '_L' \ + str(edge.caller.decl.location.line) + '_C' \ + str(edge.caller.decl.location.column)) data['callers'] = callers_list for arg in fn.decl.type.argument_types: parent_types_list.append(str(arg)) data['parent_argument_types'] = parent_types_list except AttributeError: continue """ print("IN FUNCTION:") print(parent) print("WHICH TYPE IS:") print(parent_type) print('AND ITS ARGUMENT\'S TYPES ARE: %r' \ % [str(arg) for arg in fn.decl.type.argument_types]) print("THAT CALLS:") print(callees_list) print("AND IS CALLED BY") print(callers_list) print("ALL FUNCTION CALLS") """ try: for bb in fn.cfg.basic_blocks: for stmt in bb.gimple: tvars = intake(stmt, tvars) if isinstance(stmt, gcc.GimpleCall): fnmatch1 = rexp1.search(str(stmt.fn)) fnmatch2 = rexp2.search(str(stmt.fn)) if fnmatch1: fname = str(unfold(tvars, fnmatch1.group())) \ + '@' + str(stmt.loc.file) \ + '_L' + str(stmt.loc.line) + '_C' \ + str(stmt.loc.column) #print(fname) elif fnmatch2: fname = str(unfold(tvars, fnmatch2.group())) \ + '@' + str(stmt.loc.file) \ + '_L' + str(stmt.loc.line) + '_C' \ + str(stmt.loc.column) #print(fname) else: fname = str(stmt.fn) + '@' + str(stmt.loc.file) \ + '_L' + str(stmt.loc.line) + '_C' \ + str(stmt.loc.column) #print(fname) for i, arg in enumerate(stmt.args): m1 = rexp1.search(str(stmt.args[i])) m2 = rexp2.search(str(stmt.args[i])) if m1: arguments[i] = unfold(tvars, m1.group()) elif m2: arguments[i] = unfold(tvars, m2.group()) else: arguments[i] = str(stmt.args[i]) #print(arguments) data[fname] = arguments arguments = {} #print("----------------------------------") except AttributeError: continue data_string = pickle.dumps(data) publisher.send(data_string) data.clear() del callees_list[:] del callers_list[:] del parent_types_list[:] #pprint.pprint(tvars) if p.name == "ssa": publisher.send(b"GCC_DISCONNECT")
def __init__(self, split_phi_nodes, add_fake_entry_node): Graph.__init__(self) self.supernode_for_stmtnode = {} # 1st pass: locate interprocedural instances of gcc.GimpleCall # i.e. where both caller and callee are within the supergraph # (perhaps the same function) ipcalls = set() from gcc import get_callgraph_nodes for node in get_callgraph_nodes(): fun = node.decl.function if fun: for edge in node.callees: if edge.callee.decl.function: ipcalls.add(edge.call_stmt) # 2nd pass: construct a StmtGraph for each function in the callgraph # and add nodes and edges to "self" wrapping the nodes and edges # within each StmtGraph: self.stmtg_for_fun = {} for node in get_callgraph_nodes(): fun = node.decl.function if fun: stmtg = StmtGraph(fun, split_phi_nodes) self.stmtg_for_fun[fun] = stmtg # Clone the stmtg nodes and edges into the Supergraph: stmtg.supernode_for_stmtnode = {} for node in stmtg.nodes: if node.stmt in ipcalls: # These nodes will have two supernodes, a CallNode # and a ReturnNode: callnode = self.add_node(CallNode(node, stmtg)) returnnode = self.add_node(ReturnNode(node, stmtg)) callnode.returnnode = returnnode returnnode.callnode = callnode stmtg.supernode_for_stmtnode[node] = (callnode, returnnode) self.add_edge( callnode, returnnode, CallToReturnSiteEdge, None) else: stmtg.supernode_for_stmtnode[node] = \ self.add_node(SupergraphNode(node, stmtg)) for edge in stmtg.edges: if edge.srcnode.stmt in ipcalls: # Begin the superedge from the ReturnNode: srcsupernode = stmtg.supernode_for_stmtnode[edge.srcnode][1] else: srcsupernode = stmtg.supernode_for_stmtnode[edge.srcnode] if edge.dstnode.stmt in ipcalls: # End the superedge at the CallNode: dstsupernode = stmtg.supernode_for_stmtnode[edge.dstnode][0] else: dstsupernode = stmtg.supernode_for_stmtnode[edge.dstnode] superedge = self.add_edge(srcsupernode, dstsupernode, SupergraphEdge, edge) # 3rd pass: add the interprocedural edges (call and return): for node in get_callgraph_nodes(): fun = node.decl.function if fun: for edge in node.callees: if edge.callee.decl.function: calling_stmtg = self.stmtg_for_fun[fun] called_stmtg = self.stmtg_for_fun[edge.callee.decl.function] calling_stmtnode = calling_stmtg.node_for_stmt[edge.call_stmt] assert calling_stmtnode entry_stmtnode = called_stmtg.entry assert entry_stmtnode exit_stmtnode = called_stmtg.exit assert exit_stmtnode superedge_call = self.add_edge( calling_stmtg.supernode_for_stmtnode[calling_stmtnode][0], called_stmtg.supernode_for_stmtnode[entry_stmtnode], CallToStart, None) superedge_return = self.add_edge( called_stmtg.supernode_for_stmtnode[exit_stmtnode], calling_stmtg.supernode_for_stmtnode[calling_stmtnode][1], ExitToReturnSite, None) superedge_return.calling_stmtnode = calling_stmtnode # 4th pass: create fake entry node: if not add_fake_entry_node: self.fake_entry_node = None return self.fake_entry_node = self.add_node(FakeEntryNode(None, None)) """ /* At file scope, the presence of a `static' or `register' storage class specifier, or the absence of all storage class specifiers makes this declaration a definition (perhaps tentative). Also, the absence of `static' makes it public. */ if (current_scope == file_scope) { TREE_PUBLIC (decl) = storage_class != csc_static; TREE_STATIC (decl) = !extern_ref; } """ # For now, assume all non-static functions are possible entrypoints: for fun in self.stmtg_for_fun: # Only for non-static functions: if fun.decl.is_public: stmtg = self.stmtg_for_fun[fun] self.add_edge(self.fake_entry_node, stmtg.supernode_for_stmtnode[stmtg.entry], FakeEntryEdge, None)
def __init__(self, split_phi_nodes, add_fake_entry_node): Graph.__init__(self) self.supernode_for_stmtnode = {} # 1st pass: locate interprocedural instances of gcc.GimpleCall # i.e. where both caller and callee are within the supergraph # (perhaps the same function) ipcalls = set() from gcc import get_callgraph_nodes for node in get_callgraph_nodes(): fun = node.decl.function if fun: for edge in node.callees: if edge.callee.decl.function: ipcalls.add(edge.call_stmt) # 2nd pass: construct a StmtGraph for each function in the callgraph # and add nodes and edges to "self" wrapping the nodes and edges # within each StmtGraph: self.stmtg_for_fun = {} for node in get_callgraph_nodes(): fun = node.decl.function if fun: stmtg = StmtGraph(fun, split_phi_nodes) self.stmtg_for_fun[fun] = stmtg # Clone the stmtg nodes and edges into the Supergraph: stmtg.supernode_for_stmtnode = {} for node in stmtg.nodes: if node.stmt in ipcalls: # These nodes will have two supernodes, a CallNode # and a ReturnNode: callnode = self.add_node(CallNode(node, stmtg)) returnnode = self.add_node(ReturnNode(node, stmtg)) callnode.returnnode = returnnode returnnode.callnode = callnode stmtg.supernode_for_stmtnode[node] = (callnode, returnnode) self.add_edge(callnode, returnnode, CallToReturnSiteEdge, None) else: stmtg.supernode_for_stmtnode[node] = \ self.add_node(SupergraphNode(node, stmtg)) for edge in stmtg.edges: if edge.srcnode.stmt in ipcalls: # Begin the superedge from the ReturnNode: srcsupernode = stmtg.supernode_for_stmtnode[ edge.srcnode][1] else: srcsupernode = stmtg.supernode_for_stmtnode[ edge.srcnode] if edge.dstnode.stmt in ipcalls: # End the superedge at the CallNode: dstsupernode = stmtg.supernode_for_stmtnode[ edge.dstnode][0] else: dstsupernode = stmtg.supernode_for_stmtnode[ edge.dstnode] superedge = self.add_edge(srcsupernode, dstsupernode, SupergraphEdge, edge) # 3rd pass: add the interprocedural edges (call and return): for node in get_callgraph_nodes(): fun = node.decl.function if fun: for edge in node.callees: if edge.callee.decl.function: calling_stmtg = self.stmtg_for_fun[fun] called_stmtg = self.stmtg_for_fun[ edge.callee.decl.function] calling_stmtnode = calling_stmtg.node_for_stmt[ edge.call_stmt] assert calling_stmtnode entry_stmtnode = called_stmtg.entry assert entry_stmtnode exit_stmtnode = called_stmtg.exit assert exit_stmtnode superedge_call = self.add_edge( calling_stmtg. supernode_for_stmtnode[calling_stmtnode][0], called_stmtg. supernode_for_stmtnode[entry_stmtnode], CallToStart, None) superedge_return = self.add_edge( called_stmtg.supernode_for_stmtnode[exit_stmtnode], calling_stmtg. supernode_for_stmtnode[calling_stmtnode][1], ExitToReturnSite, None) superedge_return.calling_stmtnode = calling_stmtnode # 4th pass: create fake entry node: if not add_fake_entry_node: self.fake_entry_node = None return self.fake_entry_node = self.add_node(FakeEntryNode(None, None)) """ /* At file scope, the presence of a `static' or `register' storage class specifier, or the absence of all storage class specifiers makes this declaration a definition (perhaps tentative). Also, the absence of `static' makes it public. */ if (current_scope == file_scope) { TREE_PUBLIC (decl) = storage_class != csc_static; TREE_STATIC (decl) = !extern_ref; } """ # For now, assume all non-static functions are possible entrypoints: for fun in self.stmtg_for_fun: # Only for non-static functions: if fun.decl.is_public: stmtg = self.stmtg_for_fun[fun] self.add_edge(self.fake_entry_node, stmtg.supernode_for_stmtnode[stmtg.entry], FakeEntryEdge, None)