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