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