Example #1
0
// 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")
}
Example #2
0
// 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
}