github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/cmd/nm/nm.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 package main 6 7 import ( 8 "bufio" 9 "flag" 10 "fmt" 11 "log" 12 "os" 13 "sort" 14 15 "cmd/internal/objfile" 16 ) 17 18 const helpText = `usage: go tool nm [options] file... 19 -n 20 an alias for -sort address (numeric), 21 for compatibility with other nm commands 22 -size 23 print symbol size in decimal between address and type 24 -sort {address,name,none,size} 25 sort output in the given order (default name) 26 size orders from largest to smallest 27 -type 28 print symbol type after name 29 ` 30 31 func usage() { 32 fmt.Fprintf(os.Stderr, helpText) 33 os.Exit(2) 34 } 35 36 var ( 37 sortOrder = flag.String("sort", "name", "") 38 printSize = flag.Bool("size", false, "") 39 printType = flag.Bool("type", false, "") 40 41 filePrefix = false 42 ) 43 44 func init() { 45 flag.Var(nflag(0), "n", "") // alias for -sort address 46 } 47 48 type nflag int 49 50 func (nflag) IsBoolFlag() bool { 51 return true 52 } 53 54 func (nflag) Set(value string) error { 55 if value == "true" { 56 *sortOrder = "address" 57 } 58 return nil 59 } 60 61 func (nflag) String() string { 62 if *sortOrder == "address" { 63 return "true" 64 } 65 return "false" 66 } 67 68 func main() { 69 log.SetFlags(0) 70 flag.Usage = usage 71 flag.Parse() 72 73 switch *sortOrder { 74 case "address", "name", "none", "size": 75 // ok 76 default: 77 fmt.Fprintf(os.Stderr, "nm: unknown sort order %q\n", *sortOrder) 78 os.Exit(2) 79 } 80 81 args := flag.Args() 82 filePrefix = len(args) > 1 83 if len(args) == 0 { 84 flag.Usage() 85 } 86 87 for _, file := range args { 88 nm(file) 89 } 90 91 os.Exit(exitCode) 92 } 93 94 var exitCode = 0 95 96 func errorf(format string, args ...interface{}) { 97 log.Printf(format, args...) 98 exitCode = 1 99 } 100 101 func nm(file string) { 102 f, err := objfile.Open(file) 103 if err != nil { 104 errorf("%v", err) 105 return 106 } 107 defer f.Close() 108 109 syms, err := f.Symbols() 110 if err != nil { 111 errorf("reading %s: %v", file, err) 112 } 113 if len(syms) == 0 { 114 errorf("reading %s: no symbols", file) 115 } 116 117 switch *sortOrder { 118 case "address": 119 sort.Slice(syms, func(i, j int) bool { return syms[i].Addr < syms[j].Addr }) 120 case "name": 121 sort.Slice(syms, func(i, j int) bool { return syms[i].Name < syms[j].Name }) 122 case "size": 123 sort.Slice(syms, func(i, j int) bool { return syms[i].Size > syms[j].Size }) 124 } 125 126 w := bufio.NewWriter(os.Stdout) 127 for _, sym := range syms { 128 if filePrefix { 129 fmt.Fprintf(w, "%s:\t", file) 130 } 131 if sym.Code == 'U' { 132 fmt.Fprintf(w, "%8s", "") 133 } else { 134 fmt.Fprintf(w, "%8x", sym.Addr) 135 } 136 if *printSize { 137 fmt.Fprintf(w, " %10d", sym.Size) 138 } 139 fmt.Fprintf(w, " %c %s", sym.Code, sym.Name) 140 if *printType && sym.Type != "" { 141 fmt.Fprintf(w, " %s", sym.Type) 142 } 143 fmt.Fprintf(w, "\n") 144 } 145 w.Flush() 146 }