Source file
src/runtime/symtab.go
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/goarch"
10 "internal/runtime/atomic"
11 "runtime/internal/sys"
12 "unsafe"
13 )
14
15
16
17 type Frames struct {
18
19 callers []uintptr
20
21
22 nextPC uintptr
23
24
25 frames []Frame
26 frameStore [2]Frame
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
60
61
62
63 startLine int
64
65
66
67
68 Entry uintptr
69
70
71
72
73 funcInfo funcInfo
74 }
75
76
77
78
79 func CallersFrames(callers []uintptr) *Frames {
80 f := &Frames{callers: callers}
81 f.frames = f.frameStore[:0]
82 return f
83 }
84
85
86
87
88
89
90
91
92
93
94 func (ci *Frames) Next() (frame Frame, more bool) {
95 for len(ci.frames) < 2 {
96
97
98
99 if len(ci.callers) == 0 {
100 break
101 }
102 var pc uintptr
103 if ci.nextPC != 0 {
104 pc, ci.nextPC = ci.nextPC, 0
105 } else {
106 pc, ci.callers = ci.callers[0], ci.callers[1:]
107 }
108 funcInfo := findfunc(pc)
109 if !funcInfo.valid() {
110 if cgoSymbolizer != nil {
111
112
113
114 ci.frames = append(ci.frames, expandCgoFrames(pc)...)
115 }
116 continue
117 }
118 f := funcInfo._Func()
119 entry := f.Entry()
120 if pc > entry {
121
122
123
124
125 pc--
126 }
127
128
129 u, uf := newInlineUnwinder(funcInfo, pc)
130 sf := u.srcFunc(uf)
131 if u.isInlined(uf) {
132
133
134 f = nil
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 for unext := u.next(uf); unext.valid() && len(ci.callers) > 0 && ci.callers[0] != unext.pc+1; unext = u.next(unext) {
150 snext := u.srcFunc(unext)
151 if snext.funcID == abi.FuncIDWrapper && elideWrapperCalling(sf.funcID) {
152
153 continue
154 }
155 ci.nextPC = unext.pc + 1
156 break
157 }
158 }
159 ci.frames = append(ci.frames, Frame{
160 PC: pc,
161 Func: f,
162 Function: funcNameForPrint(sf.name()),
163 Entry: entry,
164 startLine: int(sf.startLine),
165 funcInfo: funcInfo,
166
167 })
168 }
169
170
171
172 switch len(ci.frames) {
173 case 0:
174 return
175 case 1:
176 frame = ci.frames[0]
177 ci.frames = ci.frameStore[:0]
178 case 2:
179 frame = ci.frames[0]
180 ci.frameStore[0] = ci.frames[1]
181 ci.frames = ci.frameStore[:1]
182 default:
183 frame = ci.frames[0]
184 ci.frames = ci.frames[1:]
185 }
186 more = len(ci.frames) > 0
187 if frame.funcInfo.valid() {
188
189
190
191 file, line := funcline1(frame.funcInfo, frame.PC, false)
192 frame.File, frame.Line = file, int(line)
193 }
194 return
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208 func runtime_FrameStartLine(f *Frame) int {
209 return f.startLine
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225 func runtime_FrameSymbolName(f *Frame) string {
226 if !f.funcInfo.valid() {
227 return f.Function
228 }
229 u, uf := newInlineUnwinder(f.funcInfo, f.PC)
230 sf := u.srcFunc(uf)
231 return sf.name()
232 }
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247 func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr {
248
249
250 if len(stk) == 0 {
251 return stk
252 }
253 pc := stk[len(stk)-1]
254 tracepc := pc - 1
255
256 f := findfunc(tracepc)
257 if !f.valid() {
258
259 return stk
260 }
261
262 u, uf := newInlineUnwinder(f, tracepc)
263 if !u.isInlined(uf) {
264
265 return stk
266 }
267
268
269
270
271 calleeID := abi.FuncIDNormal
272
273
274 stk = stk[:len(stk)-1]
275
276 for ; uf.valid(); uf = u.next(uf) {
277 funcID := u.srcFunc(uf).funcID
278 if funcID == abi.FuncIDWrapper && elideWrapperCalling(calleeID) {
279
280 } else {
281 stk = append(stk, uf.pc+1)
282 }
283 calleeID = funcID
284 }
285
286 return stk
287 }
288
289
290
291
292 func expandCgoFrames(pc uintptr) []Frame {
293 arg := cgoSymbolizerArg{pc: pc}
294 callCgoSymbolizer(&arg)
295
296 if arg.file == nil && arg.funcName == nil {
297
298 return nil
299 }
300
301 var frames []Frame
302 for {
303 frames = append(frames, Frame{
304 PC: pc,
305 Func: nil,
306 Function: gostring(arg.funcName),
307 File: gostring(arg.file),
308 Line: int(arg.lineno),
309 Entry: arg.entry,
310
311
312 })
313 if arg.more == 0 {
314 break
315 }
316 callCgoSymbolizer(&arg)
317 }
318
319
320
321
322
323 arg.pc = 0
324 callCgoSymbolizer(&arg)
325
326 return frames
327 }
328
329
330
331
332
333
334
335
336 type Func struct {
337 opaque struct{}
338 }
339
340 func (f *Func) raw() *_func {
341 return (*_func)(unsafe.Pointer(f))
342 }
343
344 func (f *Func) funcInfo() funcInfo {
345 return f.raw().funcInfo()
346 }
347
348 func (f *_func) funcInfo() funcInfo {
349
350
351
352 ptr := uintptr(unsafe.Pointer(f))
353 var mod *moduledata
354 for datap := &firstmoduledata; datap != nil; datap = datap.next {
355 if len(datap.pclntable) == 0 {
356 continue
357 }
358 base := uintptr(unsafe.Pointer(&datap.pclntable[0]))
359 if base <= ptr && ptr < base+uintptr(len(datap.pclntable)) {
360 mod = datap
361 break
362 }
363 }
364 return funcInfo{f, mod}
365 }
366
367
368 type pcHeader struct {
369 magic uint32
370 pad1, pad2 uint8
371 minLC uint8
372 ptrSize uint8
373 nfunc int
374 nfiles uint
375 textStart uintptr
376 funcnameOffset uintptr
377 cuOffset uintptr
378 filetabOffset uintptr
379 pctabOffset uintptr
380 pclnOffset uintptr
381 }
382
383
384
385
386
387
388 type moduledata struct {
389 sys.NotInHeap
390
391 pcHeader *pcHeader
392 funcnametab []byte
393 cutab []uint32
394 filetab []byte
395 pctab []byte
396 pclntable []byte
397 ftab []functab
398 findfunctab uintptr
399 minpc, maxpc uintptr
400
401 text, etext uintptr
402 noptrdata, enoptrdata uintptr
403 data, edata uintptr
404 bss, ebss uintptr
405 noptrbss, enoptrbss uintptr
406 covctrs, ecovctrs uintptr
407 end, gcdata, gcbss uintptr
408 types, etypes uintptr
409 rodata uintptr
410 gofunc uintptr
411
412 textsectmap []textsect
413 typelinks []int32
414 itablinks []*itab
415
416 ptab []ptabEntry
417
418 pluginpath string
419 pkghashes []modulehash
420
421
422
423 inittasks []*initTask
424
425 modulename string
426 modulehashes []modulehash
427
428 hasmain uint8
429 bad bool
430
431 gcdatamask, gcbssmask bitvector
432
433 typemap map[typeOff]*_type
434
435 next *moduledata
436 }
437
438
439
440
441
442
443
444
445
446
447
448
449
450 type modulehash struct {
451 modulename string
452 linktimehash string
453 runtimehash *string
454 }
455
456
457
458
459
460
461
462
463 var pinnedTypemaps []map[typeOff]*_type
464
465 var firstmoduledata moduledata
466
467
468
469
470
471
472
473
474
475
476 var lastmoduledatap *moduledata
477
478 var modulesSlice *[]*moduledata
479
480
481
482
483
484
485
486
487
488
489
490 func activeModules() []*moduledata {
491 p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
492 if p == nil {
493 return nil
494 }
495 return *p
496 }
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516 func modulesinit() {
517 modules := new([]*moduledata)
518 for md := &firstmoduledata; md != nil; md = md.next {
519 if md.bad {
520 continue
521 }
522 *modules = append(*modules, md)
523 if md.gcdatamask == (bitvector{}) {
524 scanDataSize := md.edata - md.data
525 md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), scanDataSize)
526 scanBSSSize := md.ebss - md.bss
527 md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), scanBSSSize)
528 gcController.addGlobals(int64(scanDataSize + scanBSSSize))
529 }
530 }
531
532
533
534
535
536
537
538
539
540
541 for i, md := range *modules {
542 if md.hasmain != 0 {
543 (*modules)[0] = md
544 (*modules)[i] = &firstmoduledata
545 break
546 }
547 }
548
549 atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
550 }
551
552 type functab struct {
553 entryoff uint32
554 funcoff uint32
555 }
556
557
558
559 type textsect struct {
560 vaddr uintptr
561 end uintptr
562 baseaddr uintptr
563 }
564
565
566
567
568
569
570
571
572
573 type findfuncbucket struct {
574 idx uint32
575 subbuckets [16]byte
576 }
577
578 func moduledataverify() {
579 for datap := &firstmoduledata; datap != nil; datap = datap.next {
580 moduledataverify1(datap)
581 }
582 }
583
584 const debugPcln = false
585
586
587
588
589
590
591
592
593
594
595 func moduledataverify1(datap *moduledata) {
596
597 hdr := datap.pcHeader
598 if hdr.magic != 0xfffffff1 || hdr.pad1 != 0 || hdr.pad2 != 0 ||
599 hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize || hdr.textStart != datap.text {
600 println("runtime: pcHeader: magic=", hex(hdr.magic), "pad1=", hdr.pad1, "pad2=", hdr.pad2,
601 "minLC=", hdr.minLC, "ptrSize=", hdr.ptrSize, "pcHeader.textStart=", hex(hdr.textStart),
602 "text=", hex(datap.text), "pluginpath=", datap.pluginpath)
603 throw("invalid function symbol table")
604 }
605
606
607 nftab := len(datap.ftab) - 1
608 for i := 0; i < nftab; i++ {
609
610 if datap.ftab[i].entryoff > datap.ftab[i+1].entryoff {
611 f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
612 f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
613 f2name := "end"
614 if i+1 < nftab {
615 f2name = funcname(f2)
616 }
617 println("function symbol table not sorted by PC offset:", hex(datap.ftab[i].entryoff), funcname(f1), ">", hex(datap.ftab[i+1].entryoff), f2name, ", plugin:", datap.pluginpath)
618 for j := 0; j <= i; j++ {
619 println("\t", hex(datap.ftab[j].entryoff), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}))
620 }
621 if GOOS == "aix" && isarchive {
622 println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive")
623 }
624 throw("invalid runtime symbol table")
625 }
626 }
627
628 min := datap.textAddr(datap.ftab[0].entryoff)
629 max := datap.textAddr(datap.ftab[nftab].entryoff)
630 if datap.minpc != min || datap.maxpc != max {
631 println("minpc=", hex(datap.minpc), "min=", hex(min), "maxpc=", hex(datap.maxpc), "max=", hex(max))
632 throw("minpc or maxpc invalid")
633 }
634
635 for _, modulehash := range datap.modulehashes {
636 if modulehash.linktimehash != *modulehash.runtimehash {
637 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
638 throw("abi mismatch")
639 }
640 }
641 }
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661 func (md *moduledata) textAddr(off32 uint32) uintptr {
662 off := uintptr(off32)
663 res := md.text + off
664 if len(md.textsectmap) > 1 {
665 for i, sect := range md.textsectmap {
666
667 if off >= sect.vaddr && off < sect.end || (i == len(md.textsectmap)-1 && off == sect.end) {
668 res = sect.baseaddr + off - sect.vaddr
669 break
670 }
671 }
672 if res > md.etext && GOARCH != "wasm" {
673 println("runtime: textAddr", hex(res), "out of range", hex(md.text), "-", hex(md.etext))
674 throw("runtime: text offset out of range")
675 }
676 }
677 return res
678 }
679
680
681
682
683
684
685
686 func (md *moduledata) textOff(pc uintptr) (uint32, bool) {
687 res := uint32(pc - md.text)
688 if len(md.textsectmap) > 1 {
689 for i, sect := range md.textsectmap {
690 if sect.baseaddr > pc {
691
692 return 0, false
693 }
694 end := sect.baseaddr + (sect.end - sect.vaddr)
695
696 if i == len(md.textsectmap)-1 {
697 end++
698 }
699 if pc < end {
700 res = uint32(pc - sect.baseaddr + sect.vaddr)
701 break
702 }
703 }
704 }
705 return res, true
706 }
707
708
709 func (md *moduledata) funcName(nameOff int32) string {
710 if nameOff == 0 {
711 return ""
712 }
713 return gostringnocopy(&md.funcnametab[nameOff])
714 }
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732 func FuncForPC(pc uintptr) *Func {
733 f := findfunc(pc)
734 if !f.valid() {
735 return nil
736 }
737
738
739
740
741 u, uf := newInlineUnwinder(f, pc)
742 if !u.isInlined(uf) {
743 return f._Func()
744 }
745 sf := u.srcFunc(uf)
746 file, line := u.fileLine(uf)
747 fi := &funcinl{
748 ones: ^uint32(0),
749 entry: f.entry(),
750 name: sf.name(),
751 file: file,
752 line: int32(line),
753 startLine: sf.startLine,
754 }
755 return (*Func)(unsafe.Pointer(fi))
756 }
757
758
759 func (f *Func) Name() string {
760 if f == nil {
761 return ""
762 }
763 fn := f.raw()
764 if fn.isInlined() {
765 fi := (*funcinl)(unsafe.Pointer(fn))
766 return funcNameForPrint(fi.name)
767 }
768 return funcNameForPrint(funcname(f.funcInfo()))
769 }
770
771
772 func (f *Func) Entry() uintptr {
773 fn := f.raw()
774 if fn.isInlined() {
775 fi := (*funcinl)(unsafe.Pointer(fn))
776 return fi.entry
777 }
778 return fn.funcInfo().entry()
779 }
780
781
782
783
784
785 func (f *Func) FileLine(pc uintptr) (file string, line int) {
786 fn := f.raw()
787 if fn.isInlined() {
788 fi := (*funcinl)(unsafe.Pointer(fn))
789 return fi.file, int(fi.line)
790 }
791
792
793 file, line32 := funcline1(f.funcInfo(), pc, false)
794 return file, int(line32)
795 }
796
797
798
799 func (f *Func) startLine() int32 {
800 fn := f.raw()
801 if fn.isInlined() {
802 fi := (*funcinl)(unsafe.Pointer(fn))
803 return fi.startLine
804 }
805 return fn.funcInfo().startLine
806 }
807
808
809
810
811
812
813
814 func findmoduledatap(pc uintptr) *moduledata {
815 for datap := &firstmoduledata; datap != nil; datap = datap.next {
816 if datap.minpc <= pc && pc < datap.maxpc {
817 return datap
818 }
819 }
820 return nil
821 }
822
823 type funcInfo struct {
824 *_func
825 datap *moduledata
826 }
827
828 func (f funcInfo) valid() bool {
829 return f._func != nil
830 }
831
832 func (f funcInfo) _Func() *Func {
833 return (*Func)(unsafe.Pointer(f._func))
834 }
835
836
837 func (f *_func) isInlined() bool {
838 return f.entryOff == ^uint32(0)
839 }
840
841
842
843
844
845
846
847
848
849
850 func (f funcInfo) entry() uintptr {
851 return f.datap.textAddr(f.entryOff)
852 }
853
854
855 func badFuncInfoEntry(funcInfo) uintptr
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873 func findfunc(pc uintptr) funcInfo {
874 datap := findmoduledatap(pc)
875 if datap == nil {
876 return funcInfo{}
877 }
878 const nsub = uintptr(len(findfuncbucket{}.subbuckets))
879
880 pcOff, ok := datap.textOff(pc)
881 if !ok {
882 return funcInfo{}
883 }
884
885 x := uintptr(pcOff) + datap.text - datap.minpc
886 b := x / abi.FuncTabBucketSize
887 i := x % abi.FuncTabBucketSize / (abi.FuncTabBucketSize / nsub)
888
889 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
890 idx := ffb.idx + uint32(ffb.subbuckets[i])
891
892
893 for datap.ftab[idx+1].entryoff <= pcOff {
894 idx++
895 }
896
897 funcoff := datap.ftab[idx].funcoff
898 return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap}
899 }
900
901
902
903
904 type srcFunc struct {
905 datap *moduledata
906 nameOff int32
907 startLine int32
908 funcID abi.FuncID
909 }
910
911 func (f funcInfo) srcFunc() srcFunc {
912 if !f.valid() {
913 return srcFunc{}
914 }
915 return srcFunc{f.datap, f.nameOff, f.startLine, f.funcID}
916 }
917
918
919
920
921
922
923
924
925 func (s srcFunc) name() string {
926 if s.datap == nil {
927 return ""
928 }
929 return s.datap.funcName(s.nameOff)
930 }
931
932
933 func badSrcFuncName(srcFunc) string
934
935 type pcvalueCache struct {
936 entries [2][8]pcvalueCacheEnt
937 inUse int
938 }
939
940 type pcvalueCacheEnt struct {
941
942 targetpc uintptr
943 off uint32
944
945 val int32
946 valPC uintptr
947 }
948
949
950
951
952
953 func pcvalueCacheKey(targetpc uintptr) uintptr {
954 return (targetpc / goarch.PtrSize) % uintptr(len(pcvalueCache{}.entries))
955 }
956
957
958 func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uintptr) {
959
960
961 const debugCheckCache = false
962
963 if off == 0 {
964 return -1, 0
965 }
966
967
968
969
970 var checkVal int32
971 var checkPC uintptr
972 ck := pcvalueCacheKey(targetpc)
973 {
974 mp := acquirem()
975 cache := &mp.pcvalueCache
976
977
978
979
980 cache.inUse++
981 if cache.inUse == 1 {
982 for i := range cache.entries[ck] {
983
984
985
986
987
988 ent := &cache.entries[ck][i]
989 if ent.off == off && ent.targetpc == targetpc {
990 val, pc := ent.val, ent.valPC
991 if debugCheckCache {
992 checkVal, checkPC = ent.val, ent.valPC
993 break
994 } else {
995 cache.inUse--
996 releasem(mp)
997 return val, pc
998 }
999 }
1000 }
1001 } else if debugCheckCache && (cache.inUse < 1 || cache.inUse > 2) {
1002
1003
1004 throw("cache.inUse out of range")
1005 }
1006 cache.inUse--
1007 releasem(mp)
1008 }
1009
1010 if !f.valid() {
1011 if strict && panicking.Load() == 0 {
1012 println("runtime: no module data for", hex(f.entry()))
1013 throw("no module data")
1014 }
1015 return -1, 0
1016 }
1017 datap := f.datap
1018 p := datap.pctab[off:]
1019 pc := f.entry()
1020 prevpc := pc
1021 val := int32(-1)
1022 for {
1023 var ok bool
1024 p, ok = step(p, &pc, &val, pc == f.entry())
1025 if !ok {
1026 break
1027 }
1028 if targetpc < pc {
1029
1030
1031
1032
1033
1034
1035 if debugCheckCache && checkPC != 0 {
1036 if checkVal != val || checkPC != prevpc {
1037 print("runtime: table value ", val, "@", prevpc, " != cache value ", checkVal, "@", checkPC, " at PC ", targetpc, " off ", off, "\n")
1038 throw("bad pcvalue cache")
1039 }
1040 } else {
1041 mp := acquirem()
1042 cache := &mp.pcvalueCache
1043 cache.inUse++
1044 if cache.inUse == 1 {
1045 e := &cache.entries[ck]
1046 ci := cheaprandn(uint32(len(cache.entries[ck])))
1047 e[ci] = e[0]
1048 e[0] = pcvalueCacheEnt{
1049 targetpc: targetpc,
1050 off: off,
1051 val: val,
1052 valPC: prevpc,
1053 }
1054 }
1055 cache.inUse--
1056 releasem(mp)
1057 }
1058
1059 return val, prevpc
1060 }
1061 prevpc = pc
1062 }
1063
1064
1065
1066 if panicking.Load() != 0 || !strict {
1067 return -1, 0
1068 }
1069
1070 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
1071
1072 p = datap.pctab[off:]
1073 pc = f.entry()
1074 val = -1
1075 for {
1076 var ok bool
1077 p, ok = step(p, &pc, &val, pc == f.entry())
1078 if !ok {
1079 break
1080 }
1081 print("\tvalue=", val, " until pc=", hex(pc), "\n")
1082 }
1083
1084 throw("invalid runtime symbol table")
1085 return -1, 0
1086 }
1087
1088 func funcname(f funcInfo) string {
1089 if !f.valid() {
1090 return ""
1091 }
1092 return f.datap.funcName(f.nameOff)
1093 }
1094
1095 func funcpkgpath(f funcInfo) string {
1096 name := funcNameForPrint(funcname(f))
1097 i := len(name) - 1
1098 for ; i > 0; i-- {
1099 if name[i] == '/' {
1100 break
1101 }
1102 }
1103 for ; i < len(name); i++ {
1104 if name[i] == '.' {
1105 break
1106 }
1107 }
1108 return name[:i]
1109 }
1110
1111 func funcfile(f funcInfo, fileno int32) string {
1112 datap := f.datap
1113 if !f.valid() {
1114 return "?"
1115 }
1116
1117 if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) {
1118 return gostringnocopy(&datap.filetab[fileoff])
1119 }
1120
1121 return "?"
1122 }
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133 func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
1134 datap := f.datap
1135 if !f.valid() {
1136 return "?", 0
1137 }
1138 fileno, _ := pcvalue(f, f.pcfile, targetpc, strict)
1139 line, _ = pcvalue(f, f.pcln, targetpc, strict)
1140 if fileno == -1 || line == -1 || int(fileno) >= len(datap.filetab) {
1141
1142 return "?", 0
1143 }
1144 file = funcfile(f, fileno)
1145 return
1146 }
1147
1148 func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
1149 return funcline1(f, targetpc, true)
1150 }
1151
1152 func funcspdelta(f funcInfo, targetpc uintptr) int32 {
1153 x, _ := pcvalue(f, f.pcsp, targetpc, true)
1154 if debugPcln && x&(goarch.PtrSize-1) != 0 {
1155 print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
1156 throw("bad spdelta")
1157 }
1158 return x
1159 }
1160
1161
1162 func funcMaxSPDelta(f funcInfo) int32 {
1163 datap := f.datap
1164 p := datap.pctab[f.pcsp:]
1165 pc := f.entry()
1166 val := int32(-1)
1167 most := int32(0)
1168 for {
1169 var ok bool
1170 p, ok = step(p, &pc, &val, pc == f.entry())
1171 if !ok {
1172 return most
1173 }
1174 most = max(most, val)
1175 }
1176 }
1177
1178 func pcdatastart(f funcInfo, table uint32) uint32 {
1179 return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
1180 }
1181
1182 func pcdatavalue(f funcInfo, table uint32, targetpc uintptr) int32 {
1183 if table >= f.npcdata {
1184 return -1
1185 }
1186 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, true)
1187 return r
1188 }
1189
1190 func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, strict bool) int32 {
1191 if table >= f.npcdata {
1192 return -1
1193 }
1194 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, strict)
1195 return r
1196 }
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209 func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) {
1210 if table >= f.npcdata {
1211 return -1, 0
1212 }
1213 return pcvalue(f, pcdatastart(f, table), targetpc, true)
1214 }
1215
1216
1217
1218 func funcdata(f funcInfo, i uint8) unsafe.Pointer {
1219 if i < 0 || i >= f.nfuncdata {
1220 return nil
1221 }
1222 base := f.datap.gofunc
1223 p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4
1224 off := *(*uint32)(unsafe.Pointer(p))
1225
1226
1227 var mask uintptr
1228 if off == ^uint32(0) {
1229 mask = 1
1230 }
1231 mask--
1232 raw := base + uintptr(off)
1233 return unsafe.Pointer(raw & mask)
1234 }
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
1248
1249
1250 uvdelta := uint32(p[0])
1251 if uvdelta == 0 && !first {
1252 return nil, false
1253 }
1254 n := uint32(1)
1255 if uvdelta&0x80 != 0 {
1256 n, uvdelta = readvarint(p)
1257 }
1258 *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1))
1259 p = p[n:]
1260
1261 pcdelta := uint32(p[0])
1262 n = 1
1263 if pcdelta&0x80 != 0 {
1264 n, pcdelta = readvarint(p)
1265 }
1266 p = p[n:]
1267 *pc += uintptr(pcdelta * sys.PCQuantum)
1268 return p, true
1269 }
1270
1271
1272 func readvarint(p []byte) (read uint32, val uint32) {
1273 var v, shift, n uint32
1274 for {
1275 b := p[n]
1276 n++
1277 v |= uint32(b&0x7F) << (shift & 31)
1278 if b&0x80 == 0 {
1279 break
1280 }
1281 shift += 7
1282 }
1283 return n, v
1284 }
1285
1286 type stackmap struct {
1287 n int32
1288 nbit int32
1289 bytedata [1]byte
1290 }
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302 func stackmapdata(stkmap *stackmap, n int32) bitvector {
1303
1304
1305
1306 if stackDebug > 0 && (n < 0 || n >= stkmap.n) {
1307 throw("stackmapdata: index out of range")
1308 }
1309 return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))}
1310 }
1311
View as plain text