Skip to content

Commit

Permalink
pkg/symbolizer: favor portable nm(1) format
Browse files Browse the repository at this point in the history
On OpenBSD, nm(1) does not support the `-S' option.

The order of symbols from nm(1) varies between platforms, therefore rework the
test case to cope with that.

Fixes google#723
  • Loading branch information
mptre authored and dvyukov committed Sep 24, 2018
1 parent 28d9ac7 commit e029c3e
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 24 deletions.
27 changes: 17 additions & 10 deletions pkg/symbolizer/nm.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Symbol struct {

// ReadSymbols returns list of text symbols in the binary bin.
func ReadSymbols(bin string) (map[string][]Symbol, error) {
cmd := osutil.Command("nm", "-nS", bin)
cmd := osutil.Command("nm", "-Ptx", bin)
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
Expand All @@ -32,32 +32,39 @@ func ReadSymbols(bin string) (map[string][]Symbol, error) {
s := bufio.NewScanner(stdout)
text := [][]byte{[]byte(" t "), []byte(" T ")}
for s.Scan() {
// A line looks as: "ffffffff8104db90 0000000000000059 t snb_uncore_msr_enable_box"
// A line looks as: "snb_uncore_msr_enable_box t ffffffff8104db90 0000000000000059"
ln := s.Bytes()
if !bytes.Contains(ln, text[0]) && !bytes.Contains(ln, text[1]) {
continue
}

sp1 := bytes.IndexByte(ln, ' ')
if sp1 == -1 {
continue
}
sp2 := bytes.IndexByte(ln[sp1+1:], ' ')
if sp2 == -1 {
if !bytes.HasPrefix(ln[sp1:], text[0]) && !bytes.HasPrefix(ln[sp1:], text[1]) {
continue
}
sp2 += sp1 + 1
if !bytes.HasPrefix(ln[sp2:], text[0]) && !bytes.HasPrefix(ln[sp2:], text[1]) {

sp2 := sp1 + len(text[0])
sp3 := bytes.IndexByte(ln[sp2:], ' ')
if sp3 == -1 {
continue
}
addr, err := strconv.ParseUint(string(ln[:sp1]), 16, 64)
sp3 += sp2

addr, err := strconv.ParseUint(string(ln[sp2:sp3]), 16, 64)
if err != nil {
continue
}
size, err := strconv.ParseUint(string(ln[sp1+1:sp2]), 16, 64)
if err != nil {

size, err := strconv.ParseUint(string(ln[sp3+1:]), 16, 64)
if err != nil || size == 0 {
continue
}
name := string(ln[sp2+len(text[0]):])

name := string(ln[:sp1])

// Note: sizes reported by kernel do not match nm.
// Kernel probably subtracts address of this symbol from address of the next symbol.
// We could do the same, but for now we just round up size to 16.
Expand Down
37 changes: 23 additions & 14 deletions pkg/symbolizer/nm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@
package symbolizer

import (
"runtime"
"testing"
)

func TestSymbols(t *testing.T) {
if runtime.GOOS != "linux" {
// On openbsd it fails because nm does not have -S flag.
t.Skipf("broken on %v", runtime.GOOS)
}
symbols, err := ReadSymbols("testdata/nm.test.out")
if err != nil {
t.Fatalf("failed to read symbols: %v", err)
Expand All @@ -37,17 +32,31 @@ func TestSymbols(t *testing.T) {
if len(s) != 2 {
t.Fatalf("got %v foobar symbols, want 2", len(s))
}
if s[0].Addr != 0x4004ed {
t.Fatalf("bad foobar[0] address: 0x%x", s[0].Addr)
}
if s[0].Size != 0x10 {
t.Fatalf("bad foobar[0] size: 0x%x", s[0].Size)
want := []Symbol{
{
Addr: 0x4004fa,
Size: 0x10,
},
{
Addr: 0x4004ed,
Size: 0x10,
},
}
if s[1].Addr != 0x4004fa {
t.Fatalf("bad foobar[1] address: 0x%x", s[1].Addr)
if !symcmp(want[0], s[0]) && !symcmp(want[0], s[1]) {
t.Fatalf("foobar symbol %+v not found", want[0])
}
if s[1].Size != 0x10 {
t.Fatalf("bad foobar[1] size: 0x%x", s[1].Size)
if !symcmp(want[1], s[0]) && !symcmp(want[1], s[1]) {
t.Fatalf("foobar symbol %+v not found", want[1])
}
}
}

func symcmp(want Symbol, got Symbol) bool {
if want.Addr != got.Addr {
return false
}
if want.Size != got.Size {
return false
}
return true
}

0 comments on commit e029c3e

Please sign in to comment.