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