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