github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/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 "bytes" 10 "flag" 11 "fmt" 12 "io" 13 "log" 14 "os" 15 "sort" 16 ) 17 18 func usage() { 19 fmt.Fprintf(os.Stderr, "usage: go tool nm [-n] [-size] [-sort order] [-type] file...\n") 20 os.Exit(2) 21 } 22 23 var ( 24 sortOrder = flag.String("sort", "name", "") 25 printSize = flag.Bool("size", false, "") 26 printType = flag.Bool("type", false, "") 27 28 filePrefix = false 29 ) 30 31 func init() { 32 flag.Var(nflag(0), "n", "") // alias for -sort address 33 } 34 35 type nflag int 36 37 func (nflag) IsBoolFlag() bool { 38 return true 39 } 40 41 func (nflag) Set(value string) error { 42 if value == "true" { 43 *sortOrder = "address" 44 } 45 return nil 46 } 47 48 func (nflag) String() string { 49 if *sortOrder == "address" { 50 return "true" 51 } 52 return "false" 53 } 54 55 func main() { 56 log.SetFlags(0) 57 flag.Usage = usage 58 flag.Parse() 59 60 switch *sortOrder { 61 case "address", "name", "none", "size": 62 // ok 63 default: 64 fmt.Fprintf(os.Stderr, "nm: unknown sort order %q\n", *sortOrder) 65 os.Exit(2) 66 } 67 68 args := flag.Args() 69 filePrefix = len(args) > 1 70 if len(args) == 0 { 71 flag.Usage() 72 } 73 74 for _, file := range args { 75 nm(file) 76 } 77 78 os.Exit(exitCode) 79 } 80 81 var exitCode = 0 82 83 func errorf(format string, args ...interface{}) { 84 log.Printf(format, args...) 85 exitCode = 1 86 } 87 88 type Sym struct { 89 Addr uint64 90 Size int64 91 Code rune 92 Name string 93 Type string 94 } 95 96 var parsers = []struct { 97 prefix []byte 98 parse func(*os.File) []Sym 99 }{ 100 {[]byte("!<arch>\n"), goobjSymbols}, 101 {[]byte("go object "), goobjSymbols}, 102 {[]byte("\x7FELF"), elfSymbols}, 103 {[]byte("\xFE\xED\xFA\xCE"), machoSymbols}, 104 {[]byte("\xFE\xED\xFA\xCF"), machoSymbols}, 105 {[]byte("\xCE\xFA\xED\xFE"), machoSymbols}, 106 {[]byte("\xCF\xFA\xED\xFE"), machoSymbols}, 107 {[]byte("MZ"), peSymbols}, 108 {[]byte("\x00\x00\x01\xEB"), plan9Symbols}, // 386 109 {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips 110 {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm 111 {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64 112 } 113 114 func nm(file string) { 115 f, err := os.Open(file) 116 if err != nil { 117 errorf("%v", err) 118 return 119 } 120 defer f.Close() 121 122 buf := make([]byte, 16) 123 io.ReadFull(f, buf) 124 f.Seek(0, 0) 125 126 var syms []Sym 127 for _, p := range parsers { 128 if bytes.HasPrefix(buf, p.prefix) { 129 syms = p.parse(f) 130 goto HaveSyms 131 } 132 } 133 errorf("%v: unknown file format", file) 134 return 135 136 HaveSyms: 137 switch *sortOrder { 138 case "address": 139 sort.Sort(byAddr(syms)) 140 case "name": 141 sort.Sort(byName(syms)) 142 case "size": 143 sort.Sort(bySize(syms)) 144 } 145 146 w := bufio.NewWriter(os.Stdout) 147 for _, sym := range syms { 148 if filePrefix { 149 fmt.Fprintf(w, "%s:\t", file) 150 } 151 if sym.Code == 'U' { 152 fmt.Fprintf(w, "%8s", "") 153 } else { 154 fmt.Fprintf(w, "%8x", sym.Addr) 155 } 156 if *printSize { 157 fmt.Fprintf(w, " %10d", sym.Size) 158 } 159 fmt.Fprintf(w, " %c %s", sym.Code, sym.Name) 160 if *printType && sym.Type != "" { 161 fmt.Fprintf(w, " %s", sym.Type) 162 } 163 fmt.Fprintf(w, "\n") 164 } 165 w.Flush() 166 } 167 168 type byAddr []Sym 169 170 func (x byAddr) Len() int { return len(x) } 171 func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 172 func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } 173 174 type byName []Sym 175 176 func (x byName) Len() int { return len(x) } 177 func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 178 func (x byName) Less(i, j int) bool { return x[i].Name < x[j].Name } 179 180 type bySize []Sym 181 182 func (x bySize) Len() int { return len(x) } 183 func (x bySize) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 184 func (x bySize) Less(i, j int) bool { return x[i].Size > x[j].Size }