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