github.com/decomp/exp@v0.0.0-20210624183419-6d058f5e1da6/cmd/bin2dot/cfg.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "sort" 6 "strconv" 7 8 "github.com/decomp/exp/bin" 9 "github.com/decomp/exp/disasm/x86" 10 "github.com/graphism/simple" 11 "github.com/pkg/errors" 12 "gonum.org/v1/gonum/graph" 13 "gonum.org/v1/gonum/graph/encoding" 14 ) 15 16 // dumpCFG dumps the control flow graph of the given function. 17 func dumpCFG(dis *x86.Disasm, f *x86.Func) (graph.Directed, error) { 18 // Index functions, basic blocks and instructions. 19 g := simple.NewDirectedGraph() 20 nodes := make(map[bin.Address]*Node) 21 for _, block := range f.Blocks { 22 id := strconv.Quote(block.Addr.String()) 23 n := &Node{ 24 Node: g.NewNode(), 25 id: id, 26 Attrs: make(Attrs), 27 } 28 if block.Addr == f.Addr { 29 n.Attrs["label"] = "entry" 30 } 31 nodes[block.Addr] = n 32 g.AddNode(n) 33 } 34 for _, block := range f.Blocks { 35 targets := dis.Targets(block.Term, f.Addr) 36 fmt.Println("block.Addr:", block.Addr) 37 fmt.Println("block.Term:", block.Term) 38 fmt.Println("targets:", targets) 39 fmt.Println() 40 41 from, ok := nodes[block.Addr] 42 if !ok { 43 panic(errors.Errorf("unable to locate basic block at %v", block.Addr)) 44 } 45 for i, target := range targets { 46 to, ok := nodes[target] 47 if !ok { 48 return nil, errors.Errorf("unable to locate target basic block at %v from %v in function at %v", target, block.Addr, f.Addr) 49 } 50 e := &Edge{ 51 Edge: simple.Edge{ 52 F: from, 53 T: to, 54 }, 55 Attrs: make(Attrs), 56 } 57 if len(targets) == 2 { 58 switch i { 59 case 0: 60 // true branch. 61 e.Attrs["label"] = "true" 62 e.Attrs["color"] = "darkgreen" 63 case 1: 64 // false branch. 65 e.Attrs["label"] = "false" 66 e.Attrs["color"] = "red" 67 } 68 } 69 g.SetEdge(e) 70 } 71 } 72 return g, nil 73 } 74 75 // Node is a basic block of a function. 76 type Node struct { 77 graph.Node 78 // DOTID of node. 79 id string 80 // DOT attributes. 81 Attrs 82 } 83 84 // DOTID returns the DOTID of the node. 85 func (n Node) DOTID() string { 86 return n.id 87 } 88 89 // Edge is an edge between two basic blocks in a function. 90 type Edge struct { 91 graph.Edge 92 // DOT attributes. 93 Attrs 94 } 95 96 // ### [ Helper functions ] #################################################### 97 98 // Attrs specifies a set of DOT attributes as key-value pairs. 99 type Attrs map[string]string 100 101 // --- [ encoding.Attributer ] ------------------------------------------------- 102 103 // Attributes returns the DOT attributes of a node or edge. 104 func (a Attrs) Attributes() []encoding.Attribute { 105 var keys []string 106 for key := range a { 107 keys = append(keys, key) 108 } 109 sort.Strings(keys) 110 var attrs []encoding.Attribute 111 for _, key := range keys { 112 attr := encoding.Attribute{ 113 Key: key, 114 Value: a[key], 115 } 116 attrs = append(attrs, attr) 117 } 118 return attrs 119 }