Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The immediate goal is to support the new object file format, which libmach (nm's support library) does not understand. Rather than add code to libmach or reengineer liblink to support this new use, just write it in Go. The C version of nm reads the Plan 9 symbol table stored in Go binaries, now otherwise unused. This reimplementation uses the standard symbol table for the corresponding file format instead, bringing us one step closer to removing the Plan 9 symbol table from Go binaries. Tell cmd/dist not to build cmd/nm anymore. Tell cmd/go to install cmd/nm in the tool directory. R=golang-dev, r, iant, alex.brainman CC=golang-dev https://golang.org/cl/40600043
- Loading branch information
Showing
10 changed files
with
456 additions
and
428 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,37 @@ | ||
// Copyright 2009 The Go Authors. All rights reserved. | ||
// 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. | ||
|
||
// +build ignore | ||
|
||
/* | ||
Nm is a version of the Plan 9 nm command. The original is documented at | ||
http://plan9.bell-labs.com/magic/man2html/1/nm | ||
It prints the name list (symbol table) for programs compiled by gc as well as the | ||
Plan 9 C compiler. | ||
This implementation adds the flag -S, which prints each symbol's size | ||
in decimal after its address. | ||
Usage: | ||
go tool nm [-aghnsSTu] file | ||
*/ | ||
// Nm lists the symbols defined or used by an object file, archive, or executable. | ||
// | ||
// Usage: | ||
// go tool nm [options] file... | ||
// | ||
// The default output prints one line per symbol, with three space-separated | ||
// fields giving the address (in hexadecimal), type (a character), and name of | ||
// the symbol. The types are: | ||
// | ||
// T text (code) segment symbol | ||
// t static text segment symbol | ||
// D data segment symbol | ||
// d static data segment symbol | ||
// B bss segment symbol | ||
// b static bss segment symbol | ||
// U referenced but undefined symbol | ||
// | ||
// Following established convention, the address is omitted for undefined | ||
// symbols (type U). | ||
// | ||
// The options control the printed output: | ||
// | ||
// -n | ||
// an alias for -sort address (numeric), | ||
// for compatiblity with other nm commands | ||
// -size | ||
// print symbol size in decimal between address and type | ||
// -sort {address,name,none} | ||
// sort output in the given order (default name) | ||
// -type | ||
// print symbol type after name | ||
// | ||
package main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// 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. | ||
|
||
// Parsing of ELF executables (Linux, FreeBSD, and so on). | ||
|
||
package main | ||
|
||
import ( | ||
"debug/elf" | ||
"os" | ||
) | ||
|
||
func elfSymbols(f *os.File) []Sym { | ||
p, err := elf.NewFile(f) | ||
if err != nil { | ||
errorf("parsing %s: %v", f.Name(), err) | ||
return nil | ||
} | ||
|
||
elfSyms, err := p.Symbols() | ||
if err != nil { | ||
errorf("parsing %s: %v", f.Name(), err) | ||
return nil | ||
} | ||
|
||
var syms []Sym | ||
for _, s := range elfSyms { | ||
sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} | ||
switch s.Section { | ||
case elf.SHN_UNDEF: | ||
sym.Code = 'U' | ||
case elf.SHN_COMMON: | ||
sym.Code = 'B' | ||
default: | ||
i := int(s.Section) | ||
if i <= 0 || i > len(p.Sections) { | ||
break | ||
} | ||
sect := p.Sections[i-1] | ||
switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { | ||
case elf.SHF_ALLOC | elf.SHF_EXECINSTR: | ||
sym.Code = 'T' | ||
case elf.SHF_ALLOC: | ||
sym.Code = 'R' | ||
case elf.SHF_ALLOC | elf.SHF_WRITE: | ||
sym.Code = 'D' | ||
} | ||
} | ||
syms = append(syms, sym) | ||
} | ||
|
||
return syms | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// 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. | ||
|
||
// Parsing of Go intermediate object files and archives. | ||
|
||
package main | ||
|
||
import ( | ||
"debug/goobj" | ||
"fmt" | ||
"os" | ||
) | ||
|
||
func goobjName(id goobj.SymID) string { | ||
if id.Version == 0 { | ||
return id.Name | ||
} | ||
return fmt.Sprintf("%s<%d>", id.Name, id.Version) | ||
} | ||
|
||
func goobjSymbols(f *os.File) []Sym { | ||
pkg, err := goobj.Parse(f, `""`) | ||
if err != nil { | ||
errorf("parsing %s: %v", f.Name(), err) | ||
return nil | ||
} | ||
|
||
seen := make(map[goobj.SymID]bool) | ||
|
||
var syms []Sym | ||
for _, s := range pkg.Syms { | ||
seen[s.SymID] = true | ||
sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.SymID), Size: int64(s.Size), Type: s.Type.Name, Code: '?'} | ||
switch s.Kind { | ||
case goobj.STEXT, goobj.SELFRXSECT: | ||
sym.Code = 'T' | ||
case goobj.STYPE, goobj.SSTRING, goobj.SGOSTRING, goobj.SGOFUNC, goobj.SRODATA, goobj.SFUNCTAB, goobj.STYPELINK, goobj.SSYMTAB, goobj.SPCLNTAB, goobj.SELFROSECT: | ||
sym.Code = 'R' | ||
case goobj.SMACHOPLT, goobj.SELFSECT, goobj.SMACHO, goobj.SMACHOGOT, goobj.SNOPTRDATA, goobj.SINITARR, goobj.SDATA, goobj.SWINDOWS: | ||
sym.Code = 'D' | ||
case goobj.SBSS, goobj.SNOPTRBSS, goobj.STLSBSS: | ||
sym.Code = 'B' | ||
case goobj.SXREF, goobj.SMACHOSYMSTR, goobj.SMACHOSYMTAB, goobj.SMACHOINDIRECTPLT, goobj.SMACHOINDIRECTGOT, goobj.SFILE, goobj.SFILEPATH, goobj.SCONST, goobj.SDYNIMPORT, goobj.SHOSTOBJ: | ||
sym.Code = 'X' | ||
} | ||
if s.Version != 0 { | ||
sym.Code += 'a' - 'A' | ||
} | ||
syms = append(syms, sym) | ||
} | ||
|
||
for _, s := range pkg.Syms { | ||
for _, r := range s.Reloc { | ||
if !seen[r.Sym] { | ||
seen[r.Sym] = true | ||
sym := Sym{Name: goobjName(r.Sym), Code: 'U'} | ||
if s.Version != 0 { | ||
// should not happen but handle anyway | ||
sym.Code = 'u' | ||
} | ||
syms = append(syms, sym) | ||
} | ||
} | ||
} | ||
|
||
return syms | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// 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. | ||
|
||
// Parsing of Mach-O executables (OS X). | ||
|
||
package main | ||
|
||
import ( | ||
"debug/macho" | ||
"os" | ||
"sort" | ||
) | ||
|
||
func machoSymbols(f *os.File) []Sym { | ||
p, err := macho.NewFile(f) | ||
if err != nil { | ||
errorf("parsing %s: %v", f.Name(), err) | ||
return nil | ||
} | ||
|
||
if p.Symtab == nil { | ||
errorf("%s: no symbol table", f.Name()) | ||
return nil | ||
} | ||
|
||
// Build sorted list of addresses of all symbols. | ||
// We infer the size of a symbol by looking at where the next symbol begins. | ||
var addrs []uint64 | ||
for _, s := range p.Symtab.Syms { | ||
addrs = append(addrs, s.Value) | ||
} | ||
sort.Sort(uint64s(addrs)) | ||
|
||
var syms []Sym | ||
for _, s := range p.Symtab.Syms { | ||
sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} | ||
i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) | ||
if i < len(addrs) { | ||
sym.Size = int64(addrs[i] - s.Value) | ||
} | ||
if s.Sect == 0 { | ||
sym.Code = 'U' | ||
} else if int(s.Sect) <= len(p.Sections) { | ||
sect := p.Sections[s.Sect-1] | ||
switch sect.Seg { | ||
case "__TEXT": | ||
sym.Code = 'R' | ||
case "__DATA": | ||
sym.Code = 'D' | ||
} | ||
switch sect.Seg + " " + sect.Name { | ||
case "__TEXT __text": | ||
sym.Code = 'T' | ||
case "__DATA __bss", "__DATA __noptrbss": | ||
sym.Code = 'B' | ||
} | ||
} | ||
syms = append(syms, sym) | ||
} | ||
|
||
return syms | ||
} | ||
|
||
type uint64s []uint64 | ||
|
||
func (x uint64s) Len() int { return len(x) } | ||
func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | ||
func (x uint64s) Less(i, j int) bool { return x[i] < x[j] } |
Oops, something went wrong.