github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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  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.Sort(byAddr(syms))
   107  	case "name":
   108  		sort.Sort(byName(syms))
   109  	case "size":
   110  		sort.Sort(bySize(syms))
   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  
   135  type byAddr []objfile.Sym
   136  
   137  func (x byAddr) Len() int           { return len(x) }
   138  func (x byAddr) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   139  func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
   140  
   141  type byName []objfile.Sym
   142  
   143  func (x byName) Len() int           { return len(x) }
   144  func (x byName) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   145  func (x byName) Less(i, j int) bool { return x[i].Name < x[j].Name }
   146  
   147  type bySize []objfile.Sym
   148  
   149  func (x bySize) Len() int           { return len(x) }
   150  func (x bySize) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   151  func (x bySize) Less(i, j int) bool { return x[i].Size > x[j].Size }