...
Source file src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package binutils
16
17 import (
18 "bufio"
19 "fmt"
20 "io"
21 "os/exec"
22 "strconv"
23 "strings"
24 "sync"
25
26 "github.com/google/pprof/internal/plugin"
27 )
28
29 const (
30 defaultLLVMSymbolizer = "llvm-symbolizer"
31 )
32
33
34
35 type llvmSymbolizer struct {
36 sync.Mutex
37 filename string
38 rw lineReaderWriter
39 base uint64
40 }
41
42 type llvmSymbolizerJob struct {
43 cmd *exec.Cmd
44 in io.WriteCloser
45 out *bufio.Reader
46 }
47
48 func (a *llvmSymbolizerJob) write(s string) error {
49 _, err := fmt.Fprint(a.in, s+"\n")
50 return err
51 }
52
53 func (a *llvmSymbolizerJob) readLine() (string, error) {
54 return a.out.ReadString('\n')
55 }
56
57
58 func (a *llvmSymbolizerJob) close() {
59 a.in.Close()
60 a.cmd.Wait()
61 }
62
63
64
65
66
67 func newLLVMSymbolizer(cmd, file string, base uint64) (*llvmSymbolizer, error) {
68 if cmd == "" {
69 cmd = defaultLLVMSymbolizer
70 }
71
72 j := &llvmSymbolizerJob{
73 cmd: exec.Command(cmd, "-inlining", "-demangle=false"),
74 }
75
76 var err error
77 if j.in, err = j.cmd.StdinPipe(); err != nil {
78 return nil, err
79 }
80
81 outPipe, err := j.cmd.StdoutPipe()
82 if err != nil {
83 return nil, err
84 }
85
86 j.out = bufio.NewReader(outPipe)
87 if err := j.cmd.Start(); err != nil {
88 return nil, err
89 }
90
91 a := &llvmSymbolizer{
92 filename: file,
93 rw: j,
94 base: base,
95 }
96
97 return a, nil
98 }
99
100 func (d *llvmSymbolizer) readString() (string, error) {
101 s, err := d.rw.readLine()
102 if err != nil {
103 return "", err
104 }
105 return strings.TrimSpace(s), nil
106 }
107
108
109
110
111 func (d *llvmSymbolizer) readFrame() (plugin.Frame, bool) {
112 funcname, err := d.readString()
113 if err != nil {
114 return plugin.Frame{}, true
115 }
116
117 switch funcname {
118 case "":
119 return plugin.Frame{}, true
120 case "??":
121 funcname = ""
122 }
123
124 fileline, err := d.readString()
125 if err != nil {
126 return plugin.Frame{Func: funcname}, true
127 }
128
129 linenumber := 0
130 if fileline == "??:0" {
131 fileline = ""
132 } else {
133 switch split := strings.Split(fileline, ":"); len(split) {
134 case 1:
135
136 fileline = split[0]
137 case 2, 3:
138
139
140 fileline = split[0]
141 if line, err := strconv.Atoi(split[1]); err == nil {
142 linenumber = line
143 }
144 default:
145
146 }
147 }
148
149 return plugin.Frame{Func: funcname, File: fileline, Line: linenumber}, false
150 }
151
152
153
154 func (d *llvmSymbolizer) addrInfo(addr uint64) ([]plugin.Frame, error) {
155 d.Lock()
156 defer d.Unlock()
157
158 if err := d.rw.write(fmt.Sprintf("%s 0x%x", d.filename, addr-d.base)); err != nil {
159 return nil, err
160 }
161
162 var stack []plugin.Frame
163 for {
164 frame, end := d.readFrame()
165 if end {
166 break
167 }
168
169 if frame != (plugin.Frame{}) {
170 stack = append(stack, frame)
171 }
172 }
173
174 return stack, nil
175 }
176
View as plain text