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