diff options
author | Russ Cox <rsc@golang.org> | 2014-08-07 12:33:06 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-08-07 12:33:06 -0400 |
commit | 08033f9816e1e33092c93c050dc34514d8e3e926 (patch) | |
tree | e7442db7fd5cbf52364c7617d437f30374e1117e /src/cmd/nm | |
parent | fad69a7b77a7996b0308bdbcd559b78b32046bb3 (diff) | |
download | go-08033f9816e1e33092c93c050dc34514d8e3e926.tar.gz go-08033f9816e1e33092c93c050dc34514d8e3e926.zip |
cmd/addr2line, cmd/nm: factor object reading into cmd/internal/objfile
To do in another CL: make cmd/objdump use cmd/internal/objfile too.
There is a package placement decision in this CL:
cmd/internal/objfile instead of internal/objfile.
I chose to put internal under cmd to make clear (and enforce)
that no standard library packages should use this
(it's a bit dependency-heavy).
LGTM=r
R=r
CC=golang-codereviews
https://golang.org/cl/123910043
Diffstat (limited to 'src/cmd/nm')
-rw-r--r-- | src/cmd/nm/elf.go | 57 | ||||
-rw-r--r-- | src/cmd/nm/goobj.go | 68 | ||||
-rw-r--r-- | src/cmd/nm/macho.go | 69 | ||||
-rw-r--r-- | src/cmd/nm/nm.go | 57 | ||||
-rw-r--r-- | src/cmd/nm/nm_test.go | 4 | ||||
-rw-r--r-- | src/cmd/nm/pe.go | 98 | ||||
-rw-r--r-- | src/cmd/nm/plan9obj.go | 48 |
7 files changed, 14 insertions, 387 deletions
diff --git a/src/cmd/nm/elf.go b/src/cmd/nm/elf.go deleted file mode 100644 index 5aaa194dd1..0000000000 --- a/src/cmd/nm/elf.go +++ /dev/null @@ -1,57 +0,0 @@ -// 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] - 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' - } - } - if elf.ST_BIND(s.Info) == elf.STB_LOCAL { - sym.Code += 'a' - 'A' - } - syms = append(syms, sym) - } - - return syms -} diff --git a/src/cmd/nm/goobj.go b/src/cmd/nm/goobj.go deleted file mode 100644 index b0de51db9c..0000000000 --- a/src/cmd/nm/goobj.go +++ /dev/null @@ -1,68 +0,0 @@ -// 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' // should not see - } - 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 -} diff --git a/src/cmd/nm/macho.go b/src/cmd/nm/macho.go deleted file mode 100644 index c60bde55b4..0000000000 --- a/src/cmd/nm/macho.go +++ /dev/null @@ -1,69 +0,0 @@ -// 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] } diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go index a4036184e4..3089e481be 100644 --- a/src/cmd/nm/nm.go +++ b/src/cmd/nm/nm.go @@ -6,13 +6,13 @@ package main import ( "bufio" - "bytes" "flag" "fmt" - "io" "log" "os" "sort" + + "cmd/internal/objfile" ) func usage() { @@ -85,55 +85,22 @@ func errorf(format string, args ...interface{}) { exitCode = 1 } -type Sym struct { - Addr uint64 - Size int64 - Code rune - Name string - Type string -} - -var parsers = []struct { - prefix []byte - parse func(*os.File) []Sym -}{ - {[]byte("!<arch>\n"), goobjSymbols}, - {[]byte("go object "), goobjSymbols}, - {[]byte("\x7FELF"), elfSymbols}, - {[]byte("\xFE\xED\xFA\xCE"), machoSymbols}, - {[]byte("\xFE\xED\xFA\xCF"), machoSymbols}, - {[]byte("\xCE\xFA\xED\xFE"), machoSymbols}, - {[]byte("\xCF\xFA\xED\xFE"), machoSymbols}, - {[]byte("MZ"), peSymbols}, - {[]byte("\x00\x00\x01\xEB"), plan9Symbols}, // 386 - {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips - {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm - {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64 -} - func nm(file string) { - f, err := os.Open(file) + f, err := objfile.Open(file) if err != nil { errorf("%v", err) return } defer f.Close() - buf := make([]byte, 16) - io.ReadFull(f, buf) - f.Seek(0, 0) - - var syms []Sym - for _, p := range parsers { - if bytes.HasPrefix(buf, p.prefix) { - syms = p.parse(f) - goto HaveSyms - } + syms, err := f.Symbols() + if err != nil { + errorf("reading %s: %v", file, err) + } + if len(syms) == 0 { + errorf("reading %s: no symbols", file) } - errorf("%v: unknown file format", file) - return -HaveSyms: switch *sortOrder { case "address": sort.Sort(byAddr(syms)) @@ -165,19 +132,19 @@ HaveSyms: w.Flush() } -type byAddr []Sym +type byAddr []objfile.Sym func (x byAddr) Len() int { return len(x) } func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } -type byName []Sym +type byName []objfile.Sym func (x byName) Len() int { return len(x) } func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x byName) Less(i, j int) bool { return x[i].Name < x[j].Name } -type bySize []Sym +type bySize []objfile.Sym func (x bySize) Len() int { return len(x) } func (x bySize) Swap(i, j int) { x[i], x[j] = x[j], x[i] } diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index 74773877f3..f447e8e491 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -77,7 +77,7 @@ func TestNM(t *testing.T) { "elf/testdata/gcc-amd64-linux-exec", "macho/testdata/gcc-386-darwin-exec", "macho/testdata/gcc-amd64-darwin-exec", - "pe/testdata/gcc-amd64-mingw-exec", + // "pe/testdata/gcc-amd64-mingw-exec", // no symbols! "pe/testdata/gcc-386-mingw-exec", "plan9obj/testdata/amd64-plan9-exec", "plan9obj/testdata/386-plan9-exec", @@ -87,7 +87,7 @@ func TestNM(t *testing.T) { cmd := exec.Command(testnmpath, exepath) out, err := cmd.CombinedOutput() if err != nil { - t.Fatalf("go tool nm %v: %v\n%s", exepath, err, string(out)) + t.Errorf("go tool nm %v: %v\n%s", exepath, err, string(out)) } } diff --git a/src/cmd/nm/pe.go b/src/cmd/nm/pe.go deleted file mode 100644 index 52d05e51d0..0000000000 --- a/src/cmd/nm/pe.go +++ /dev/null @@ -1,98 +0,0 @@ -// 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 PE executables (Microsoft Windows). - -package main - -import ( - "debug/pe" - "os" - "sort" -) - -func peSymbols(f *os.File) []Sym { - p, err := pe.NewFile(f) - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - 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 - - var imageBase uint64 - switch oh := p.OptionalHeader.(type) { - case *pe.OptionalHeader32: - imageBase = uint64(oh.ImageBase) - case *pe.OptionalHeader64: - imageBase = oh.ImageBase - default: - errorf("parsing %s: file format not recognized", f.Name()) - return nil - } - - var syms []Sym - for _, s := range p.Symbols { - const ( - N_UNDEF = 0 // An undefined (extern) symbol - N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) - N_DEBUG = -2 // A debugging symbol - ) - sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} - switch s.SectionNumber { - case N_UNDEF: - sym.Code = 'U' - case N_ABS: - sym.Code = 'C' - case N_DEBUG: - sym.Code = '?' - default: - if s.SectionNumber < 0 { - errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber) - return nil - } - if len(p.Sections) < int(s.SectionNumber) { - errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections)) - return nil - } - sect := p.Sections[s.SectionNumber-1] - const ( - text = 0x20 - data = 0x40 - bss = 0x80 - permX = 0x20000000 - permR = 0x40000000 - permW = 0x80000000 - ) - ch := sect.Characteristics - switch { - case ch&text != 0: - sym.Code = 'T' - case ch&data != 0: - if ch&permW == 0 { - sym.Code = 'R' - } else { - sym.Code = 'D' - } - case ch&bss != 0: - sym.Code = 'B' - } - sym.Addr += imageBase + uint64(sect.VirtualAddress) - } - syms = append(syms, sym) - addrs = append(addrs, sym.Addr) - } - - sort.Sort(uint64s(addrs)) - for i := range syms { - j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) - if j < len(addrs) { - syms[i].Size = int64(addrs[j] - syms[i].Addr) - } - } - - return syms -} diff --git a/src/cmd/nm/plan9obj.go b/src/cmd/nm/plan9obj.go deleted file mode 100644 index 006c66ebfd..0000000000 --- a/src/cmd/nm/plan9obj.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2014 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 Plan 9 a.out executables. - -package main - -import ( - "debug/plan9obj" - "os" - "sort" -) - -func plan9Symbols(f *os.File) []Sym { - p, err := plan9obj.NewFile(f) - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - return nil - } - - plan9Syms, err := p.Symbols() - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - 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 plan9Syms { - addrs = append(addrs, s.Value) - } - sort.Sort(uint64s(addrs)) - - var syms []Sym - - for _, s := range plan9Syms { - sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)} - 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) - } - syms = append(syms, sym) - } - - return syms -} |