Source file src/pkg/debug/gosym/pclntab.go
1
2
3
4
5
8
9 package gosym
10
11 import (
12 "bytes"
13 "encoding/binary"
14 "sync"
15 )
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 type LineTable struct {
31 Data []byte
32 PC uint64
33 Line int
34
35
36 mu sync.Mutex
37 go12 int
38 binary binary.ByteOrder
39 quantum uint32
40 ptrsize uint32
41 functab []byte
42 nfunctab uint32
43 filetab []byte
44 nfiletab uint32
45 fileMap map[string]uint32
46 strings map[uint32]string
47 }
48
49
50
51
52
53 const oldQuantum = 1
54
55 func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
56
57
58
59
60
61
62
63
64 b, pc, line = t.Data, t.PC, t.Line
65 for pc <= targetPC && line != targetLine && len(b) > 0 {
66 code := b[0]
67 b = b[1:]
68 switch {
69 case code == 0:
70 if len(b) < 4 {
71 b = b[0:0]
72 break
73 }
74 val := binary.BigEndian.Uint32(b)
75 b = b[4:]
76 line += int(val)
77 case code <= 64:
78 line += int(code)
79 case code <= 128:
80 line -= int(code - 64)
81 default:
82 pc += oldQuantum * uint64(code-128)
83 continue
84 }
85 pc += oldQuantum
86 }
87 return b, pc, line
88 }
89
90 func (t *LineTable) slice(pc uint64) *LineTable {
91 data, pc, line := t.parse(pc, -1)
92 return &LineTable{Data: data, PC: pc, Line: line}
93 }
94
95
96
97
98 func (t *LineTable) PCToLine(pc uint64) int {
99 if t.isGo12() {
100 return t.go12PCToLine(pc)
101 }
102 _, _, line := t.parse(pc, -1)
103 return line
104 }
105
106
107
108
109
110 func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 {
111 if t.isGo12() {
112 return 0
113 }
114 _, pc, line1 := t.parse(maxpc, line)
115 if line1 != line {
116 return 0
117 }
118
119 return pc - oldQuantum
120 }
121
122
123
124
125
126 func NewLineTable(data []byte, text uint64) *LineTable {
127 return &LineTable{Data: data, PC: text, Line: 0, strings: make(map[uint32]string)}
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142 func (t *LineTable) isGo12() bool {
143 t.go12Init()
144 return t.go12 == 1
145 }
146
147 const go12magic = 0xfffffffb
148
149
150
151 func (t *LineTable) uintptr(b []byte) uint64 {
152 if t.ptrsize == 4 {
153 return uint64(t.binary.Uint32(b))
154 }
155 return t.binary.Uint64(b)
156 }
157
158
159 func (t *LineTable) go12Init() {
160 t.mu.Lock()
161 defer t.mu.Unlock()
162 if t.go12 != 0 {
163 return
164 }
165
166 defer func() {
167
168 recover()
169 }()
170
171
172 t.go12 = -1
173 if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 ||
174 (t.Data[6] != 1 && t.Data[6] != 2 && t.Data[6] != 4) ||
175 (t.Data[7] != 4 && t.Data[7] != 8) {
176 return
177 }
178
179 switch uint32(go12magic) {
180 case binary.LittleEndian.Uint32(t.Data):
181 t.binary = binary.LittleEndian
182 case binary.BigEndian.Uint32(t.Data):
183 t.binary = binary.BigEndian
184 default:
185 return
186 }
187
188 t.quantum = uint32(t.Data[6])
189 t.ptrsize = uint32(t.Data[7])
190
191 t.nfunctab = uint32(t.uintptr(t.Data[8:]))
192 t.functab = t.Data[8+t.ptrsize:]
193 functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize
194 fileoff := t.binary.Uint32(t.functab[functabsize:])
195 t.functab = t.functab[:functabsize]
196 t.filetab = t.Data[fileoff:]
197 t.nfiletab = t.binary.Uint32(t.filetab)
198 t.filetab = t.filetab[:t.nfiletab*4]
199
200 t.go12 = 1
201 }
202
203
204 func (t *LineTable) go12Funcs() []Func {
205
206 defer func() {
207 recover()
208 }()
209
210 n := len(t.functab) / int(t.ptrsize) / 2
211 funcs := make([]Func, n)
212 for i := range funcs {
213 f := &funcs[i]
214 f.Entry = t.uintptr(t.functab[2*i*int(t.ptrsize):])
215 f.End = t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):])
216 info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
217 f.LineTable = t
218 f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
219 f.Sym = &Sym{
220 Value: f.Entry,
221 Type: 'T',
222 Name: t.string(t.binary.Uint32(info[t.ptrsize:])),
223 GoType: 0,
224 Func: f,
225 }
226 }
227 return funcs
228 }
229
230
231 func (t *LineTable) findFunc(pc uint64) []byte {
232 if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
233 return nil
234 }
235
236
237
238 f := t.functab
239 nf := t.nfunctab
240 for nf > 0 {
241 m := nf / 2
242 fm := f[2*t.ptrsize*m:]
243 if t.uintptr(fm) <= pc && pc < t.uintptr(fm[2*t.ptrsize:]) {
244 return t.Data[t.uintptr(fm[t.ptrsize:]):]
245 } else if pc < t.uintptr(fm) {
246 nf = m
247 } else {
248 f = f[(m+1)*2*t.ptrsize:]
249 nf -= m + 1
250 }
251 }
252 return nil
253 }
254
255
256 func (t *LineTable) readvarint(pp *[]byte) uint32 {
257 var v, shift uint32
258 p := *pp
259 for shift = 0; ; shift += 7 {
260 b := p[0]
261 p = p[1:]
262 v |= (uint32(b) & 0x7F) << shift
263 if b&0x80 == 0 {
264 break
265 }
266 }
267 *pp = p
268 return v
269 }
270
271
272 func (t *LineTable) string(off uint32) string {
273 if s, ok := t.strings[off]; ok {
274 return s
275 }
276 i := bytes.IndexByte(t.Data[off:], 0)
277 s := string(t.Data[off : off+uint32(i)])
278 t.strings[off] = s
279 return s
280 }
281
282
283 func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
284 uvdelta := t.readvarint(p)
285 if uvdelta == 0 && !first {
286 return false
287 }
288 if uvdelta&1 != 0 {
289 uvdelta = ^(uvdelta >> 1)
290 } else {
291 uvdelta >>= 1
292 }
293 vdelta := int32(uvdelta)
294 pcdelta := t.readvarint(p) * t.quantum
295 *pc += uint64(pcdelta)
296 *val += vdelta
297 return true
298 }
299
300
301
302
303 func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
304 p := t.Data[off:]
305
306 val := int32(-1)
307 pc := entry
308 for t.step(&p, &pc, &val, pc == entry) {
309 if targetpc < pc {
310 return val
311 }
312 }
313 return -1
314 }
315
316
317
318
319
320
321
322 func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32) uint64 {
323 if filetab == 0 || linetab == 0 {
324 return 0
325 }
326
327 fp := t.Data[filetab:]
328 fl := t.Data[linetab:]
329 fileVal := int32(-1)
330 filePC := entry
331 lineVal := int32(-1)
332 linePC := entry
333 fileStartPC := filePC
334 for t.step(&fp, &filePC, &fileVal, filePC == entry) {
335 if fileVal == filenum && fileStartPC < filePC {
336
337
338
339
340 lineStartPC := linePC
341 for linePC < filePC && t.step(&fl, &linePC, &lineVal, linePC == entry) {
342
343 if lineVal == line {
344 if fileStartPC <= lineStartPC {
345 return lineStartPC
346 }
347 if fileStartPC < linePC {
348 return fileStartPC
349 }
350 }
351 lineStartPC = linePC
352 }
353 }
354 fileStartPC = filePC
355 }
356 return 0
357 }
358
359
360 func (t *LineTable) go12PCToLine(pc uint64) (line int) {
361 defer func() {
362 if recover() != nil {
363 line = -1
364 }
365 }()
366
367 f := t.findFunc(pc)
368 if f == nil {
369 return -1
370 }
371 entry := t.uintptr(f)
372 linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
373 return int(t.pcvalue(linetab, entry, pc))
374 }
375
376
377 func (t *LineTable) go12PCToFile(pc uint64) (file string) {
378 defer func() {
379 if recover() != nil {
380 file = ""
381 }
382 }()
383
384 f := t.findFunc(pc)
385 if f == nil {
386 return ""
387 }
388 entry := t.uintptr(f)
389 filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
390 fno := t.pcvalue(filetab, entry, pc)
391 if fno <= 0 {
392 return ""
393 }
394 return t.string(t.binary.Uint32(t.filetab[4*fno:]))
395 }
396
397
398 func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
399 defer func() {
400 if recover() != nil {
401 pc = 0
402 }
403 }()
404
405 t.initFileMap()
406 filenum := t.fileMap[file]
407 if filenum == 0 {
408 return 0
409 }
410
411
412
413
414 for i := uint32(0); i < t.nfunctab; i++ {
415 f := t.Data[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
416 entry := t.uintptr(f)
417 filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
418 linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
419 pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line))
420 if pc != 0 {
421 return pc
422 }
423 }
424 return 0
425 }
426
427
428 func (t *LineTable) initFileMap() {
429 t.mu.Lock()
430 defer t.mu.Unlock()
431
432 if t.fileMap != nil {
433 return
434 }
435 m := make(map[string]uint32)
436
437 for i := uint32(1); i < t.nfiletab; i++ {
438 s := t.string(t.binary.Uint32(t.filetab[4*i:]))
439 m[s] = i
440 }
441 t.fileMap = m
442 }
443
444
445
446
447 func (t *LineTable) go12MapFiles(m map[string]*Obj, obj *Obj) {
448 defer func() {
449 recover()
450 }()
451
452 t.initFileMap()
453 for file := range t.fileMap {
454 m[file] = obj
455 }
456 }
457
View as plain text