github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/internal/cmd/irdump/main.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // irdump: a tool for displaying the IR form of Go programs. 6 package main 7 8 import ( 9 "flag" 10 "fmt" 11 "go/build" 12 "os" 13 "runtime/pprof" 14 15 "github.com/amarpal/go-tools/go/ir" 16 "github.com/amarpal/go-tools/go/ir/irutil" 17 18 "golang.org/x/tools/go/buildutil" 19 "golang.org/x/tools/go/packages" 20 ) 21 22 // flags 23 var ( 24 mode = ir.BuilderMode(ir.PrintPackages | ir.PrintFunctions) 25 testFlag = flag.Bool("test", false, "include implicit test packages and executables") 26 cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") 27 dot bool 28 html string 29 ) 30 31 func init() { 32 flag.Var(&mode, "build", ir.BuilderModeDoc) 33 flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc) 34 flag.BoolVar(&dot, "dot", false, "Print Graphviz dot of CFG") 35 flag.StringVar(&html, "html", "", "Print HTML for 'function'") 36 } 37 38 const usage = `IR builder. 39 Usage: irdump [-build=[DBCSNFL]] [-test] [-arg=...] package... 40 Use -help flag to display options. 41 42 Examples: 43 % irdump -build=F hello.go # dump IR form of a single package 44 % irdump -build=F -test fmt # dump IR form of a package and its tests 45 ` 46 47 func main() { 48 if err := doMain(); err != nil { 49 fmt.Fprintf(os.Stderr, "irdump: %s\n", err) 50 os.Exit(1) 51 } 52 } 53 54 func doMain() error { 55 flag.Parse() 56 if len(flag.Args()) == 0 { 57 fmt.Fprint(os.Stderr, usage) 58 os.Exit(1) 59 } 60 61 cfg := &packages.Config{ 62 Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedDeps | packages.NeedTypes | packages.NeedTypesSizes | packages.NeedSyntax | packages.NeedTypesInfo, 63 Tests: *testFlag, 64 } 65 66 // Profiling support. 67 if *cpuprofile != "" { 68 f, err := os.Create(*cpuprofile) 69 if err != nil { 70 fmt.Fprintln(os.Stderr, err) 71 os.Exit(1) 72 } 73 pprof.StartCPUProfile(f) 74 defer pprof.StopCPUProfile() 75 } 76 77 // Load, parse and type-check the initial packages. 78 initial, err := packages.Load(cfg, flag.Args()...) 79 if err != nil { 80 return err 81 } 82 if len(initial) == 0 { 83 return fmt.Errorf("no packages") 84 } 85 if packages.PrintErrors(initial) > 0 { 86 return fmt.Errorf("packages contain errors") 87 } 88 89 // Create IR-form program representation. 90 _, pkgs := irutil.Packages(initial, mode, &irutil.Options{PrintFunc: html}) 91 92 for i, p := range pkgs { 93 if p == nil { 94 return fmt.Errorf("cannot build IR for package %s", initial[i]) 95 } 96 } 97 98 // Build and display only the initial packages 99 // (and synthetic wrappers). 100 for _, p := range pkgs { 101 p.Build() 102 } 103 104 if dot { 105 for _, p := range pkgs { 106 for _, m := range p.Members { 107 if fn, ok := m.(*ir.Function); ok { 108 fmt.Println("digraph{") 109 fmt.Printf("label = %q;\n", fn.Name()) 110 for _, b := range fn.Blocks { 111 fmt.Printf("n%d [label=\"%d: %s\"]\n", b.Index, b.Index, b.Comment) 112 for _, succ := range b.Succs { 113 fmt.Printf("n%d -> n%d\n", b.Index, succ.Index) 114 } 115 } 116 fmt.Println("}") 117 } 118 } 119 } 120 } 121 return nil 122 }