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, typedesclen, etypes uintptr
423 itaboffset, itabsize uintptr
424 rodata uintptr
425 gofunc uintptr
426 epclntab uintptr
427
428 textsectmap []textsect
429
430 ptab []ptabEntry
431
432 pluginpath string
433 pkghashes []modulehash
434
435
436
437 inittasks []*initTask
438
439 modulename string
440 modulehashes []modulehash
441
442 hasmain uint8
443 bad bool
444
445 gcdatamask, gcbssmask bitvector
446
447 typemap map[*_type]*_type
448
449 next *moduledata
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463
464 type modulehash struct {
465 modulename string
466 linktimehash string
467 runtimehash *string
468 }
469
470
471
472
473
474
475
476
477 var pinnedTypemaps []map[*_type]*_type
478
479
480
481
482
483
484
485
486
487
488
489 var aixStaticDataBase uintptr
490
491 var firstmoduledata moduledata
492
493
494
495
496
497
498
499
500
501
502
503 var lastmoduledatap *moduledata
504
505 var modulesSlice *[]*moduledata
506
507
508
509
510
511
512
513
514
515
516
517 func activeModules() []*moduledata {
518 p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
519 if p == nil {
520 return nil
521 }
522 return *p
523 }
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 func modulesinit() {
544 modules := new([]*moduledata)
545 for md := &firstmoduledata; md != nil; md = md.next {
546 if md.bad {
547 continue
548 }
549 *modules = append(*modules, md)
550 if md.gcdatamask == (bitvector{}) {
551 scanDataSize := md.edata - md.data
552 md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), scanDataSize)
553 scanBSSSize := md.ebss - md.bss
554 md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), scanBSSSize)
555 gcController.addGlobals(int64(scanDataSize + scanBSSSize))
556 }
557 }
558
559
560
561
562
563
564
565
566
567
568 for i, md := range *modules {
569 if md.hasmain != 0 {
570 (*modules)[0] = md
571 (*modules)[i] = &firstmoduledata
572 break
573 }
574 }
575
576 atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
577 }
578
579 type functab struct {
580 entryoff uint32
581 funcoff uint32
582 }
583
584
585
586 type textsect struct {
587 vaddr uintptr
588 end uintptr
589 baseaddr uintptr
590 }
591
592
593
594
595
596
597
598
599
600 type findfuncbucket struct {
601 idx uint32
602 subbuckets [16]byte
603 }
604
605 func moduledataverify() {
606 for datap := &firstmoduledata; datap != nil; datap = datap.next {
607 moduledataverify1(datap)
608 }
609 }
610
611 const debugPcln = false
612
613
614
615
616
617
618
619
620
621
622
623 func moduledataverify1(datap *moduledata) {
624
625 hdr := datap.pcHeader
626 if hdr.magic != abi.CurrentPCLnTabMagic || hdr.pad1 != 0 || hdr.pad2 != 0 ||
627 hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize {
628 println("runtime: pcHeader: magic=", hex(hdr.magic), "pad1=", hdr.pad1, "pad2=", hdr.pad2,
629 "minLC=", hdr.minLC, "ptrSize=", hdr.ptrSize, "pluginpath=", datap.pluginpath)
630 throw("invalid function symbol table")
631 }
632
633
634 nftab := len(datap.ftab) - 1
635 for i := 0; i < nftab; i++ {
636
637 if datap.ftab[i].entryoff > datap.ftab[i+1].entryoff {
638 f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
639 f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
640 f2name := "end"
641 if i+1 < nftab {
642 f2name = funcname(f2)
643 }
644 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)
645 for j := 0; j <= i; j++ {
646 println("\t", hex(datap.ftab[j].entryoff), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}))
647 }
648 if GOOS == "aix" && isarchive {
649 println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive")
650 }
651 throw("invalid runtime symbol table")
652 }
653 }
654
655 min := datap.textAddr(datap.ftab[0].entryoff)
656 max := datap.textAddr(datap.ftab[nftab].entryoff)
657 minpc := datap.minpc
658 maxpc := datap.maxpc
659 if GOARCH == "wasm" {
660
661
662
663
664 maxpc = alignUp(maxpc, 1<<16)
665 }
666 if minpc != min || maxpc != max {
667 println("minpc=", hex(minpc), "min=", hex(min), "maxpc=", hex(maxpc), "max=", hex(max))
668 throw("minpc or maxpc invalid")
669 }
670
671 for _, modulehash := range datap.modulehashes {
672 if modulehash.linktimehash != *modulehash.runtimehash {
673 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
674 throw("abi mismatch")
675 }
676 }
677 }
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697 func (md *moduledata) textAddr(off32 uint32) uintptr {
698 off := uintptr(off32)
699 if GOARCH == "wasm" {
700
701
702 off <<= 16
703 }
704 res := md.text + off
705 if len(md.textsectmap) > 1 {
706 for i, sect := range md.textsectmap {
707
708 if off >= sect.vaddr && off < sect.end || (i == len(md.textsectmap)-1 && off == sect.end) {
709 res = sect.baseaddr + off - sect.vaddr
710 break
711 }
712 }
713 if res > md.etext && GOARCH != "wasm" {
714 println("runtime: textAddr", hex(res), "out of range", hex(md.text), "-", hex(md.etext))
715 throw("runtime: text offset out of range")
716 }
717 }
718 return res
719 }
720
721
722
723
724
725
726
727 func (md *moduledata) textOff(pc uintptr) (uint32, bool) {
728 off := pc - md.text
729 if GOARCH == "wasm" {
730
731
732 off >>= 16
733 }
734 res := uint32(off)
735 if len(md.textsectmap) > 1 {
736 if GOARCH == "wasm" {
737 fatal("unexpected multiple text sections on Wasm")
738 }
739 for i, sect := range md.textsectmap {
740 if sect.baseaddr > pc {
741
742 return 0, false
743 }
744 end := sect.baseaddr + (sect.end - sect.vaddr)
745
746 if i == len(md.textsectmap)-1 {
747 end++
748 }
749 if pc < end {
750 res = uint32(pc - sect.baseaddr + sect.vaddr)
751 break
752 }
753 }
754 }
755 return res, true
756 }
757
758
759 func (md *moduledata) funcName(nameOff int32) string {
760 if nameOff == 0 {
761 return ""
762 }
763 return gostringnocopy(&md.funcnametab[nameOff])
764 }
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784 func FuncForPC(pc uintptr) *Func {
785 f := findfunc(pc)
786 if !f.valid() {
787 return nil
788 }
789
790
791
792
793 u, uf := newInlineUnwinder(f, pc)
794 if !u.isInlined(uf) {
795 return f._Func()
796 }
797 sf := u.srcFunc(uf)
798 file, line := u.fileLine(uf)
799 fi := &funcinl{
800 ones: ^uint32(0),
801 entry: f.entry(),
802 name: sf.name(),
803 file: file,
804 line: int32(line),
805 startLine: sf.startLine,
806 }
807 return (*Func)(unsafe.Pointer(fi))
808 }
809
810
811 func (f *Func) Name() string {
812 if f == nil {
813 return ""
814 }
815 fn := f.raw()
816 if fn.isInlined() {
817 fi := (*funcinl)(unsafe.Pointer(fn))
818 return funcNameForPrint(fi.name)
819 }
820 return funcNameForPrint(funcname(f.funcInfo()))
821 }
822
823
824 func (f *Func) Entry() uintptr {
825 fn := f.raw()
826 if fn.isInlined() {
827 fi := (*funcinl)(unsafe.Pointer(fn))
828 return fi.entry
829 }
830 return fn.funcInfo().entry()
831 }
832
833
834
835
836
837 func (f *Func) FileLine(pc uintptr) (file string, line int) {
838 fn := f.raw()
839 if fn.isInlined() {
840 fi := (*funcinl)(unsafe.Pointer(fn))
841 return fi.file, int(fi.line)
842 }
843
844
845 file, line32 := funcline1(f.funcInfo(), pc, false)
846 return file, int(line32)
847 }
848
849
850
851 func (f *Func) startLine() int32 {
852 fn := f.raw()
853 if fn.isInlined() {
854 fi := (*funcinl)(unsafe.Pointer(fn))
855 return fi.startLine
856 }
857 return fn.funcInfo().startLine
858 }
859
860
861
862
863
864
865
866 func findmoduledatap(pc uintptr) *moduledata {
867 for datap := &firstmoduledata; datap != nil; datap = datap.next {
868 if datap.minpc <= pc && pc < datap.maxpc {
869 return datap
870 }
871 }
872 return nil
873 }
874
875 type funcInfo struct {
876 *_func
877 datap *moduledata
878 }
879
880 func (f funcInfo) valid() bool {
881 return f._func != nil
882 }
883
884 func (f funcInfo) _Func() *Func {
885 return (*Func)(unsafe.Pointer(f._func))
886 }
887
888
889 func (f *_func) isInlined() bool {
890 return f.entryOff == ^uint32(0)
891 }
892
893
894
895
896
897
898
899
900
901
902 func (f funcInfo) entry() uintptr {
903 return f.datap.textAddr(f.entryOff)
904 }
905
906
907 func badFuncInfoEntry(funcInfo) uintptr
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924 func findfunc(pc uintptr) funcInfo {
925 datap := findmoduledatap(pc)
926 if datap == nil {
927 return funcInfo{}
928 }
929 const nsub = uintptr(len(findfuncbucket{}.subbuckets))
930
931 pcOff, ok := datap.textOff(pc)
932 if !ok {
933 return funcInfo{}
934 }
935
936 x := uintptr(pcOff) + datap.text - datap.minpc
937 if GOARCH == "wasm" {
938
939
940 x = uintptr(pcOff)<<16 + datap.text - datap.minpc
941 }
942 b := x / abi.FuncTabBucketSize
943 i := x % abi.FuncTabBucketSize / (abi.FuncTabBucketSize / nsub)
944
945 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
946 idx := ffb.idx + uint32(ffb.subbuckets[i])
947
948
949 for datap.ftab[idx+1].entryoff <= pcOff {
950 idx++
951 }
952
953 funcoff := datap.ftab[idx].funcoff
954 return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap}
955 }
956
957
958
959
960 type srcFunc struct {
961 datap *moduledata
962 nameOff int32
963 startLine int32
964 funcID abi.FuncID
965 }
966
967 func (f funcInfo) srcFunc() srcFunc {
968 if !f.valid() {
969 return srcFunc{}
970 }
971 return srcFunc{f.datap, f.nameOff, f.startLine, f.funcID}
972 }
973
974
975
976
977
978
979
980
981 func (s srcFunc) name() string {
982 if s.datap == nil {
983 return ""
984 }
985 return s.datap.funcName(s.nameOff)
986 }
987
988
989 func badSrcFuncName(srcFunc) string
990
991 type pcvalueCache struct {
992 entries [2][8]pcvalueCacheEnt
993 inUse int
994 }
995
996 type pcvalueCacheEnt struct {
997
998 targetpc uintptr
999 off uint32
1000
1001 val int32
1002 valPC uintptr
1003 }
1004
1005
1006
1007
1008
1009 func pcvalueCacheKey(targetpc uintptr) uintptr {
1010 return (targetpc / goarch.PtrSize) % uintptr(len(pcvalueCache{}.entries))
1011 }
1012
1013
1014 func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uintptr) {
1015
1016
1017 const debugCheckCache = false
1018
1019
1020 const skipCache = false
1021
1022 if off == 0 {
1023 return -1, 0
1024 }
1025
1026
1027
1028
1029 var checkVal int32
1030 var checkPC uintptr
1031 ck := pcvalueCacheKey(targetpc)
1032 if !skipCache {
1033 mp := acquirem()
1034 cache := &mp.pcvalueCache
1035
1036
1037
1038
1039 cache.inUse++
1040 if cache.inUse == 1 {
1041 for i := range cache.entries[ck] {
1042
1043
1044
1045
1046
1047 ent := &cache.entries[ck][i]
1048 if ent.off == off && ent.targetpc == targetpc {
1049 val, pc := ent.val, ent.valPC
1050 if debugCheckCache {
1051 checkVal, checkPC = ent.val, ent.valPC
1052 break
1053 } else {
1054 cache.inUse--
1055 releasem(mp)
1056 return val, pc
1057 }
1058 }
1059 }
1060 } else if debugCheckCache && (cache.inUse < 1 || cache.inUse > 2) {
1061
1062
1063 throw("cache.inUse out of range")
1064 }
1065 cache.inUse--
1066 releasem(mp)
1067 }
1068
1069 if !f.valid() {
1070 if strict && panicking.Load() == 0 {
1071 println("runtime: no module data for", hex(f.entry()))
1072 throw("no module data")
1073 }
1074 return -1, 0
1075 }
1076 datap := f.datap
1077 p := datap.pctab[off:]
1078 pc := f.entry()
1079 prevpc := pc
1080 val := int32(-1)
1081 for {
1082 var ok bool
1083 p, ok = step(p, &pc, &val, pc == f.entry())
1084 if !ok {
1085 break
1086 }
1087 if targetpc < pc {
1088
1089
1090
1091
1092
1093
1094 if debugCheckCache && checkPC != 0 {
1095 if checkVal != val || checkPC != prevpc {
1096 print("runtime: table value ", val, "@", prevpc, " != cache value ", checkVal, "@", checkPC, " at PC ", targetpc, " off ", off, "\n")
1097 throw("bad pcvalue cache")
1098 }
1099 } else {
1100 mp := acquirem()
1101 cache := &mp.pcvalueCache
1102 cache.inUse++
1103 if cache.inUse == 1 {
1104 e := &cache.entries[ck]
1105 ci := cheaprandn(uint32(len(cache.entries[ck])))
1106 e[ci] = e[0]
1107 e[0] = pcvalueCacheEnt{
1108 targetpc: targetpc,
1109 off: off,
1110 val: val,
1111 valPC: prevpc,
1112 }
1113 }
1114 cache.inUse--
1115 releasem(mp)
1116 }
1117
1118 return val, prevpc
1119 }
1120 prevpc = pc
1121 }
1122
1123
1124
1125 if panicking.Load() != 0 || !strict {
1126 return -1, 0
1127 }
1128
1129 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
1130
1131 p = datap.pctab[off:]
1132 pc = f.entry()
1133 val = -1
1134 for {
1135 var ok bool
1136 p, ok = step(p, &pc, &val, pc == f.entry())
1137 if !ok {
1138 break
1139 }
1140 print("\tvalue=", val, " until pc=", hex(pc), "\n")
1141 }
1142
1143 throw("invalid runtime symbol table")
1144 return -1, 0
1145 }
1146
1147 func funcname(f funcInfo) string {
1148 if !f.valid() {
1149 return ""
1150 }
1151 return f.datap.funcName(f.nameOff)
1152 }
1153
1154 func funcpkgpath(f funcInfo) string {
1155 name := funcNameForPrint(funcname(f))
1156 i := len(name) - 1
1157 for ; i > 0; i-- {
1158 if name[i] == '/' {
1159 break
1160 }
1161 }
1162 for ; i < len(name); i++ {
1163 if name[i] == '.' {
1164 break
1165 }
1166 }
1167 return name[:i]
1168 }
1169
1170 func funcfile(f funcInfo, fileno int32) string {
1171 datap := f.datap
1172 if !f.valid() {
1173 return "?"
1174 }
1175
1176 if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) {
1177 return gostringnocopy(&datap.filetab[fileoff])
1178 }
1179
1180 return "?"
1181 }
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192 func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
1193 datap := f.datap
1194 if !f.valid() {
1195 return "?", 0
1196 }
1197 fileno, _ := pcvalue(f, f.pcfile, targetpc, strict)
1198 line, _ = pcvalue(f, f.pcln, targetpc, strict)
1199 if fileno == -1 || line == -1 || int(fileno) >= len(datap.filetab) {
1200
1201 return "?", 0
1202 }
1203 file = funcfile(f, fileno)
1204 return
1205 }
1206
1207 func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
1208 return funcline1(f, targetpc, true)
1209 }
1210
1211 func funcspdelta(f funcInfo, targetpc uintptr) int32 {
1212 x, _ := pcvalue(f, f.pcsp, targetpc, true)
1213 if debugPcln && x&(goarch.PtrSize-1) != 0 {
1214 print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
1215 throw("bad spdelta")
1216 }
1217 return x
1218 }
1219
1220
1221 func funcMaxSPDelta(f funcInfo) int32 {
1222 datap := f.datap
1223 p := datap.pctab[f.pcsp:]
1224 pc := f.entry()
1225 val := int32(-1)
1226 most := int32(0)
1227 for {
1228 var ok bool
1229 p, ok = step(p, &pc, &val, pc == f.entry())
1230 if !ok {
1231 return most
1232 }
1233 most = max(most, val)
1234 }
1235 }
1236
1237 func pcdatastart(f funcInfo, table uint32) uint32 {
1238 return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
1239 }
1240
1241 func pcdatavalue(f funcInfo, table uint32, targetpc uintptr) int32 {
1242 if table >= f.npcdata {
1243 return -1
1244 }
1245 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, true)
1246 return r
1247 }
1248
1249 func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, strict bool) int32 {
1250 if table >= f.npcdata {
1251 return -1
1252 }
1253 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, strict)
1254 return r
1255 }
1256
1257
1258 func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) {
1259 if table >= f.npcdata {
1260 return -1, 0
1261 }
1262 return pcvalue(f, pcdatastart(f, table), targetpc, true)
1263 }
1264
1265
1266
1267 func funcdata(f funcInfo, i uint8) unsafe.Pointer {
1268 if i < 0 || i >= f.nfuncdata {
1269 return nil
1270 }
1271 base := f.datap.gofunc
1272 p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4
1273 off := *(*uint32)(unsafe.Pointer(p))
1274
1275
1276 var mask uintptr
1277 if off == ^uint32(0) {
1278 mask = 1
1279 }
1280 mask--
1281 raw := base + uintptr(off)
1282 return unsafe.Pointer(raw & mask)
1283 }
1284
1285
1286 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
1287
1288
1289 uvdelta := uint32(p[0])
1290 if uvdelta == 0 && !first {
1291 return nil, false
1292 }
1293 n := uint32(1)
1294 if uvdelta&0x80 != 0 {
1295 n, uvdelta = readvarint(p)
1296 }
1297 *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1))
1298 p = p[n:]
1299
1300 pcdelta := uint32(p[0])
1301 n = 1
1302 if pcdelta&0x80 != 0 {
1303 n, pcdelta = readvarint(p)
1304 }
1305 p = p[n:]
1306 *pc += uintptr(pcdelta * sys.PCQuantum)
1307 return p, true
1308 }
1309
1310
1311 func readvarint(p []byte) (read uint32, val uint32) {
1312 var v, shift, n uint32
1313 for {
1314 b := p[n]
1315 n++
1316 v |= uint32(b&0x7F) << (shift & 31)
1317 if b&0x80 == 0 {
1318 break
1319 }
1320 shift += 7
1321 }
1322 return n, v
1323 }
1324
1325 type stackmap struct {
1326 n int32
1327 nbit int32
1328 bytedata [1]byte
1329 }
1330
1331
1332 func stackmapdata(stkmap *stackmap, n int32) bitvector {
1333
1334
1335
1336 if stackDebug > 0 && (n < 0 || n >= stkmap.n) {
1337 throw("stackmapdata: index out of range")
1338 }
1339 return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))}
1340 }
1341
View as plain text