Home | History | Annotate | Download | only in nm
      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