// findPrim locates a control flow primitive in the provided control flow graph // and merges its nodes into a single node. func findPrim(graph *dot.Graph, subs []*graphs.SubGraph, step int) (*primitive.Primitive, error) { for _, sub := range subs { // Locate an isomorphism of sub in graph. m, ok := iso.Search(graph, sub) if !ok { // No match, try next control flow primitive. continue } if flagVerbose && !flagQuiet { printMapping(graph, sub, m) } // Output pre-merge intermediate control flow graphs. if flagSteps { // Highlight nodes to be replaced in red. for _, preNodeName := range m { preNode, ok := graph.Nodes.Lookup[preNodeName] if !ok { return nil, errutil.Newf("unable to locate pre-merge node %q", preNodeName) } if preNode.Attrs == nil { preNode.Attrs = dot.NewAttrs() } preNode.Attrs["fillcolor"] = "red" preNode.Attrs["style"] = "filled" } // Store pre-merge DOT graph. stepName := fmt.Sprintf("%s_%da", graph.Name, step) if err := createDOT(stepName, graph); err != nil { return nil, errutil.Err(err) } // Restore node colour. for _, preNodeName := range m { preNode, ok := graph.Nodes.Lookup[preNodeName] if !ok { return nil, errutil.Newf("unable to locate pre-merge node %q", preNodeName) } delete(preNode.Attrs, "fillcolor") delete(preNode.Attrs, "style") } } // Check if one of the nodes to be merged has the label "entry". hasEntry := false for _, preNodeName := range m { preNode, ok := graph.Nodes.Lookup[preNodeName] if !ok { return nil, errutil.Newf("unable to locate pre-merge node %q", preNodeName) } if preNode.Attrs != nil && preNode.Attrs["label"] == "entry" { hasEntry = true break } } // Merge the nodes of the subgraph isomorphism into a single node. postNodeName, err := merge.Merge(graph, m, sub) if err != nil { return nil, errutil.Err(err) } // Add "entry" label to new node if present in the pre-merge nodes. if hasEntry { postNode, ok := graph.Nodes.Lookup[postNodeName] if !ok { return nil, errutil.Newf("unable to locate post-merge node %q", postNodeName) } if postNode.Attrs == nil { postNode.Attrs = dot.NewAttrs() } postNode.Attrs["label"] = "entry" index := postNode.Index graph.Nodes.Nodes[0], graph.Nodes.Nodes[index] = postNode, graph.Nodes.Nodes[0] } // Output post-merge intermediate control flow graphs. if flagSteps { // Highlight node to be replaced in red. postNode, ok := graph.Nodes.Lookup[postNodeName] if !ok { return nil, errutil.Newf("unable to locate post-merge node %q", postNodeName) } if postNode.Attrs == nil { postNode.Attrs = dot.NewAttrs() } postNode.Attrs["fillcolor"] = "red" postNode.Attrs["style"] = "filled" // Store post-merge DOT graph. stepName := fmt.Sprintf("%s_%db", graph.Name, step) if err := createDOT(stepName, graph); err != nil { return nil, errutil.Err(err) } // Restore node colour. delete(postNode.Attrs, "fillcolor") delete(postNode.Attrs, "style") } // Create a new control flow primitive. prim := &primitive.Primitive{ Node: postNodeName, Prim: sub.Name, Nodes: m, } return prim, nil } return nil, errutil.New("unable to locate control flow primitive") }
// locateAndMerge parses the provided graphs and tries to merge isomorphisms of // the subgraph in the graph into single nodes. func locateAndMerge(graphPath, subPath string) error { // Parse graph. graph, err := dot.ParseFile(graphPath) if err != nil { return errutil.Err(err) } // Search for subgraph in GOPATH if not found. if ok, _ := osutil.Exists(subPath); !ok { dir, err := goutil.SrcDir("decomp.org/decomp/graphs/testdata/primitives") if err != nil { return errutil.Err(err) } subPath = filepath.Join(dir, subPath) } sub, err := graphs.ParseSubGraph(subPath) if err != nil { return errutil.Err(err) } // Merge isomorphisms. found := false if len(flagStart) > 0 { // Merge an isomorphism of sub in graph which starts at the node // specified by the "-start" flag. m, ok := iso.Isomorphism(graph, flagStart, sub) if ok { found = true printMapping(graph, sub, m) _, err := merge.Merge(graph, m, sub) if err != nil { return errutil.Err(err) } } } else { // Merge all isomorphisms of sub in graph. for { m, ok := iso.Search(graph, sub) if !ok { break } found = true printMapping(graph, sub, m) _, err := merge.Merge(graph, m, sub) if err != nil { return errutil.Err(err) } } } // Store DOT and PNG representation of graph. if found { err = dump(graph) if err != nil { return errutil.Err(err) } } else { fmt.Println("not found.") } return nil }