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 }