...
Source file src/pkg/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package binutils
16
17 import (
18 "bufio"
19 "bytes"
20 "io"
21 "os/exec"
22 "strconv"
23 "strings"
24
25 "github.com/google/pprof/internal/plugin"
26 )
27
28 const (
29 defaultNM = "nm"
30 )
31
32
33
34 type addr2LinerNM struct {
35 m []symbolInfo
36 }
37
38 type symbolInfo struct {
39 address uint64
40 name string
41 }
42
43
44
45
46
47 func newAddr2LinerNM(cmd, file string, base uint64) (*addr2LinerNM, error) {
48 if cmd == "" {
49 cmd = defaultNM
50 }
51 var b bytes.Buffer
52 c := exec.Command(cmd, "-n", file)
53 c.Stdout = &b
54 if err := c.Run(); err != nil {
55 return nil, err
56 }
57 return parseAddr2LinerNM(base, &b)
58 }
59
60 func parseAddr2LinerNM(base uint64, nm io.Reader) (*addr2LinerNM, error) {
61 a := &addr2LinerNM{
62 m: []symbolInfo{},
63 }
64
65
66
67 buf := bufio.NewReader(nm)
68 for {
69 line, err := buf.ReadString('\n')
70 if line == "" && err != nil {
71 if err == io.EOF {
72 break
73 }
74 return nil, err
75 }
76 line = strings.TrimSpace(line)
77 fields := strings.SplitN(line, " ", 3)
78 if len(fields) != 3 {
79 continue
80 }
81 address, err := strconv.ParseUint(fields[0], 16, 64)
82 if err != nil {
83 continue
84 }
85 a.m = append(a.m, symbolInfo{
86 address: address + base,
87 name: fields[2],
88 })
89 }
90
91 return a, nil
92 }
93
94
95
96 func (a *addr2LinerNM) addrInfo(addr uint64) ([]plugin.Frame, error) {
97 if len(a.m) == 0 || addr < a.m[0].address || addr > a.m[len(a.m)-1].address {
98 return nil, nil
99 }
100
101
102 low, high := 0, len(a.m)
103 for low+1 < high {
104 mid := (low + high) / 2
105 v := a.m[mid].address
106 if addr == v {
107 low = mid
108 break
109 } else if addr > v {
110 low = mid
111 } else {
112 high = mid
113 }
114 }
115
116
117
118 f := []plugin.Frame{
119 {
120 Func: a.m[low].name,
121 },
122 }
123 return f, nil
124 }
125
View as plain text