Source file
src/runtime/symtab.go
Documentation: runtime
1
2
3
4
5 package runtime
6
7 import (
8 "runtime/internal/atomic"
9 "runtime/internal/sys"
10 "unsafe"
11 )
12
13
14
15 type Frames struct {
16
17 callers []uintptr
18
19
20
21 stackExpander stackExpander
22
23
24
25
26 elideWrapper bool
27 }
28
29
30 type Frame struct {
31
32
33
34
35
36 PC uintptr
37
38
39
40 Func *Func
41
42
43
44
45
46
47 Function string
48
49
50
51
52
53 File string
54 Line int
55
56
57
58
59 Entry uintptr
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73 type stackExpander struct {
74
75 pcExpander pcExpander
76
77
78
79
80 wasPanic bool
81
82
83
84
85 skip int
86 }
87
88
89
90
91 func CallersFrames(callers []uintptr) *Frames {
92 ci := &Frames{}
93 ci.callers = ci.stackExpander.init(callers)
94 return ci
95 }
96
97 func (se *stackExpander) init(callers []uintptr) []uintptr {
98 if len(callers) >= 1 {
99 pc := callers[0]
100 s := pc - skipPC
101 if s >= 0 && s < sizeofSkipFunction {
102
103 return callers[1:]
104 }
105 }
106 if len(callers) >= 2 {
107 pc := callers[1]
108 s := pc - skipPC
109 if s > 0 && s < sizeofSkipFunction {
110
111 se.skip = int(s)
112 }
113 }
114 return callers
115 }
116
117
118
119 func (ci *Frames) Next() (frame Frame, more bool) {
120 ci.callers, frame, more = ci.stackExpander.next(ci.callers, ci.elideWrapper)
121 ci.elideWrapper = elideWrapperCalling(frame.Function)
122 return
123 }
124
125 func (se *stackExpander) next(callers []uintptr, elideWrapper bool) (ncallers []uintptr, frame Frame, more bool) {
126 ncallers = callers
127 again:
128 if !se.pcExpander.more {
129
130 if len(ncallers) == 0 {
131 se.wasPanic = false
132 return ncallers, Frame{}, false
133 }
134 se.pcExpander.init(ncallers[0], se.wasPanic)
135 ncallers = ncallers[1:]
136 se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.entry == sigpanicPC
137 if se.skip > 0 {
138 for ; se.skip > 0; se.skip-- {
139 se.pcExpander.next()
140 }
141 se.skip = 0
142
143 ncallers = ncallers[1:]
144 }
145 if !se.pcExpander.more {
146
147
148
149 return ncallers, Frame{}, len(ncallers) > 0
150 }
151 }
152
153 frame = se.pcExpander.next()
154 if elideWrapper && frame.File == "<autogenerated>" {
155
156
157
158
159 goto again
160 }
161 return ncallers, frame, se.pcExpander.more || len(ncallers) > 0
162 }
163
164
165 type pcExpander struct {
166
167
168 more bool
169
170
171 pc uintptr
172
173
174
175
176 frames []Frame
177
178
179 funcInfo funcInfo
180
181
182 inlTree *[1 << 20]inlinedCall
183
184
185
186 file string
187 line int32
188
189
190
191 inlIndex int32
192 }
193
194
195
196
197
198
199
200
201
202 func (ex *pcExpander) init(pc uintptr, panicCall bool) {
203 ex.more = false
204
205 ex.funcInfo = findfunc(pc)
206 if !ex.funcInfo.valid() {
207 if cgoSymbolizer != nil {
208
209
210
211 ex.frames = expandCgoFrames(pc)
212 ex.more = len(ex.frames) > 0
213 }
214 return
215 }
216
217 ex.more = true
218 entry := ex.funcInfo.entry
219 ex.pc = pc
220 if ex.pc > entry && !panicCall {
221 ex.pc--
222 }
223
224
225 ex.file, ex.line = funcline1(ex.funcInfo, ex.pc, false)
226
227
228 inldata := funcdata(ex.funcInfo, _FUNCDATA_InlTree)
229 if inldata != nil {
230 ex.inlTree = (*[1 << 20]inlinedCall)(inldata)
231 ex.inlIndex = pcdatavalue(ex.funcInfo, _PCDATA_InlTreeIndex, ex.pc, nil)
232 } else {
233 ex.inlTree = nil
234 ex.inlIndex = -1
235 }
236 }
237
238
239
240 func (ex *pcExpander) next() Frame {
241 if !ex.more {
242 return Frame{}
243 }
244
245 if len(ex.frames) > 0 {
246
247 frame := ex.frames[0]
248 ex.frames = ex.frames[1:]
249 ex.more = len(ex.frames) > 0
250 return frame
251 }
252
253 if ex.inlIndex >= 0 {
254
255 call := ex.inlTree[ex.inlIndex]
256 frame := Frame{
257 PC: ex.pc,
258 Func: nil,
259 Function: funcnameFromNameoff(ex.funcInfo, call.func_),
260 File: ex.file,
261 Line: int(ex.line),
262 Entry: ex.funcInfo.entry,
263 }
264 ex.file = funcfile(ex.funcInfo, call.file)
265 ex.line = call.line
266 ex.inlIndex = call.parent
267 return frame
268 }
269
270
271 ex.more = false
272 return Frame{
273 PC: ex.pc,
274 Func: ex.funcInfo._Func(),
275 Function: funcname(ex.funcInfo),
276 File: ex.file,
277 Line: int(ex.line),
278 Entry: ex.funcInfo.entry,
279 }
280 }
281
282
283
284
285 func expandCgoFrames(pc uintptr) []Frame {
286 arg := cgoSymbolizerArg{pc: pc}
287 callCgoSymbolizer(&arg)
288
289 if arg.file == nil && arg.funcName == nil {
290
291 return nil
292 }
293
294 var frames []Frame
295 for {
296 frames = append(frames, Frame{
297 PC: pc,
298 Func: nil,
299 Function: gostring(arg.funcName),
300 File: gostring(arg.file),
301 Line: int(arg.lineno),
302 Entry: arg.entry,
303 })
304 if arg.more == 0 {
305 break
306 }
307 callCgoSymbolizer(&arg)
308 }
309
310
311
312
313
314 arg.pc = 0
315 callCgoSymbolizer(&arg)
316
317 return frames
318 }
319
320
321
322
323
324
325
326
327 type Func struct {
328 opaque struct{}
329 }
330
331 func (f *Func) raw() *_func {
332 return (*_func)(unsafe.Pointer(f))
333 }
334
335 func (f *Func) funcInfo() funcInfo {
336 fn := f.raw()
337 return funcInfo{fn, findmoduledatap(fn.entry)}
338 }
339
340
341
342
343 const (
344 _PCDATA_StackMapIndex = 0
345 _PCDATA_InlTreeIndex = 1
346 _FUNCDATA_ArgsPointerMaps = 0
347 _FUNCDATA_LocalsPointerMaps = 1
348 _FUNCDATA_InlTree = 2
349 _ArgsSizeUnknown = -0x80000000
350 )
351
352
353
354
355
356
357 type moduledata struct {
358 pclntable []byte
359 ftab []functab
360 filetab []uint32
361 findfunctab uintptr
362 minpc, maxpc uintptr
363
364 text, etext uintptr
365 noptrdata, enoptrdata uintptr
366 data, edata uintptr
367 bss, ebss uintptr
368 noptrbss, enoptrbss uintptr
369 end, gcdata, gcbss uintptr
370 types, etypes uintptr
371
372 textsectmap []textsect
373 typelinks []int32
374 itablinks []*itab
375
376 ptab []ptabEntry
377
378 pluginpath string
379 pkghashes []modulehash
380
381 modulename string
382 modulehashes []modulehash
383
384 hasmain uint8
385
386 gcdatamask, gcbssmask bitvector
387
388 typemap map[typeOff]*_type
389
390 bad bool
391
392 next *moduledata
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407 type modulehash struct {
408 modulename string
409 linktimehash string
410 runtimehash *string
411 }
412
413
414
415
416
417
418
419
420 var pinnedTypemaps []map[typeOff]*_type
421
422 var firstmoduledata moduledata
423 var lastmoduledatap *moduledata
424 var modulesSlice *[]*moduledata
425
426
427
428
429
430
431
432
433
434
435 func activeModules() []*moduledata {
436 p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
437 if p == nil {
438 return nil
439 }
440 return *p
441 }
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461 func modulesinit() {
462 modules := new([]*moduledata)
463 for md := &firstmoduledata; md != nil; md = md.next {
464 if md.bad {
465 continue
466 }
467 *modules = append(*modules, md)
468 if md.gcdatamask == (bitvector{}) {
469 md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), md.edata-md.data)
470 md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), md.ebss-md.bss)
471 }
472 }
473
474
475
476
477
478
479
480
481
482
483 for i, md := range *modules {
484 if md.hasmain != 0 {
485 (*modules)[0] = md
486 (*modules)[i] = &firstmoduledata
487 break
488 }
489 }
490
491 atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
492 }
493
494 type functab struct {
495 entry uintptr
496 funcoff uintptr
497 }
498
499
500
501 type textsect struct {
502 vaddr uintptr
503 length uintptr
504 baseaddr uintptr
505 }
506
507 const minfunc = 16
508 const pcbucketsize = 256 * minfunc
509
510
511
512
513
514
515
516
517
518 type findfuncbucket struct {
519 idx uint32
520 subbuckets [16]byte
521 }
522
523 func moduledataverify() {
524 for datap := &firstmoduledata; datap != nil; datap = datap.next {
525 moduledataverify1(datap)
526 }
527 }
528
529 const debugPcln = false
530
531 func moduledataverify1(datap *moduledata) {
532
533
534
535 pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
536 pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
537 if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != sys.PCQuantum || pcln[7] != sys.PtrSize {
538 println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
539 throw("invalid function symbol table\n")
540 }
541
542
543 nftab := len(datap.ftab) - 1
544 for i := 0; i < nftab; i++ {
545
546 if datap.ftab[i].entry > datap.ftab[i+1].entry {
547 f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
548 f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
549 f2name := "end"
550 if i+1 < nftab {
551 f2name = funcname(f2)
552 }
553 println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
554 for j := 0; j <= i; j++ {
555 print("\t", hex(datap.ftab[j].entry), " ", funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}), "\n")
556 }
557 throw("invalid runtime symbol table")
558 }
559 }
560
561 if datap.minpc != datap.ftab[0].entry ||
562 datap.maxpc != datap.ftab[nftab].entry {
563 throw("minpc or maxpc invalid")
564 }
565
566 for _, modulehash := range datap.modulehashes {
567 if modulehash.linktimehash != *modulehash.runtimehash {
568 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
569 throw("abi mismatch")
570 }
571 }
572 }
573
574
575
576
577
578
579 func FuncForPC(pc uintptr) *Func {
580 return findfunc(pc)._Func()
581 }
582
583
584 func (f *Func) Name() string {
585 if f == nil {
586 return ""
587 }
588 return funcname(f.funcInfo())
589 }
590
591
592 func (f *Func) Entry() uintptr {
593 return f.raw().entry
594 }
595
596
597
598
599
600 func (f *Func) FileLine(pc uintptr) (file string, line int) {
601
602
603 file, line32 := funcline1(f.funcInfo(), pc, false)
604 return file, int(line32)
605 }
606
607 func findmoduledatap(pc uintptr) *moduledata {
608 for datap := &firstmoduledata; datap != nil; datap = datap.next {
609 if datap.minpc <= pc && pc < datap.maxpc {
610 return datap
611 }
612 }
613 return nil
614 }
615
616 type funcInfo struct {
617 *_func
618 datap *moduledata
619 }
620
621 func (f funcInfo) valid() bool {
622 return f._func != nil
623 }
624
625 func (f funcInfo) _Func() *Func {
626 return (*Func)(unsafe.Pointer(f._func))
627 }
628
629 func findfunc(pc uintptr) funcInfo {
630 datap := findmoduledatap(pc)
631 if datap == nil {
632 return funcInfo{}
633 }
634 const nsub = uintptr(len(findfuncbucket{}.subbuckets))
635
636 x := pc - datap.minpc
637 b := x / pcbucketsize
638 i := x % pcbucketsize / (pcbucketsize / nsub)
639
640 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
641 idx := ffb.idx + uint32(ffb.subbuckets[i])
642
643
644
645
646
647 if idx >= uint32(len(datap.ftab)) {
648 idx = uint32(len(datap.ftab) - 1)
649 }
650 if pc < datap.ftab[idx].entry {
651
652
653
654
655 for datap.ftab[idx].entry > pc && idx > 0 {
656 idx--
657 }
658 if idx == 0 {
659 throw("findfunc: bad findfunctab entry idx")
660 }
661 } else {
662
663
664 for datap.ftab[idx+1].entry <= pc {
665 idx++
666 }
667 }
668 return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])), datap}
669 }
670
671 type pcvalueCache struct {
672 entries [16]pcvalueCacheEnt
673 }
674
675 type pcvalueCacheEnt struct {
676
677 targetpc uintptr
678 off int32
679
680 val int32
681 }
682
683 func pcvalue(f funcInfo, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
684 if off == 0 {
685 return -1
686 }
687
688
689
690
691
692
693
694 if cache != nil {
695 for i := range cache.entries {
696
697
698
699
700
701 ent := &cache.entries[i]
702 if ent.off == off && ent.targetpc == targetpc {
703 return ent.val
704 }
705 }
706 }
707
708 if !f.valid() {
709 if strict && panicking == 0 {
710 print("runtime: no module data for ", hex(f.entry), "\n")
711 throw("no module data")
712 }
713 return -1
714 }
715 datap := f.datap
716 p := datap.pclntable[off:]
717 pc := f.entry
718 val := int32(-1)
719 for {
720 var ok bool
721 p, ok = step(p, &pc, &val, pc == f.entry)
722 if !ok {
723 break
724 }
725 if targetpc < pc {
726
727
728
729
730 if cache != nil {
731 ci := fastrandn(uint32(len(cache.entries)))
732 cache.entries[ci] = pcvalueCacheEnt{
733 targetpc: targetpc,
734 off: off,
735 val: val,
736 }
737 }
738
739 return val
740 }
741 }
742
743
744
745 if panicking != 0 || !strict {
746 return -1
747 }
748
749 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
750
751 p = datap.pclntable[off:]
752 pc = f.entry
753 val = -1
754 for {
755 var ok bool
756 p, ok = step(p, &pc, &val, pc == f.entry)
757 if !ok {
758 break
759 }
760 print("\tvalue=", val, " until pc=", hex(pc), "\n")
761 }
762
763 throw("invalid runtime symbol table")
764 return -1
765 }
766
767 func cfuncname(f funcInfo) *byte {
768 if !f.valid() || f.nameoff == 0 {
769 return nil
770 }
771 return &f.datap.pclntable[f.nameoff]
772 }
773
774 func funcname(f funcInfo) string {
775 return gostringnocopy(cfuncname(f))
776 }
777
778 func funcnameFromNameoff(f funcInfo, nameoff int32) string {
779 datap := f.datap
780 if !f.valid() {
781 return ""
782 }
783 cstr := &datap.pclntable[nameoff]
784 return gostringnocopy(cstr)
785 }
786
787 func funcfile(f funcInfo, fileno int32) string {
788 datap := f.datap
789 if !f.valid() {
790 return "?"
791 }
792 return gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
793 }
794
795 func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
796 datap := f.datap
797 if !f.valid() {
798 return "?", 0
799 }
800 fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict))
801 line = pcvalue(f, f.pcln, targetpc, nil, strict)
802 if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
803
804 return "?", 0
805 }
806 file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
807 return
808 }
809
810 func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
811 return funcline1(f, targetpc, true)
812 }
813
814 func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
815 x := pcvalue(f, f.pcsp, targetpc, cache, true)
816 if x&(sys.PtrSize-1) != 0 {
817 print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
818 }
819 return x
820 }
821
822 func pcdatavalue(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
823 if table < 0 || table >= f.npcdata {
824 return -1
825 }
826 off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
827 return pcvalue(f, off, targetpc, cache, true)
828 }
829
830 func funcdata(f funcInfo, i int32) unsafe.Pointer {
831 if i < 0 || i >= f.nfuncdata {
832 return nil
833 }
834 p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
835 if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
836 if uintptr(unsafe.Pointer(f._func))&4 != 0 {
837 println("runtime: misaligned func", f._func)
838 }
839 p = add(p, 4)
840 }
841 return *(*unsafe.Pointer)(add(p, uintptr(i)*sys.PtrSize))
842 }
843
844
845 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
846
847
848 uvdelta := uint32(p[0])
849 if uvdelta == 0 && !first {
850 return nil, false
851 }
852 n := uint32(1)
853 if uvdelta&0x80 != 0 {
854 n, uvdelta = readvarint(p)
855 }
856 p = p[n:]
857 if uvdelta&1 != 0 {
858 uvdelta = ^(uvdelta >> 1)
859 } else {
860 uvdelta >>= 1
861 }
862 vdelta := int32(uvdelta)
863 pcdelta := uint32(p[0])
864 n = 1
865 if pcdelta&0x80 != 0 {
866 n, pcdelta = readvarint(p)
867 }
868 p = p[n:]
869 *pc += uintptr(pcdelta * sys.PCQuantum)
870 *val += vdelta
871 return p, true
872 }
873
874
875 func readvarint(p []byte) (read uint32, val uint32) {
876 var v, shift, n uint32
877 for {
878 b := p[n]
879 n++
880 v |= uint32(b&0x7F) << (shift & 31)
881 if b&0x80 == 0 {
882 break
883 }
884 shift += 7
885 }
886 return n, v
887 }
888
889 type stackmap struct {
890 n int32
891 nbit int32
892 bytedata [1]byte
893 }
894
895
896 func stackmapdata(stkmap *stackmap, n int32) bitvector {
897 if n < 0 || n >= stkmap.n {
898 throw("stackmapdata: index out of range")
899 }
900 return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+7)>>3))))}
901 }
902
903
904 type inlinedCall struct {
905 parent int32
906 file int32
907 line int32
908 func_ int32
909 }
910
View as plain text