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 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 func nm(file string) { 89 f, err := objfile.Open(file) 90 if err != nil { 91 errorf("%v", err) 92 return 93 } 94 defer f.Close() 95 96 syms, err := f.Symbols() 97 if err != nil { 98 errorf("reading %s: %v", file, err) 99 } 100 if len(syms) == 0 { 101 errorf("reading %s: no symbols", file) 102 } 103 104 switch *sortOrder { 105 case "address": 106 sort.Slice(syms, func(i, j int) bool { return syms[i].Addr < syms[j].Addr }) 107 case "name": 108 sort.Slice(syms, func(i, j int) bool { return syms[i].Name < syms[j].Name }) 109 case "size": 110 sort.Slice(syms, func(i, j int) bool { return syms[i].Size > syms[j].Size }) 111 } 112 113 w := bufio.NewWriter(os.Stdout) 114 for _, sym := range syms { 115 if filePrefix { 116 fmt.Fprintf(w, "%s:\t", file) 117 } 118 if sym.Code == 'U' { 119 fmt.Fprintf(w, "%8s", "") 120 } else { 121 fmt.Fprintf(w, "%8x", sym.Addr) 122 } 123 if *printSize { 124 fmt.Fprintf(w, " %10d", sym.Size) 125 } 126 fmt.Fprintf(w, " %c %s", sym.Code, sym.Name) 127 if *printType && sym.Type != "" { 128 fmt.Fprintf(w, " %s", sym.Type) 129 } 130 fmt.Fprintf(w, "\n") 131 } 132 w.Flush() 133 } 134