Exemplo n.º 1
0
// parseSubs parses the graph representations of the given high-level control
// flow primitives. If unable to locate a subgraph, a second attempt is made by
// prepending $GOPATH/src/decomp.org/decomp/cmd/restructure/primitives/ to the
// subgraph path.
func parseSubs(subPaths []string) (subs []*graphs.SubGraph, err error) {
	// Prepend $GOPATH/src/decomp.org/decomp/cmd/restructure/primitives/ to the path
	// of missing subgraphs.
	subDir, err := goutil.SrcDir("decomp.org/decomp/cmd/restructure/primitives")
	if err != nil {
		return nil, errutil.Err(err)
	}
	for i, subPath := range subPaths {
		if ok, _ := osutil.Exists(subPath); !ok {
			subPath = filepath.Join(subDir, subPath)
			subPaths[i] = subPath
		}
	}

	// Parse subgraphs representing control flow primitives.
	for _, subPath := range subPaths {
		sub, err := graphs.ParseSubGraph(subPath)
		if err != nil {
			return nil, errutil.Err(err)
		}
		subs = append(subs, sub)
	}

	return subs, nil
}
Exemplo n.º 2
0
Arquivo: iso.go Projeto: decomp/decomp
// locate parses the provided graphs and tries to locate isomorphisms of the
// subgraph in the graph.
func locate(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)
	}

	// Locate isomorphisms.
	found := false
	if len(flagStart) > 0 {
		// Locate 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)
		}
	} else {
		// Locate all isomorphisms of sub in graph.
		var names []string
		for name := range graph.Nodes.Lookup {
			names = append(names, name)
		}
		sort.Strings(names)
		for _, name := range names {
			m, ok := iso.Isomorphism(graph, name, sub)
			if !ok {
				continue
			}
			found = true
			printMapping(graph, sub, m)
		}
	}
	if !found {
		fmt.Println("not found.")
	}

	return nil
}
Exemplo n.º 3
0
func TestEquationIsValid(t *testing.T) {
	golden := []struct {
		subPath   string
		graphPath string
		eq        *equation
		want      bool
	}{
		// i=0
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "71",
					"body": "74",
					"exit": "75",
				},
			},
			want: true,
		},
		// i=1
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "17",
					"body": "24",
					"exit": "32",
				},
			},
			want: true,
		},
		// i=2
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "89",
					"body": "92",
					"exit": "93",
				},
			},
			want: false,
		},
		// i=3
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "94",
					"body": "97",
					"exit": "98",
				},
			},
			want: false,
		},
		// i=4
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			eq: &equation{
				m: map[string]string{
					"cond":       "282",
					"body_true":  "292",
					"body_false": "287",
					"exit":       "299",
				},
			},
			want: true,
		},
		// i=5
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			eq: &equation{
				m: map[string]string{
					"cond":       "282",
					"body_true":  "287",
					"body_false": "292",
					"exit":       "299",
				},
			},
			want: true,
		},
		// i=6
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			eq: &equation{
				m: map[string]string{
					"cond":       "438",
					"body_true":  "446",
					"body_false": "443",
					"exit":       "447",
				},
			},
			want: true,
		},
		// i=7
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			eq: &equation{
				m: map[string]string{
					"cond":       "438",
					"body_true":  "443",
					"body_false": "446",
					"exit":       "447",
				},
			},
			want: true,
		},
		// i=8
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			eq: &equation{
				m: map[string]string{
					"cond":       "487",
					"body_true":  "492",
					"body_false": "495",
					"exit":       "496",
				},
			},
			want: true,
		},
		// i=9
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			eq: &equation{
				m: map[string]string{
					"cond":       "487",
					"body_true":  "495",
					"body_false": "492",
					"exit":       "496",
				},
			},
			want: true,
		},
		// i=10
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			eq: &equation{
				m: map[string]string{
					"cond":       "124",
					"body_true":  "134",
					"body_false": "126",
					"exit":       "145",
				},
			},
			want: false,
		},
		// i=11
		{
			subPath:   "../testdata/primitives/list.dot",
			graphPath: "../testdata/c4_graphs/main.dot",
			eq: &equation{
				m: map[string]string{
					"entry": "740",
					"exit":  "760",
				},
			},
			want: true,
		},
		// i=12
		{
			subPath:   "../testdata/primitives/list.dot",
			graphPath: "../testdata/c4_graphs/main.dot",
			eq: &equation{
				m: map[string]string{
					"entry": "761",
					"exit":  "762",
				},
			},
			want: false,
		},
		// i=13
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "191",
					"body": "194",
					"exit": "196",
				},
			},
			want: true,
		},
		// i=14
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "370",
					"body": "378",
					"exit": "374",
				},
			},
			want: false,
		},
		// i=15
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "526",
					"body": "530",
					"exit": "539",
				},
			},
			want: false,
		},
		// i=16
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			eq: &equation{
				m: map[string]string{
					"cond":       "611",
					"body_true":  "615",
					"body_false": "615",
					"exit":       "631",
				},
			},
			want: false,
		},
		// i=17
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			eq: &equation{
				m: map[string]string{
					"cond":      "611",
					"body_true": "615",
					"exit":      "631",
				},
			},
			want: false,
		},
		// i=18
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/main.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "20",
					"body": "25",
					"exit": "34",
				},
			},
			want: false,
		},
		// i=19
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "39", // 48
					"body": "44",
					"exit": "52", // 45
				},
			},
			want: false,
		},
		// i=20
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			eq: &equation{
				m: map[string]string{
					"cond": "39",
					"body": "44",
					"exit": "45",
				},
			},
			want: false,
		},
	}

	for i, g := range golden {
		sub, err := graphs.ParseSubGraph(g.subPath)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		graph, err := dot.ParseFile(g.graphPath)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		got := g.eq.isValid(graph, sub)
		if got != g.want {
			t.Errorf("i=%d: ok mismatch; expected %v, got %v", i, g.want, got)
			continue
		}
	}
}
Exemplo n.º 4
0
func TestSolveBrute(t *testing.T) {
	golden := []struct {
		subPath   string
		graphPath string
		entry     string
		wants     []map[string]string
		err       string
	}{
		// i=0
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/primitives/if_else.dot",
			entry:     "cond",
			wants: []map[string]string{
				{
					"cond":       "cond",
					"body_true":  "body_true",
					"body_false": "body_false",
					"exit":       "exit",
				},
				{
					"cond":       "cond",
					"body_true":  "body_false",
					"body_false": "body_true",
					"exit":       "exit",
				},
			},
			err: "",
		},
		// i=1
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "85",
			wants:     []map[string]string{nil},
			err:       "unable to locate node pair mapping",
		},
		// i=2
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "71",
			wants:     []map[string]string{nil},
			err:       "unable to locate node pair mapping",
		},
		// i=3
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "89",
			wants: []map[string]string{
				{
					"cond": "89",
					"body": "92",
					"exit": "93",
				},
			},
		},
		// i=4
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "71",
			wants: []map[string]string{
				{
					"cond": "71",
					"body": "74",
					"exit": "75",
				},
			},
		},
	}

