Source file src/cmd/nm/nm.go

     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  const helpText = `usage: go tool nm [options] file...
    19    -n
    20        an alias for -sort address (numeric),
    21        for compatibility with other nm commands
    22    -size
    23        print symbol size in decimal between address and type
    24    -sort {address,name,none,size}
    25        sort output in the given order (default name)
    26        size orders from largest to smallest
    27    -type
    28        print symbol type after name
    29  `
    30  
    31  func usage() {
    32  	fmt.Fprint(os.Stderr, helpText)
    33  	os.Exit(2)
    34  }
    35  
    36  var (
    37  	sortOrder = flag.String("sort", "name", "")
    38  	printSize = flag.Bool("size", false, "")
    39  	printType = flag.Bool("type", false, "")
    40  
    41  	filePrefix = false
    42  )
    43  
    44  func init() {
    45  	flag.Var(nflag(0), "n", "") // alias for -sort address
    46  }
    47  
    48  type nflag int
    49  
    50  func (nflag) IsBoolFlag() bool {
    51  	return true
    52  }
    53  
    54  func (nflag) Set(value string) error {
    55  	if value == "true" {
    56  		*sortOrder = "address"
    57  	}
    58  	return nil
    59  }
    60  
    61  func (nflag) String() string {
    62  	if *sortOrder == "address" {
    63  		return "true"
    64  	}
    65  	return "false"
    66  }
    67  
    68  func main() {
    69  	log.SetFlags(0)
    70  	flag.Usage = usage
    71  	flag.Parse()
    72  
    73  	switch *sortOrder {
    74  	case "address", "name", "none", "size":
    75  		// ok
    76  	default:
    77  		fmt.Fprintf(os.Stderr, "nm: unknown sort order %q\n", *sortOrder)
    78  		os.Exit(2)
    79  	}
    80  
    81  	args := flag.Args()
    82  	filePrefix = len(args) > 1
    83  	if len(args) == 0 {
    84  		flag.Usage()
    85  	}
    86  
    87  	for _, file := range args {
    88  		nm(file)
    89  	}
    90  
    91  	os.Exit(exitCode)
    92  }
    93  
    94  var exitCode = 0
    95  
    96  func errorf(format string, args ...any) {
    97  	log.Printf(format, args...)
    98  	exitCode = 1
    99  }
   100  
   101  func nm(file string) {
   102  	f, err := objfile.Open(file)
   103  	if err != nil {
   104  		errorf("%v", err)
   105  		return
   106  	}
   107  	defer f.Close()
   108  
   109  	w := bufio.NewWriter(os.Stdout)
   110  
   111  	entries := f.Entries()
   112  
   113  	var found bool
   114  
   115  	for _, e := range entries {
   116  		syms, err := e.Symbols()
   117  		if err != nil {
   118  			errorf("reading %s: %v", file, err)
   119  		}
   120  		if len(syms) == 0 {
   121  			continue
   122  		}
   123  
   124  		found = true
   125  
   126  		switch *sortOrder {
   127  		case "address":
   128  			sort.Slice(syms, func(i, j int) bool { return syms[i].Addr < syms[j].Addr })
   129  		case "name":
   130  			sort.Slice(syms, func(i, j int) bool { return syms[i].Name < syms[j].Name })
   131  		case "size":
   132  			sort.Slice(syms, func(i, j int) bool { return syms[i].Size > syms[j].Size })
   133  		}
   134  
   135  		for _, sym := range syms {
   136  			if len(entries) > 1 {
   137  				name := e.Name()
   138  				if name == "" {
   139  					fmt.Fprintf(w, "%s(%s):\t", file, "_go_.o")
   140  				} else {
   141  					fmt.Fprintf(w, "%s(%s):\t", file, name)
   142  				}
   143  			} else if filePrefix {
   144  				fmt.Fprintf(w, "%s:\t", file)
   145  			}
   146  			if sym.Code == 'U' {
   147  				fmt.Fprintf(w, "%8s", "")
   148  			} else {
   149  				fmt.Fprintf(w, "%8x", sym.Addr)
   150  			}
   151  			if *printSize {
   152  				fmt.Fprintf(w, " %10d", sym.Size)
   153  			}
   154  			fmt.Fprintf(w, " %c %s", sym.Code, sym.Name)
   155  			if *printType && sym.Type != "" {
   156  				fmt.Fprintf(w, " %s", sym.Type)
   157  			}
   158  			fmt.Fprintf(w, "\n")
   159  		}
   160  	}
   161  
   162  	if !found {
   163  		errorf("reading %s: no symbols", file)
   164  	}
   165  
   166  	w.Flush()
   167  }
   168  

View as plain text