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 if off == 0 {
985 return -1, 0
986 }
987
988
989
990
991 var checkVal int32
992 var checkPC uintptr
993 ck := pcvalueCacheKey(targetpc)
994 {
995 mp := acquirem()
996 cache := &mp.pcvalueCache
997
998
999
1000
1001 cache.inUse++
1002 if cache.inUse == 1 {
1003 for i := range cache.entries[ck] {
1004
1005
1006
1007
1008
1009 ent := &cache.entries[ck][i]
1010 if ent.off == off && ent.targetpc == targetpc {
1011 val, pc := ent.val, ent.valPC
1012 if debugCheckCache {
1013 checkVal, checkPC = ent.val, ent.valPC
1014 break
1015 } else {
1016 cache.inUse--
1017 releasem(mp)
1018 return val, pc
1019 }
1020 }
1021 }
1022 } else if debugCheckCache && (cache.inUse < 1 || cache.inUse > 2) {
1023
1024
1025 throw("cache.inUse out of range")
1026 }
1027 cache.inUse--
1028 releasem(mp)
1029 }
1030
1031 if !f.valid() {
1032 if strict && panicking.Load() == 0 {
1033 println("runtime: no module data for", hex(f.entry()))
1034 throw("no module data")
1035 }
1036 return -1, 0
1037 }
1038 datap := f.datap
1039 p := datap.pctab[off:]
1040 pc := f.entry()
1041 prevpc := pc
1042 val := int32(-1)
1043 for {
1044 var ok bool
1045 p, ok = step(p, &pc, &val, pc == f.entry())
1046 if !ok {
1047 break
1048 }
1049 if targetpc < pc {
1050
1051
1052
1053
1054
1055
1056 if debugCheckCache && checkPC != 0 {
1057 if checkVal != val || checkPC != prevpc {
1058 print("runtime: table value ", val, "@", prevpc, " != cache value ", checkVal, "@", checkPC, " at PC ", targetpc, " off ", off, "\n")
1059 throw("bad pcvalue cache")
1060 }
1061 } else {
1062 mp := acquirem()
1063 cache := &mp.pcvalueCache
1064 cache.inUse++
1065 if cache.inUse == 1 {
1066 e := &cache.entries[ck]
1067 ci := cheaprandn(uint32(len(cache.entries[ck])))
1068 e[ci] = e[0]
1069 e[0] = pcvalueCacheEnt{
1070 targetpc: targetpc,
1071 off: off,
1072 val: val,
1073 valPC: prevpc,
1074 }
1075 }
1076 cache.inUse--
1077 releasem(mp)
1078 }
1079
1080 return val, prevpc
1081 }
1082 prevpc = pc
1083 }
1084
1085
1086
1087 if panicking.Load() != 0 || !strict {
1088 return -1, 0
1089 }
1090
1091 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
1092
1093 p = datap.pctab[off:]
1094 pc = f.entry()
1095 val = -1
1096 for {
1097 var ok bool
1098 p, ok = step(p, &pc, &val, pc == f.entry())
1099 if !ok {
1100 break
1101 }
1102 print("\tvalue=", val, " until pc=", hex(pc), "\n")
1103 }
1104
1105 throw("invalid runtime symbol table")
1106 return -1, 0
1107 }
1108
1109 func funcname(f funcInfo) string {
1110 if !f.valid() {
1111 return ""
1112 }
1113 return f.datap.funcName(f.nameOff)
1114 }
1115
1116 func funcpkgpath(f funcInfo) string {
1117 name := funcNameForPrint(funcname(f))
1118 i := len(name) - 1
1119 for ; i > 0; i-- {
1120 if name[i] == '/' {
1121 break
1122 }
1123 }
1124 for ; i < len(name); i++ {
1125 if name[i] == '.' {
1126 break
1127 }
1128 }
1129 return name[:i]
1130 }
1131
1132 func funcfile(f funcInfo, fileno int32) string {
1133 datap := f.datap
1134 if !f.valid() {
1135 return "?"
1136 }
1137
1138 if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) {
1139 return gostringnocopy(&datap.filetab[fileoff])
1140 }
1141
1142 return "?"
1143 }
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154 func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
1155 datap := f.datap
1156 if !f.valid() {
1157 return "?", 0
1158 }
1159 fileno, _ := pcvalue(f, f.pcfile, targetpc, strict)
1160 line, _ = pcvalue(f, f.pcln, targetpc, strict)
1161 if fileno == -1 || line == -1 || int(fileno) >= len(datap.filetab) {
1162
1163 return "?", 0
1164 }
1165 file = funcfile(f, fileno)
1166 return
1167 }
1168
1169 func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
1170 return funcline1(f, targetpc, true)
1171 }
1172
1173 func funcspdelta(f funcInfo, targetpc uintptr) int32 {
1174 x, _ := pcvalue(f, f.pcsp, targetpc, true)
1175 if debugPcln && x&(goarch.PtrSize-1) != 0 {
1176 print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
1177 throw("bad spdelta")
1178 }
1179 return x
1180 }
1181
1182
1183 func funcMaxSPDelta(f funcInfo) int32 {
1184 datap := f.datap
1185 p := datap.pctab[f.pcsp:]
1186 pc := f.entry()
1187 val := int32(-1)
1188 most := int32(0)
1189 for {
1190 var ok bool
1191 p, ok = step(p, &pc, &val, pc == f.entry())
1192 if !ok {
1193 return most
1194 }
1195 most = max(most, val)
1196 }
1197 }
1198
1199 func pcdatastart(f funcInfo, table uint32) uint32 {
1200 return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
1201 }
1202
1203 func pcdatavalue(f funcInfo, table uint32, targetpc uintptr) int32 {
1204 if table >= f.npcdata {
1205 return -1
1206 }
1207 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, true)
1208 return r
1209 }
1210
1211 func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, strict bool) int32 {
1212 if table >= f.npcdata {
1213 return -1
1214 }
1215 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, strict)
1216 return r
1217 }
1218
1219
1220 func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) {
1221 if table >= f.npcdata {
1222 return -1, 0
1223 }
1224 return pcvalue(f, pcdatastart(f, table), targetpc, true)
1225 }
1226
1227
1228
1229 func funcdata(f funcInfo, i uint8) unsafe.Pointer {
1230 if i < 0 || i >= f.nfuncdata {
1231 return nil
1232 }
1233 base := f.datap.gofunc
1234 p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4
1235 off := *(*uint32)(unsafe.Pointer(p))
1236
1237
1238 var mask uintptr
1239 if off == ^uint32(0) {
1240 mask = 1
1241 }
1242 mask--
1243 raw := base + uintptr(off)
1244 return unsafe.Pointer(raw & mask)
1245 }
1246
1247
1248 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
1249
1250
1251 uvdelta := uint32(p[0])
1252 if uvdelta == 0 && !first {
1253 return nil, false
1254 }
1255 n := uint32(1)
1256 if uvdelta&0x80 != 0 {
1257 n, uvdelta = readvarint(p)
1258 }
1259 *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1))
1260 p = p[n:]
1261
1262 pcdelta := uint32(p[0])
1263 n = 1
1264 if pcdelta&0x80 != 0 {
1265 n, pcdelta = readvarint(p)
1266 }
1267 p = p[n:]
1268 *pc += uintptr(pcdelta * sys.PCQuantum)
1269 return p, true
1270 }
1271
1272
1273 func readvarint(p []byte) (read uint32, val uint32) {
1274 var v, shift, n uint32
1275 for {
1276 b := p[n]
1277 n++
1278 v |= uint32(b&0x7F) << (shift & 31)
1279 if b&0x80 == 0 {
1280 break
1281 }
1282 shift += 7
1283 }
1284 return n, v
1285 }
1286
1287 type stackmap struct {
1288 n int32
1289 nbit int32
1290 bytedata [1]byte
1291 }
1292
1293
1294 func stackmapdata(stkmap *stackmap, n int32) bitvector {
1295
1296
1297
1298 if stackDebug > 0 && (n < 0 || n >= stkmap.n) {
1299 throw("stackmapdata: index out of range")
1300 }
1301 return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))}
1302 }
1303
View as plain text