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