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 uint32
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
426 textsectmap []textsect
427 typelinks []int32
428 itablinks []*itab
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[typeOff]*_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[typeOff]*_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 != 0xfffffff1 || 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 maxpc = alignUp(maxpc, 1<<16)
663 }
664 if minpc != min || maxpc != max {
665 println("minpc=", hex(minpc), "min=", hex(min), "maxpc=", hex(maxpc), "max=", hex(max))
666 throw("minpc or maxpc invalid")
667 }
668
669 for _, modulehash := range datap.modulehashes {
670 if modulehash.linktimehash != *modulehash.runtimehash {
671 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
672 throw("abi mismatch")
673 }
674 }
675 }
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695 func (md *moduledata) textAddr(off32 uint32) uintptr {
696 off := uintptr(off32)
697 res := md.text + off
698 if len(md.textsectmap) > 1 {
699 for i, sect := range md.textsectmap {
700
701 if off >= sect.vaddr && off < sect.end || (i == len(md.textsectmap)-1 && off == sect.end) {
702 res = sect.baseaddr + off - sect.vaddr
703 break
704 }
705 }
706 if res > md.etext && GOARCH != "wasm" {
707 println("runtime: textAddr", hex(res), "out of range", hex(md.text), "-", hex(md.etext))
708 throw("runtime: text offset out of range")
709 }
710 }
711 if GOARCH == "wasm" {
712
713
714 res <<= 16
715 }
716 return res
717 }
718
719
720
721
722
723
724
725 func (md *moduledata) textOff(pc uintptr) (uint32, bool) {
726 off := pc - md.text
727 if GOARCH == "wasm" {
728
729
730 off >>= 16
731 }
732 res := uint32(off)
733 if len(md.textsectmap) > 1 {
734 if GOARCH == "wasm" {
735 fatal("unexpected multiple text sections on Wasm")
736 }
737 for i, sect := range md.textsectmap {
738 if sect.baseaddr > pc {
739
740 return 0, false
741 }
742 end := sect.baseaddr + (sect.end - sect.vaddr)
743
744 if i == len(md.textsectmap)-1 {
745 end++
746 }
747 if pc < end {
748 res = uint32(pc - sect.baseaddr + sect.vaddr)
749 break
750 }
751 }
752 }
753 return res, true
754 }
755
756
757 func (md *moduledata) funcName(nameOff int32) string {
758 if nameOff == 0 {
759 return ""
760 }
761 return gostringnocopy(&md.funcnametab[nameOff])
762 }
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782 func FuncForPC(pc uintptr) *Func {
783 f := findfunc(pc)
784 if !f.valid() {
785 return nil
786 }
787
788
789
790
791 u, uf := newInlineUnwinder(f, pc)
792 if !u.isInlined(uf) {
793 return f._Func()
794 }
795 sf := u.srcFunc(uf)
796 file, line := u.fileLine(uf)
797 fi := &funcinl{
798 ones: ^uint32(0),
799 entry: f.entry(),
800 name: sf.name(),
801 file: file,
802 line: int32(line),
803 startLine: sf.startLine,
804 }
805 return (*Func)(unsafe.Pointer(fi))
806 }
807
808
809 func (f *Func) Name() string {
810 if f == nil {
811 return ""
812 }
813 fn := f.raw()
814 if fn.isInlined() {
815 fi := (*funcinl)(unsafe.Pointer(fn))
816 return funcNameForPrint(fi.name)
817 }
818 return funcNameForPrint(funcname(f.funcInfo()))
819 }
820
821
822 func (f *Func) Entry() uintptr {
823 fn := f.raw()
824 if fn.isInlined() {
825 fi := (*funcinl)(unsafe.Pointer(fn))
826 return fi.entry
827 }
828 return fn.funcInfo().entry()
829 }
830
831
832
833
834
835 func (f *Func) FileLine(pc uintptr) (file string, line int) {
836 fn := f.raw()
837 if fn.isInlined() {
838 fi := (*funcinl)(unsafe.Pointer(fn))
839 return fi.file, int(fi.line)
840 }
841
842
843 file, line32 := funcline1(f.funcInfo(), pc, false)
844 return file, int(line32)
845 }
846
847
848
849 func (f *Func) startLine() int32 {
850 fn := f.raw()
851 if fn.isInlined() {
852 fi := (*funcinl)(unsafe.Pointer(fn))
853 return fi.startLine
854 }
855 return fn.funcInfo().startLine
856 }
857
858
859
860
861
862
863
864 func findmoduledatap(pc uintptr) *moduledata {
865 for datap := &firstmoduledata; datap != nil; datap = datap.next {
866 if datap.minpc <= pc && pc < datap.maxpc {
867 return datap
868 }
869 }
870 return nil
871 }
872
873 type funcInfo struct {
874 *_func
875 datap *moduledata
876 }
877
878 func (f funcInfo) valid() bool {
879 return f._func != nil
880 }
881
882 func (f funcInfo) _Func() *Func {
883 return (*Func)(unsafe.Pointer(f._func))
884 }
885
886
887 func (f *_func) isInlined() bool {
888 return f.entryOff == ^uint32(0)
889 }
890
891
892
893
894
895
896
897
898
899
900 func (f funcInfo) entry() uintptr {
901 return f.datap.textAddr(f.entryOff)
902 }
903
904
905 func badFuncInfoEntry(funcInfo) uintptr
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922 func findfunc(pc uintptr) funcInfo {
923 datap := findmoduledatap(pc)
924 if datap == nil {
925 return funcInfo{}
926 }
927 const nsub = uintptr(len(findfuncbucket{}.subbuckets))
928
929 pcOff, ok := datap.textOff(pc)
930 if !ok {
931 return funcInfo{}
932 }
933
934 x := uintptr(pcOff) + datap.text - datap.minpc
935 if GOARCH == "wasm" {
936
937
938 x = uintptr(pcOff)<<16 + datap.text - datap.minpc
939 }
940 b := x / abi.FuncTabBucketSize
941 i := x % abi.FuncTabBucketSize / (abi.FuncTabBucketSize / nsub)
942
943 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
944 idx := ffb.idx + uint32(ffb.subbuckets[i])
945
946
947 for datap.ftab[idx+1].entryoff <= pcOff {
948 idx++
949 }
950
951 funcoff := datap.ftab[idx].funcoff
952 return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap}
953 }
954
955
956
957
958 type srcFunc struct {
959 datap *moduledata
960 nameOff int32
961 startLine int32
962 funcID abi.FuncID
963 }
964
965 func (f funcInfo) srcFunc() srcFunc {
966 if !f.valid() {
967 return srcFunc{}
968 }
969 return srcFunc{f.datap, f.nameOff, f.startLine, f.funcID}
970 }
971
972
973
974
975
976
977
978
979 func (s srcFunc) name() string {
980 if s.datap == nil {
981 return ""
982 }
983 return s.datap.funcName(s.nameOff)
984 }
985
986
987 func badSrcFuncName(srcFunc) string
988
989 type pcvalueCache struct {
990 entries [2][8]pcvalueCacheEnt
991 inUse int
992 }
993
994 type pcvalueCacheEnt struct {
995
996 targetpc uintptr
997 off uint32
998
999 val int32
1000 valPC uintptr
1001 }
1002
1003
1004
1005
1006
1007 func pcvalueCacheKey(targetpc uintptr) uintptr {
1008 return (targetpc / goarch.PtrSize) % uintptr(len(pcvalueCache{}.entries))
1009 }
1010
1011
1012 func pcvalue(f funcInfo, off uint32, targetpc uintptr, strict bool) (int32, uintptr) {
1013
1014
1015 const debugCheckCache = false
1016
1017
1018 const skipCache = false
1019
1020 if off == 0 {
1021 return -1, 0
1022 }
1023
1024
1025
1026
1027 var checkVal int32
1028 var checkPC uintptr
1029 ck := pcvalueCacheKey(targetpc)
1030 if !skipCache {
1031 mp := acquirem()
1032 cache := &mp.pcvalueCache
1033
1034
1035
1036
1037 cache.inUse++
1038 if cache.inUse == 1 {
1039 for i := range cache.entries[ck] {
1040
1041
1042
1043
1044
1045 ent := &cache.entries[ck][i]
1046 if ent.off == off && ent.targetpc == targetpc {
1047 val, pc := ent.val, ent.valPC
1048 if debugCheckCache {
1049 checkVal, checkPC = ent.val, ent.valPC
1050 break
1051 } else {
1052 cache.inUse--
1053 releasem(mp)
1054 return val, pc
1055 }
1056 }
1057 }
1058 } else if debugCheckCache && (cache.inUse < 1 || cache.inUse > 2) {
1059
1060
1061 throw("cache.inUse out of range")
1062 }
1063 cache.inUse--
1064 releasem(mp)
1065 }
1066
1067 if !f.valid() {
1068 if strict && panicking.Load() == 0 {
1069 println("runtime: no module data for", hex(f.entry()))
1070 throw("no module data")
1071 }
1072 return -1, 0
1073 }
1074 datap := f.datap
1075 p := datap.pctab[off:]
1076 pc := f.entry()
1077 prevpc := pc
1078 val := int32(-1)
1079 for {
1080 var ok bool
1081 p, ok = step(p, &pc, &val, pc == f.entry())
1082 if !ok {
1083 break
1084 }
1085 if targetpc < pc {
1086
1087
1088
1089
1090
1091
1092 if debugCheckCache && checkPC != 0 {
1093 if checkVal != val || checkPC != prevpc {
1094 print("runtime: table value ", val, "@", prevpc, " != cache value ", checkVal, "@", checkPC, " at PC ", targetpc, " off ", off, "\n")
1095 throw("bad pcvalue cache")
1096 }
1097 } else {
1098 mp := acquirem()
1099 cache := &mp.pcvalueCache
1100 cache.inUse++
1101 if cache.inUse == 1 {
1102 e := &cache.entries[ck]
1103 ci := cheaprandn(uint32(len(cache.entries[ck])))
1104 e[ci] = e[0]
1105 e[0] = pcvalueCacheEnt{
1106 targetpc: targetpc,
1107 off: off,
1108 val: val,
1109 valPC: prevpc,
1110 }
1111 }
1112 cache.inUse--
1113 releasem(mp)
1114 }
1115
1116 return val, prevpc
1117 }
1118 prevpc = pc
1119 }
1120
1121
1122
1123 if panicking.Load() != 0 || !strict {
1124 return -1, 0
1125 }
1126
1127 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
1128
1129 p = datap.pctab[off:]
1130 pc = f.entry()
1131 val = -1
1132 for {
1133 var ok bool
1134 p, ok = step(p, &pc, &val, pc == f.entry())
1135 if !ok {
1136 break
1137 }
1138 print("\tvalue=", val, " until pc=", hex(pc), "\n")
1139 }
1140
1141 throw("invalid runtime symbol table")
1142 return -1, 0
1143 }
1144
1145 func funcname(f funcInfo) string {
1146 if !f.valid() {
1147 return ""
1148 }
1149 return f.datap.funcName(f.nameOff)
1150 }
1151
1152 func funcpkgpath(f funcInfo) string {
1153 name := funcNameForPrint(funcname(f))
1154 i := len(name) - 1
1155 for ; i > 0; i-- {
1156 if name[i] == '/' {
1157 break
1158 }
1159 }
1160 for ; i < len(name); i++ {
1161 if name[i] == '.' {
1162 break
1163 }
1164 }
1165 return name[:i]
1166 }
1167
1168 func funcfile(f funcInfo, fileno int32) string {
1169 datap := f.datap
1170 if !f.valid() {
1171 return "?"
1172 }
1173
1174 if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) {
1175 return gostringnocopy(&datap.filetab[fileoff])
1176 }
1177
1178 return "?"
1179 }
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190 func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
1191 datap := f.datap
1192 if !f.valid() {
1193 return "?", 0
1194 }
1195 fileno, _ := pcvalue(f, f.pcfile, targetpc, strict)
1196 line, _ = pcvalue(f, f.pcln, targetpc, strict)
1197 if fileno == -1 || line == -1 || int(fileno) >= len(datap.filetab) {
1198
1199 return "?", 0
1200 }
1201 file = funcfile(f, fileno)
1202 return
1203 }
1204
1205 func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
1206 return funcline1(f, targetpc, true)
1207 }
1208
1209 func funcspdelta(f funcInfo, targetpc uintptr) int32 {
1210 x, _ := pcvalue(f, f.pcsp, targetpc, true)
1211 if debugPcln && x&(goarch.PtrSize-1) != 0 {
1212 print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
1213 throw("bad spdelta")
1214 }
1215 return x
1216 }
1217
1218
1219 func funcMaxSPDelta(f funcInfo) int32 {
1220 datap := f.datap
1221 p := datap.pctab[f.pcsp:]
1222 pc := f.entry()
1223 val := int32(-1)
1224 most := int32(0)
1225 for {
1226 var ok bool
1227 p, ok = step(p, &pc, &val, pc == f.entry())
1228 if !ok {
1229 return most
1230 }
1231 most = max(most, val)
1232 }
1233 }
1234
1235 func pcdatastart(f funcInfo, table uint32) uint32 {
1236 return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
1237 }
1238
1239 func pcdatavalue(f funcInfo, table uint32, targetpc uintptr) int32 {
1240 if table >= f.npcdata {
1241 return -1
1242 }
1243 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, true)
1244 return r
1245 }
1246
1247 func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, strict bool) int32 {
1248 if table >= f.npcdata {
1249 return -1
1250 }
1251 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, strict)
1252 return r
1253 }
1254
1255
1256 func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) {
1257 if table >= f.npcdata {
1258 return -1, 0
1259 }
1260 return pcvalue(f, pcdatastart(f, table), targetpc, true)
1261 }
1262
1263
1264
1265 func funcdata(f funcInfo, i uint8) unsafe.Pointer {
1266 if i < 0 || i >= f.nfuncdata {
1267 return nil
1268 }
1269 base := f.datap.gofunc
1270 p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4
1271 off := *(*uint32)(unsafe.Pointer(p))
1272
1273
1274 var mask uintptr
1275 if off == ^uint32(0) {
1276 mask = 1
1277 }
1278 mask--
1279 raw := base + uintptr(off)
1280 return unsafe.Pointer(raw & mask)
1281 }
1282
1283
1284 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
1285
1286
1287 uvdelta := uint32(p[0])
1288 if uvdelta == 0 && !first {
1289 return nil, false
1290 }
1291 n := uint32(1)
1292 if uvdelta&0x80 != 0 {
1293 n, uvdelta = readvarint(p)
1294 }
1295 *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1))
1296 p = p[n:]
1297
1298 pcdelta := uint32(p[0])
1299 n = 1
1300 if pcdelta&0x80 != 0 {
1301 n, pcdelta = readvarint(p)
1302 }
1303 p = p[n:]
1304 *pc += uintptr(pcdelta * sys.PCQuantum)
1305 return p, true
1306 }
1307
1308
1309 func readvarint(p []byte) (read uint32, val uint32) {
1310 var v, shift, n uint32
1311 for {
1312 b := p[n]
1313 n++
1314 v |= uint32(b&0x7F) << (shift & 31)
1315 if b&0x80 == 0 {
1316 break
1317 }
1318 shift += 7
1319 }
1320 return n, v
1321 }
1322
1323 type stackmap struct {
1324 n int32
1325 nbit int32
1326 bytedata [1]byte
1327 }
1328
1329
1330 func stackmapdata(stkmap *stackmap, n int32) bitvector {
1331
1332
1333
1334 if stackDebug > 0 && (n < 0 || n >= stkmap.n) {
1335 throw("stackmapdata: index out of range")
1336 }
1337 return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))}
1338 }
1339
View as plain text