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