diff options
Diffstat (limited to 'src/cmd/nm/nm.go')
-rw-r--r-- | src/cmd/nm/nm.go | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go new file mode 100644 index 0000000..4572399 --- /dev/null +++ b/src/cmd/nm/nm.go @@ -0,0 +1,167 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bufio" + "flag" + "fmt" + "log" + "os" + "sort" + + "cmd/internal/objfile" +) + +const helpText = `usage: go tool nm [options] file... + -n + an alias for -sort address (numeric), + for compatibility with other nm commands + -size + print symbol size in decimal between address and type + -sort {address,name,none,size} + sort output in the given order (default name) + size orders from largest to smallest + -type + print symbol type after name +` + +func usage() { + fmt.Fprintf(os.Stderr, helpText) + os.Exit(2) +} + +var ( + sortOrder = flag.String("sort", "name", "") + printSize = flag.Bool("size", false, "") + printType = flag.Bool("type", false, "") + + filePrefix = false +) + +func init() { + flag.Var(nflag(0), "n", "") // alias for -sort address +} + +type nflag int + +func (nflag) IsBoolFlag() bool { + return true +} + +func (nflag) Set(value string) error { + if value == "true" { + *sortOrder = "address" + } + return nil +} + +func (nflag) String() string { + if *sortOrder == "address" { + return "true" + } + return "false" +} + +func main() { + log.SetFlags(0) + flag.Usage = usage + flag.Parse() + + switch *sortOrder { + case "address", "name", "none", "size": + // ok + default: + fmt.Fprintf(os.Stderr, "nm: unknown sort order %q\n", *sortOrder) + os.Exit(2) + } + + args := flag.Args() + filePrefix = len(args) > 1 + if len(args) == 0 { + flag.Usage() + } + + for _, file := range args { + nm(file) + } + + os.Exit(exitCode) +} + +var exitCode = 0 + +func errorf(format string, args ...interface{}) { + log.Printf(format, args...) + exitCode = 1 +} + +func nm(file string) { + f, err := objfile.Open(file) + if err != nil { + errorf("%v", err) + return + } + defer f.Close() + + w := bufio.NewWriter(os.Stdout) + + entries := f.Entries() + + var found bool + + for _, e := range entries { + syms, err := e.Symbols() + if err != nil { + errorf("reading %s: %v", file, err) + } + if len(syms) == 0 { + continue + } + + found = true + + switch *sortOrder { + case "address": + sort.Slice(syms, func(i, j int) bool { return syms[i].Addr < syms[j].Addr }) + case "name": + sort.Slice(syms, func(i, j int) bool { return syms[i].Name < syms[j].Name }) + case "size": + sort.Slice(syms, func(i, j int) bool { return syms[i].Size > syms[j].Size }) + } + + for _, sym := range syms { + if len(entries) > 1 { + name := e.Name() + if name == "" { + fmt.Fprintf(w, "%s(%s):\t", file, "_go_.o") + } else { + fmt.Fprintf(w, "%s(%s):\t", file, name) + } + } else if filePrefix { + fmt.Fprintf(w, "%s:\t", file) + } + if sym.Code == 'U' { + fmt.Fprintf(w, "%8s", "") + } else { + fmt.Fprintf(w, "%8x", sym.Addr) + } + if *printSize { + fmt.Fprintf(w, " %10d", sym.Size) + } + fmt.Fprintf(w, " %c %s", sym.Code, sym.Name) + if *printType && sym.Type != "" { + fmt.Fprintf(w, " %s", sym.Type) + } + fmt.Fprintf(w, "\n") + } + } + + if !found { + errorf("reading %s: no symbols", file) + } + + w.Flush() +} |