loop:
	for i, g := range golden {
		graph, err := dot.ParseFile(g.graphPath)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		sub, err := graphs.ParseSubGraph(g.subPath)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		eq, err := candidates(graph, g.entry, sub)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		m, err := eq.solveBrute(graph, sub)
		if !sameError(err, g.err) {
			t.Errorf("i=%d: error mismatch; expected %v, got %v", i, g.err, err)
			continue
		} else if err != nil {
			// Expected error, check next test case.
			continue
		}
		for _, want := range g.wants {
			if reflect.DeepEqual(m, want) {
				continue loop
			}
		}
		t.Errorf("i=%d: node pair map mismatch; expected one of %v, got %v", i, g.wants, m)
	}
}
Exemplo n.º 5
0
func TestSearch(t *testing.T) {
	golden := []struct {
		subPath   string
		graphPath string
		m         map[string]string
		ok        bool
	}{
		// i=0
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			m: map[string]string{
				"cond": "17",
				"body": "24",
				"exit": "32",
			},
			ok: true,
		},
		// i=1
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			m:         nil,
			ok:        false,
		},
		// i=2
		{
			subPath:   "../testdata/primitives/list.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			m: map[string]string{
				"entry": "101",
				"exit":  "105",
			},
			ok: true,
		},
		// i=3
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			m: map[string]string{
				"cond": "89",
				"body": "92",
				"exit": "93",
			},
			ok: true,
		},

		// i=4
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			m: map[string]string{
				"cond": "120",
				"body": "122",
				"exit": "127",
			},
			ok: true,
		},
		// i=5
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			m: map[string]string{
				"cond":       "282",
				"body_true":  "292",
				"body_false": "287",
				"exit":       "299",
			},
			ok: true,
		},
		// i=6
		{
			subPath:   "../testdata/primitives/list.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			m: map[string]string{
				"entry": "109",
				"exit":  "119",
			},
			ok: true,
		},
		// i=7
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/expr.dot",
			m: map[string]string{
				"cond": "191",
				"body": "194",
				"exit": "196",
			},
			ok: true,
		},

		// i=8
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			m: map[string]string{
				"cond": "195",
				"body": "200",
				"exit": "205",
			},
			ok: true,
		},
		// i=9
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			m: map[string]string{
				"cond":       "28",
				"body_true":  "44",
				"body_false": "39",
				"exit":       "46",
			},
			ok: true,
		},
		// i=10
		{
			subPath:   "../testdata/primitives/list.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			m: map[string]string{
				"entry": "320",
				"exit":  "322",
			},
			ok: true,
		},
		// i=11
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/next.dot",
			m:         nil,
			ok:        false,
		},

		// i=12
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/main.dot",
			m: map[string]string{
				"cond": "135",
				"body": "138",
				"exit": "139",
			},
			ok: true,
		},
		// i=13
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/main.dot",
			m: map[string]string{
				"cond":       "442",
				"body_true":  "451",
				"body_false": "448",
				"exit":       "453",
			},
			ok: true,
		},
		// i=14
		{
			subPath:   "../testdata/primitives/list.dot",
			graphPath: "../testdata/c4_graphs/main.dot",
			m: map[string]string{
				"entry": "740",
				"exit":  "760",
			},
			ok: true,
		},
		// i=15
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/main.dot",
			m: map[string]string{
				"cond": "190",
				"body": "193",
				"exit": "195",
			},
			ok: true,
		},
	}

	for i, g := range golden {
		sub, err := graphs.ParseSubGraph(g.subPath)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		graph, err := dot.ParseFile(g.graphPath)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		m, ok := Search(graph, sub)
		if ok != g.ok {
			t.Errorf("i=%d: ok mismatch; expected %v, got %v", i, g.ok, ok)
			continue
		}
		if !reflect.DeepEqual(m, g.m) {
			t.Errorf("i=%d: node pair mapping mismatch; expected %v, got %v", i, g.m, m)
		}
	}
}
Exemplo n.º 6
0
func TestCandidates(t *testing.T) {
	golden := []struct {
		subPath   string
		graphPath string
		entry     string
		want      map[string]map[string]bool
		err       string
	}{
		// i=0
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/primitives/if_else.dot",
			entry:     "cond",
			want: map[string]map[string]bool{
				"cond": {
					"cond": true,
				},
				"body_true": {
					"body_true":  true,
					"body_false": true,
				},
				"body_false": {
					"body_true":  true,
					"body_false": true,
				},
				"exit": {
					"exit": true,
				},
			},
			err: "",
		},
		// i=1
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "85",
			want: map[string]map[string]bool{
				"cond": {
					"85": true,
				},
				"body_true": {
					"88": true,
				},
				"body_false": {
					"88": true,
				},
				"exit": {
					"89": true,
				},
			},
			err: "",
		},
		// i=2
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "71",
			want: map[string]map[string]bool{
				"cond": {
					"71": true,
				},
				"body": {
					"74": true,
				},
				"exit": {
					"74": true,
				},
			},
			err: "",
		},
		// i=3
		{
			subPath:   "../testdata/primitives/pre_loop.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "89",
			want: map[string]map[string]bool{
				"cond": {
					"89": true,
				},
				"body": {
					"92": true,
					"93": true,
				},
				"exit": {
					"92": true,
					"93": true,
				},
			},
			err: "",
		},
		// i=4
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "71",
			want: map[string]map[string]bool{
				"cond": {
					"71": true,
				},
				"body": {
					"74": true,
				},
				"exit": {
					"75": true,
				},
			},
			err: "",
		},
		// i=5
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "foo",
			want:      nil,
			err:       `unable to locate entry node "foo" in graph`,
		},
		// i=6
		{
			subPath:   "../testdata/primitives/if.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "97",
			want:      nil,
			err:       `invalid entry node candidate "97"; expected 2 successors, got 1`,
		},
		// i=7
		{
			subPath:   "../testdata/primitives/if_else.dot",
			graphPath: "../testdata/c4_graphs/stmt.dot",
			entry:     "68",
			want:      nil,
			err:       "incomplete candidate mapping; expected 4 map entites, got 1",
		},
	}

	for i, g := range golden {
		sub, err := graphs.ParseSubGraph(g.subPath)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		graph, err := dot.ParseFile(g.graphPath)
		if err != nil {
			t.Errorf("i=%d: %v", i, err)
			continue
		}
		eq, err := candidates(graph, g.entry, sub)
		if !sameError(err, g.err) {
			t.Errorf("i=%d: error mismatch; expected %v, got %v", i, g.err, err)
			continue
		} else if err != nil {
			// Expected error, check next test case.
			continue
		}
		if !reflect.DeepEqual(eq.c, g.want) {
			t.Errorf("i=%d: candidate map mismatch; expected %v, got %v", i, g.want, eq.c)
		}
	}
}
Exemplo n.º 7
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
}