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