Source file src/runtime/symtab.go
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 func expandCgoFrames(pc uintptr) []Frame {
155 arg := cgoSymbolizerArg{pc: pc}
156 callCgoSymbolizer(&arg)
157
158 if arg.file == nil && arg.funcName == nil {
159
160 return nil
161 }
162
163 var frames []Frame
164 for {
165 frames = append(frames, Frame{
166 PC: pc,
167 Func: nil,
168 Function: gostring(arg.funcName),
169 File: gostring(arg.file),
170 Line: int(arg.lineno),
171 Entry: arg.entry,
172
173
174 })
175 if arg.more == 0 {
176 break
177 }
178 callCgoSymbolizer(&arg)
179 }
180
181
182
183
184
185 arg.pc = 0
186 callCgoSymbolizer(&arg)
187
188 return frames
189 }
190
191
192
193
194
195
196
197
198 type Func struct {
199 opaque struct{}
200 }
201
202 func (f *Func) raw() *_func {
203 return (*_func)(unsafe.Pointer(f))
204 }
205
206 func (f *Func) funcInfo() funcInfo {
207 fn := f.raw()
208 return funcInfo{fn, findmoduledatap(fn.entry)}
209 }
210
211
212
213
214 const (
215 _PCDATA_RegMapIndex = 0
216 _PCDATA_StackMapIndex = 1
217 _PCDATA_InlTreeIndex = 2
218
219 _FUNCDATA_ArgsPointerMaps = 0
220 _FUNCDATA_LocalsPointerMaps = 1
221 _FUNCDATA_RegPointerMaps = 2
222 _FUNCDATA_StackObjects = 3
223 _FUNCDATA_InlTree = 4
224
225 _ArgsSizeUnknown = -0x80000000
226 )
227
228
229
230
231
232
233 type funcID uint8
234
235 const (
236 funcID_normal funcID = iota
237 funcID_runtime_main
238 funcID_goexit
239 funcID_jmpdefer
240 funcID_mcall
241 funcID_morestack
242 funcID_mstart
243 funcID_rt0_go
244 funcID_asmcgocall
245 funcID_sigpanic
246 funcID_runfinq
247 funcID_gcBgMarkWorker
248 funcID_systemstack_switch
249 funcID_systemstack
250 funcID_cgocallback_gofunc
251 funcID_gogo
252 funcID_externalthreadhandler
253 funcID_debugCallV1
254 funcID_gopanic
255 funcID_panicwrap
256 funcID_wrapper
257 )
258
259
260
261
262
263
264 type moduledata struct {
265 pclntable []byte
266 ftab []functab
267 filetab []uint32
268 findfunctab uintptr
269 minpc, maxpc uintptr
270
271 text, etext uintptr
272 noptrdata, enoptrdata uintptr
273 data, edata uintptr
274 bss, ebss uintptr
275 noptrbss, enoptrbss uintptr
276 end, gcdata, gcbss uintptr
277 types, etypes uintptr
278
279 textsectmap []textsect
280 typelinks []int32
281 itablinks []*itab
282
283 ptab []ptabEntry
284
285 pluginpath string
286 pkghashes []modulehash
287
288 modulename string
289 modulehashes []modulehash
290
291 hasmain uint8
292
293 gcdatamask, gcbssmask bitvector
294
295 typemap map[typeOff]*_type
296
297 bad bool
298
299 next *moduledata
300 }
301
302
303
304
305
306
307
308
309
310
311
312
313
314 type modulehash struct {
315 modulename string
316 linktimehash string
317 runtimehash *string
318 }
319
320
321
322
323
324
325
326
327 var pinnedTypemaps []map[typeOff]*_type
328
329 var firstmoduledata moduledata
330 var lastmoduledatap *moduledata
331 var modulesSlice *[]*moduledata
332
333
334
335
336
337
338
339
340
341
342 func activeModules() []*moduledata {
343 p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
344 if p == nil {
345 return nil
346 }
347 return *p
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368 func modulesinit() {
369 modules := new([]*moduledata)
370 for md := &firstmoduledata; md != nil; md = md.next {
371 if md.bad {
372 continue
373 }
374 *modules = append(*modules, md)
375 if md.gcdatamask == (bitvector{}) {
376 md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), md.edata-md.data)
377 md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), md.ebss-md.bss)
378 }
379 }
380
381
382
383
384
385
386
387
388
389
390 for i, md := range *modules {
391 if md.hasmain != 0 {
392 (*modules)[0] = md
393 (*modules)[i] = &firstmoduledata
394 break
395 }
396 }
397
398 atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
399 }
400
401 type functab struct {
402 entry uintptr
403 funcoff uintptr
404 }
405
406
407
408 type textsect struct {
409 vaddr uintptr
410 length uintptr
411 baseaddr uintptr
412 }
413
414 const minfunc = 16
415 const pcbucketsize = 256 * minfunc
416
417
418
419
420
421
422
423
424
425 type findfuncbucket struct {
426 idx uint32
427 subbuckets [16]byte
428 }
429
430 func moduledataverify() {
431 for datap := &firstmoduledata; datap != nil; datap = datap.next {
432 moduledataverify1(datap)
433 }
434 }
435
436 const debugPcln = false
437
438 func moduledataverify1(datap *moduledata) {
439
440
441
442 pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
443 pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
444 if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != sys.PCQuantum || pcln[7] != sys.PtrSize {
445 println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
446 throw("invalid function symbol table\n")
447 }
448
449
450 nftab := len(datap.ftab) - 1
451 for i := 0; i < nftab; i++ {
452
453 if datap.ftab[i].entry > datap.ftab[i+1].entry {
454 f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
455 f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
456 f2name := "end"
457 if i+1 < nftab {
458 f2name = funcname(f2)
459 }
460 println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
461 for j := 0; j <= i; j++ {
462 print("\t", hex(datap.ftab[j].entry), " ", funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}), "\n")
463 }
464 if GOOS == "aix" && isarchive {
465 println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive")
466 }
467 throw("invalid runtime symbol table")
468 }
469 }
470
471 if datap.minpc != datap.ftab[0].entry ||
472 datap.maxpc != datap.ftab[nftab].entry {
473 throw("minpc or maxpc invalid")
474 }
475
476 for _, modulehash := range datap.modulehashes {
477 if modulehash.linktimehash != *modulehash.runtimehash {
478 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
479 throw("abi mismatch")
480 }
481 }
482 }
483
484
485
486
487
488
489
490 func FuncForPC(pc uintptr) *Func {
491 f := findfunc(pc)
492 if !f.valid() {
493 return nil
494 }
495 if inldata := funcdata(f, _FUNCDATA_InlTree); inldata != nil {
496
497
498
499
500 if ix := pcdatavalue1(f, _PCDATA_InlTreeIndex, pc, nil, false); ix >= 0 {
501 inltree := (*[1 << 20]inlinedCall)(inldata)
502 name := funcnameFromNameoff(f, inltree[ix].func_)
503 file, line := funcline(f, pc)
504 fi := &funcinl{
505 entry: f.entry,
506 name: name,
507 file: file,
508 line: int(line),
509 }
510 return (*Func)(unsafe.Pointer(fi))
511 }
512 }
513 return f._Func()
514 }
515
516
517 func (f *Func) Name() string {
518 if f == nil {
519 return ""
520 }
521 fn := f.raw()
522 if fn.entry == 0 {
523 fi := (*funcinl)(unsafe.Pointer(fn))
524 return fi.name
525 }
526 return funcname(f.funcInfo())
527 }
528
529
530 func (f *Func) Entry() uintptr {
531 fn := f.raw()
532 if fn.entry == 0 {
533 fi := (*funcinl)(unsafe.Pointer(fn))
534 return fi.entry
535 }
536 return fn.entry
537 }
538
539
540
541
542
543 func (f *Func) FileLine(pc uintptr) (file string, line int) {
544 fn := f.raw()
545 if fn.entry == 0 {
546 fi := (*funcinl)(unsafe.Pointer(fn))
547 return fi.file, fi.line
548 }
549
550
551 file, line32 := funcline1(f.funcInfo(), pc, false)
552 return file, int(line32)
553 }
554
555 func findmoduledatap(pc uintptr) *moduledata {
556 for datap := &firstmoduledata; datap != nil; datap = datap.next {
557 if datap.minpc <= pc && pc < datap.maxpc {
558 return datap
559 }
560 }
561 return nil
562 }
563
564 type funcInfo struct {
565 *_func
566 datap *moduledata
567 }
568
569 func (f funcInfo) valid() bool {
570 return f._func != nil
571 }
572
573 func (f funcInfo) _Func() *Func {
574 return (*Func)(unsafe.Pointer(f._func))
575 }
576
577 func findfunc(pc uintptr) funcInfo {
578 datap := findmoduledatap(pc)
579 if datap == nil {
580 return funcInfo{}
581 }
582 const nsub = uintptr(len(findfuncbucket{}.subbuckets))
583
584 x := pc - datap.minpc
585 b := x / pcbucketsize
586 i := x % pcbucketsize / (pcbucketsize / nsub)
587
588 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
589 idx := ffb.idx + uint32(ffb.subbuckets[i])
590
591
592
593
594
595 if idx >= uint32(len(datap.ftab)) {
596 idx = uint32(len(datap.ftab) - 1)
597 }
598 if pc < datap.ftab[idx].entry {
599
600
601
602 for datap.ftab[idx].entry > pc && idx > 0 {
603 idx--
604 }
605 if idx == 0 {
606 throw("findfunc: bad findfunctab entry idx")
607 }
608 } else {
609
610 for datap.ftab[idx+1].entry <= pc {
611 idx++
612 }
613 }
614 return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])), datap}
615 }
616
617 type pcvalueCache struct {
618 entries [2][8]pcvalueCacheEnt
619 }
620
621 type pcvalueCacheEnt struct {
622
623 targetpc uintptr
624 off int32
625
626 val int32
627 }
628
629
630
631
632
633 func pcvalueCacheKey(targetpc uintptr) uintptr {
634 return (targetpc / sys.PtrSize) % uintptr(len(pcvalueCache{}.entries))
635 }
636
637 func pcvalue(f funcInfo, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
638 if off == 0 {
639 return -1
640 }
641
642
643
644
645
646
647
648 if cache != nil {
649 x := pcvalueCacheKey(targetpc)
650 for i := range cache.entries[x] {
651
652
653
654
655
656 ent := &cache.entries[x][i]
657 if ent.off == off && ent.targetpc == targetpc {
658 return ent.val
659 }
660 }
661 }
662
663 if !f.valid() {
664 if strict && panicking == 0 {
665 print("runtime: no module data for ", hex(f.entry), "\n")
666 throw("no module data")
667 }
668 return -1
669 }
670 datap := f.datap
671 p := datap.pclntable[off:]
672 pc := f.entry
673 val := int32(-1)
674 for {
675 var ok bool
676 p, ok = step(p, &pc, &val, pc == f.entry)
677 if !ok {
678 break
679 }
680 if targetpc < pc {
681
682
683
684
685
686
687 if cache != nil {
688 x := pcvalueCacheKey(targetpc)
689 e := &cache.entries[x]
690 ci := fastrand() % uint32(len(cache.entries[x]))
691 e[ci] = e[0]
692 e[0] = pcvalueCacheEnt{
693 targetpc: targetpc,
694 off: off,
695 val: val,
696 }
697 }
698
699 return val
700 }
701 }
702
703
704
705 if panicking != 0 || !strict {
706 return -1
707 }
708
709 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
710
711 p = datap.pclntable[off:]
712 pc = f.entry
713 val = -1
714 for {
715 var ok bool
716 p, ok = step(p, &pc, &val, pc == f.entry)
717 if !ok {
718 break
719 }
720 print("\tvalue=", val, " until pc=", hex(pc), "\n")
721 }
722
723 throw("invalid runtime symbol table")
724 return -1
725 }
726
727 func cfuncname(f funcInfo) *byte {
728 if !f.valid() || f.nameoff == 0 {
729 return nil
730 }
731 return &f.datap.pclntable[f.nameoff]
732 }
733
734 func funcname(f funcInfo) string {
735 return gostringnocopy(cfuncname(f))
736 }
737
738 func funcnameFromNameoff(f funcInfo, nameoff int32) string {
739 datap := f.datap
740 if !f.valid() {
741 return ""
742 }
743 cstr := &datap.pclntable[nameoff]
744 return gostringnocopy(cstr)
745 }
746
747 func funcfile(f funcInfo, fileno int32) string {
748 datap := f.datap
749 if !f.valid() {
750 return "?"
751 }
752 return gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
753 }
754
755 func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
756 datap := f.datap
757 if !f.valid() {
758 return "?", 0
759 }
760 fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict))
761 line = pcvalue(f, f.pcln, targetpc, nil, strict)
762 if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
763
764 return "?", 0
765 }
766 file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
767 return
768 }
769
770 func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
771 return funcline1(f, targetpc, true)
772 }
773
774 func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
775 x := pcvalue(f, f.pcsp, targetpc, cache, true)
776 if x&(sys.PtrSize-1) != 0 {
777 print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
778 }
779 return x
780 }
781
782 func pcdatastart(f funcInfo, table int32) int32 {
783 return *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
784 }
785
786 func pcdatavalue(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
787 if table < 0 || table >= f.npcdata {
788 return -1
789 }
790 return pcvalue(f, pcdatastart(f, table), targetpc, cache, true)
791 }
792
793 func pcdatavalue1(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
794 if table < 0 || table >= f.npcdata {
795 return -1
796 }
797 return pcvalue(f, pcdatastart(f, table), targetpc, cache, strict)
798 }
799
800 func funcdata(f funcInfo, i uint8) unsafe.Pointer {
801 if i < 0 || i >= f.nfuncdata {
802 return nil
803 }
804 p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
805 if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
806 if uintptr(unsafe.Pointer(f._func))&4 != 0 {
807 println("runtime: misaligned func", f._func)
808 }
809 p = add(p, 4)
810 }
811 return *(*unsafe.Pointer)(add(p, uintptr(i)*sys.PtrSize))
812 }
813
814
815 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
816
817
818 uvdelta := uint32(p[0])
819 if uvdelta == 0 && !first {
820 return nil, false
821 }
822 n := uint32(1)
823 if uvdelta&0x80 != 0 {
824 n, uvdelta = readvarint(p)
825 }
826 *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1))
827 p = p[n:]
828
829 pcdelta := uint32(p[0])
830 n = 1
831 if pcdelta&0x80 != 0 {
832 n, pcdelta = readvarint(p)
833 }
834 p = p[n:]
835 *pc += uintptr(pcdelta * sys.PCQuantum)
836 return p, true
837 }
838
839
840 func readvarint(p []byte) (read uint32, val uint32) {
841 var v, shift, n uint32
842 for {
843 b := p[n]
844 n++
845 v |= uint32(b&0x7F) << (shift & 31)
846 if b&0x80 == 0 {
847 break
848 }
849 shift += 7
850 }
851 return n, v
852 }
853
854 type stackmap struct {
855 n int32
856 nbit int32
857 bytedata [1]byte
858 }
859
860
861 func stackmapdata(stkmap *stackmap, n int32) bitvector {
862
863
864
865 if stackDebug > 0 && (n < 0 || n >= stkmap.n) {
866 throw("stackmapdata: index out of range")
867 }
868 return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))}
869 }
870
871
872 type inlinedCall struct {
873 parent int16
874 funcID funcID
875 _ byte
876 file int32
877 line int32
878 func_ int32
879 parentPc int32
880 }
881
View as plain text