Source file
src/runtime/symtab.go
Documentation: runtime
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
500 func activeModules() []*moduledata {
501 p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
502 if p == nil {
503 return nil
504 }
505 return *p
506 }
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526 func modulesinit() {
527 modules := new([]*moduledata)
528 for md := &firstmoduledata; md != nil; md = md.next {
529 if md.bad {
530 continue
531 }
532 *modules = append(*modules, md)
533 if md.gcdatamask == (bitvector{}) {
534 scanDataSize := md.edata - md.data
535 md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), scanDataSize)
536 scanBSSSize := md.ebss - md.bss
537 md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), scanBSSSize)
538 gcController.addGlobals(int64(scanDataSize + scanBSSSize))
539 }
540 }
541
542
543
544
545
546
547
548
549
550
551 for i, md := range *modules {
552 if md.hasmain != 0 {
553 (*modules)[0] = md
554 (*modules)[i] = &firstmoduledata
555 break
556 }
557 }
558
559 atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
560 }
561
562 type functab struct {
563 entryoff uint32
564 funcoff uint32
565 }
566
567
568
569 type textsect struct {
570 vaddr uintptr
571 end uintptr
572 baseaddr uintptr
573 }
574
575 const minfunc = 16
576 const pcbucketsize = 256 * minfunc
577
578
579
580
581
582
583
584
585
586 type findfuncbucket struct {
587 idx uint32
588 subbuckets [16]byte
589 }
590
591 func moduledataverify() {
592 for datap := &firstmoduledata; datap != nil; datap = datap.next {
593 moduledataverify1(datap)
594 }
595 }
596
597 const debugPcln = false
598
599 func moduledataverify1(datap *moduledata) {
600
601 hdr := datap.pcHeader
602 if hdr.magic != 0xfffffff0 || hdr.pad1 != 0 || hdr.pad2 != 0 ||
603 hdr.minLC != sys.PCQuantum || hdr.ptrSize != goarch.PtrSize || hdr.textStart != datap.text {
604 println("runtime: pcHeader: magic=", hex(hdr.magic), "pad1=", hdr.pad1, "pad2=", hdr.pad2,
605 "minLC=", hdr.minLC, "ptrSize=", hdr.ptrSize, "pcHeader.textStart=", hex(hdr.textStart),
606 "text=", hex(datap.text), "pluginpath=", datap.pluginpath)
607 throw("invalid function symbol table")
608 }
609
610
611 nftab := len(datap.ftab) - 1
612 for i := 0; i < nftab; i++ {
613
614 if datap.ftab[i].entryoff > datap.ftab[i+1].entryoff {
615 f1 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])), datap}
616 f2 := funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])), datap}
617 f2name := "end"
618 if i+1 < nftab {
619 f2name = funcname(f2)
620 }
621 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)
622 for j := 0; j <= i; j++ {
623 println("\t", hex(datap.ftab[j].entryoff), funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}))
624 }
625 if GOOS == "aix" && isarchive {
626 println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive")
627 }
628 throw("invalid runtime symbol table")
629 }
630 }
631
632 min := datap.textAddr(datap.ftab[0].entryoff)
633 max := datap.textAddr(datap.ftab[nftab].entryoff)
634 if datap.minpc != min || datap.maxpc != max {
635 println("minpc=", hex(datap.minpc), "min=", hex(min), "maxpc=", hex(datap.maxpc), "max=", hex(max))
636 throw("minpc or maxpc invalid")
637 }
638
639 for _, modulehash := range datap.modulehashes {
640 if modulehash.linktimehash != *modulehash.runtimehash {
641 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
642 throw("abi mismatch")
643 }
644 }
645 }
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665 func (md *moduledata) textAddr(off32 uint32) uintptr {
666 off := uintptr(off32)
667 res := md.text + off
668 if len(md.textsectmap) > 1 {
669 for i, sect := range md.textsectmap {
670
671 if off >= sect.vaddr && off < sect.end || (i == len(md.textsectmap)-1 && off == sect.end) {
672 res = sect.baseaddr + off - sect.vaddr
673 break
674 }
675 }
676 if res > md.etext && GOARCH != "wasm" {
677 println("runtime: textAddr", hex(res), "out of range", hex(md.text), "-", hex(md.etext))
678 throw("runtime: text offset out of range")
679 }
680 }
681 return res
682 }
683
684
685
686
687
688
689
690 func (md *moduledata) textOff(pc uintptr) (uint32, bool) {
691 res := uint32(pc - md.text)
692 if len(md.textsectmap) > 1 {
693 for i, sect := range md.textsectmap {
694 if sect.baseaddr > pc {
695
696 return 0, false
697 }
698 end := sect.baseaddr + (sect.end - sect.vaddr)
699
700 if i == len(md.textsectmap) {
701 end++
702 }
703 if pc < end {
704 res = uint32(pc - sect.baseaddr + sect.vaddr)
705 break
706 }
707 }
708 }
709 return res, true
710 }
711
712
713
714
715
716
717
718 func FuncForPC(pc uintptr) *Func {
719 f := findfunc(pc)
720 if !f.valid() {
721 return nil
722 }
723 if inldata := funcdata(f, _FUNCDATA_InlTree); inldata != nil {
724
725
726
727
728 if ix := pcdatavalue1(f, _PCDATA_InlTreeIndex, pc, nil, false); ix >= 0 {
729 inltree := (*[1 << 20]inlinedCall)(inldata)
730 name := funcnameFromNameoff(f, inltree[ix].func_)
731 file, line := funcline(f, pc)
732 fi := &funcinl{
733 ones: ^uint32(0),
734 entry: f.entry(),
735 name: name,
736 file: file,
737 line: int(line),
738 }
739 return (*Func)(unsafe.Pointer(fi))
740 }
741 }
742 return f._Func()
743 }
744
745
746 func (f *Func) Name() string {
747 if f == nil {
748 return ""
749 }
750 fn := f.raw()
751 if fn.isInlined() {
752 fi := (*funcinl)(unsafe.Pointer(fn))
753 return fi.name
754 }
755 return funcname(f.funcInfo())
756 }
757
758
759 func (f *Func) Entry() uintptr {
760 fn := f.raw()
761 if fn.isInlined() {
762 fi := (*funcinl)(unsafe.Pointer(fn))
763 return fi.entry
764 }
765 return fn.funcInfo().entry()
766 }
767
768
769
770
771
772 func (f *Func) FileLine(pc uintptr) (file string, line int) {
773 fn := f.raw()
774 if fn.isInlined() {
775 fi := (*funcinl)(unsafe.Pointer(fn))
776 return fi.file, fi.line
777 }
778
779
780 file, line32 := funcline1(f.funcInfo(), pc, false)
781 return file, int(line32)
782 }
783
784
785
786
787
788
789
790 func findmoduledatap(pc uintptr) *moduledata {
791 for datap := &firstmoduledata; datap != nil; datap = datap.next {
792 if datap.minpc <= pc && pc < datap.maxpc {
793 return datap
794 }
795 }
796 return nil
797 }
798
799 type funcInfo struct {
800 *_func
801 datap *moduledata
802 }
803
804 func (f funcInfo) valid() bool {
805 return f._func != nil
806 }
807
808 func (f funcInfo) _Func() *Func {
809 return (*Func)(unsafe.Pointer(f._func))
810 }
811
812
813 func (f *_func) isInlined() bool {
814 return f.entryoff == ^uint32(0)
815 }
816
817
818 func (f funcInfo) entry() uintptr {
819 return f.datap.textAddr(f.entryoff)
820 }
821
822
823
824
825
826
827
828 func findfunc(pc uintptr) funcInfo {
829 datap := findmoduledatap(pc)
830 if datap == nil {
831 return funcInfo{}
832 }
833 const nsub = uintptr(len(findfuncbucket{}.subbuckets))
834
835 pcOff, ok := datap.textOff(pc)
836 if !ok {
837 return funcInfo{}
838 }
839
840 x := uintptr(pcOff) + datap.text - datap.minpc
841 b := x / pcbucketsize
842 i := x % pcbucketsize / (pcbucketsize / nsub)
843
844 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
845 idx := ffb.idx + uint32(ffb.subbuckets[i])
846
847
848 for datap.ftab[idx+1].entryoff <= pcOff {
849 idx++
850 }
851
852 funcoff := datap.ftab[idx].funcoff
853 return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap}
854 }
855
856 type pcvalueCache struct {
857 entries [2][8]pcvalueCacheEnt
858 }
859
860 type pcvalueCacheEnt struct {
861
862 targetpc uintptr
863 off uint32
864
865 val int32
866 }
867
868
869
870
871
872 func pcvalueCacheKey(targetpc uintptr) uintptr {
873 return (targetpc / goarch.PtrSize) % uintptr(len(pcvalueCache{}.entries))
874 }
875
876
877
878 func pcvalue(f funcInfo, off uint32, targetpc uintptr, cache *pcvalueCache, strict bool) (int32, uintptr) {
879 if off == 0 {
880 return -1, 0
881 }
882
883
884
885
886
887
888
889 if cache != nil {
890 x := pcvalueCacheKey(targetpc)
891 for i := range cache.entries[x] {
892
893
894
895
896
897 ent := &cache.entries[x][i]
898 if ent.off == off && ent.targetpc == targetpc {
899 return ent.val, 0
900 }
901 }
902 }
903
904 if !f.valid() {
905 if strict && panicking == 0 {
906 println("runtime: no module data for", hex(f.entry()))
907 throw("no module data")
908 }
909 return -1, 0
910 }
911 datap := f.datap
912 p := datap.pctab[off:]
913 pc := f.entry()
914 prevpc := pc
915 val := int32(-1)
916 for {
917 var ok bool
918 p, ok = step(p, &pc, &val, pc == f.entry())
919 if !ok {
920 break
921 }
922 if targetpc < pc {
923
924
925
926
927
928
929 if cache != nil {
930 x := pcvalueCacheKey(targetpc)
931 e := &cache.entries[x]
932 ci := fastrandn(uint32(len(cache.entries[x])))
933 e[ci] = e[0]
934 e[0] = pcvalueCacheEnt{
935 targetpc: targetpc,
936 off: off,
937 val: val,
938 }
939 }
940
941 return val, prevpc
942 }
943 prevpc = pc
944 }
945
946
947
948 if panicking != 0 || !strict {
949 return -1, 0
950 }
951
952 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
953
954 p = datap.pctab[off:]
955 pc = f.entry()
956 val = -1
957 for {
958 var ok bool
959 p, ok = step(p, &pc, &val, pc == f.entry())
960 if !ok {
961 break
962 }
963 print("\tvalue=", val, " until pc=", hex(pc), "\n")
964 }
965
966 throw("invalid runtime symbol table")
967 return -1, 0
968 }
969
970 func cfuncname(f funcInfo) *byte {
971 if !f.valid() || f.nameoff == 0 {
972 return nil
973 }
974 return &f.datap.funcnametab[f.nameoff]
975 }
976
977 func funcname(f funcInfo) string {
978 return gostringnocopy(cfuncname(f))
979 }
980
981 func funcpkgpath(f funcInfo) string {
982 name := funcname(f)
983 i := len(name) - 1
984 for ; i > 0; i-- {
985 if name[i] == '/' {
986 break
987 }
988 }
989 for ; i < len(name); i++ {
990 if name[i] == '.' {
991 break
992 }
993 }
994 return name[:i]
995 }
996
997 func cfuncnameFromNameoff(f funcInfo, nameoff int32) *byte {
998 if !f.valid() {
999 return nil
1000 }
1001 return &f.datap.funcnametab[nameoff]
1002 }
1003
1004 func funcnameFromNameoff(f funcInfo, nameoff int32) string {
1005 return gostringnocopy(cfuncnameFromNameoff(f, nameoff))
1006 }
1007
1008 func funcfile(f funcInfo, fileno int32) string {
1009 datap := f.datap
1010 if !f.valid() {
1011 return "?"
1012 }
1013
1014 if fileoff := datap.cutab[f.cuOffset+uint32(fileno)]; fileoff != ^uint32(0) {
1015 return gostringnocopy(&datap.filetab[fileoff])
1016 }
1017
1018 return "?"
1019 }
1020
1021 func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) {
1022 datap := f.datap
1023 if !f.valid() {
1024 return "?", 0
1025 }
1026 fileno, _ := pcvalue(f, f.pcfile, targetpc, nil, strict)
1027 line, _ = pcvalue(f, f.pcln, targetpc, nil, strict)
1028 if fileno == -1 || line == -1 || int(fileno) >= len(datap.filetab) {
1029
1030 return "?", 0
1031 }
1032 file = funcfile(f, fileno)
1033 return
1034 }
1035
1036 func funcline(f funcInfo, targetpc uintptr) (file string, line int32) {
1037 return funcline1(f, targetpc, true)
1038 }
1039
1040 func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
1041 x, _ := pcvalue(f, f.pcsp, targetpc, cache, true)
1042 if debugPcln && x&(goarch.PtrSize-1) != 0 {
1043 print("invalid spdelta ", funcname(f), " ", hex(f.entry()), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
1044 throw("bad spdelta")
1045 }
1046 return x
1047 }
1048
1049
1050 func funcMaxSPDelta(f funcInfo) int32 {
1051 datap := f.datap
1052 p := datap.pctab[f.pcsp:]
1053 pc := f.entry()
1054 val := int32(-1)
1055 max := int32(0)
1056 for {
1057 var ok bool
1058 p, ok = step(p, &pc, &val, pc == f.entry())
1059 if !ok {
1060 return max
1061 }
1062 if val > max {
1063 max = val
1064 }
1065 }
1066 }
1067
1068 func pcdatastart(f funcInfo, table uint32) uint32 {
1069 return *(*uint32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
1070 }
1071
1072 func pcdatavalue(f funcInfo, table uint32, targetpc uintptr, cache *pcvalueCache) int32 {
1073 if table >= f.npcdata {
1074 return -1
1075 }
1076 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, cache, true)
1077 return r
1078 }
1079
1080 func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
1081 if table >= f.npcdata {
1082 return -1
1083 }
1084 r, _ := pcvalue(f, pcdatastart(f, table), targetpc, cache, strict)
1085 return r
1086 }
1087
1088
1089
1090 func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) {
1091 if table >= f.npcdata {
1092 return -1, 0
1093 }
1094 return pcvalue(f, pcdatastart(f, table), targetpc, nil, true)
1095 }
1096
1097
1098
1099 func funcdata(f funcInfo, i uint8) unsafe.Pointer {
1100 if i < 0 || i >= f.nfuncdata {
1101 return nil
1102 }
1103 base := f.datap.gofunc
1104 p := uintptr(unsafe.Pointer(&f.nfuncdata)) + unsafe.Sizeof(f.nfuncdata) + uintptr(f.npcdata)*4 + uintptr(i)*4
1105 off := *(*uint32)(unsafe.Pointer(p))
1106
1107
1108 var mask uintptr
1109 if off == ^uint32(0) {
1110 mask = 1
1111 }
1112 mask--
1113 raw := base + uintptr(off)
1114 return unsafe.Pointer(raw & mask)
1115 }
1116
1117
1118 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
1119
1120
1121 uvdelta := uint32(p[0])
1122 if uvdelta == 0 && !first {
1123 return nil, false
1124 }
1125 n := uint32(1)
1126 if uvdelta&0x80 != 0 {
1127 n, uvdelta = readvarint(p)
1128 }
1129 *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1))
1130 p = p[n:]
1131
1132 pcdelta := uint32(p[0])
1133 n = 1
1134 if pcdelta&0x80 != 0 {
1135 n, pcdelta = readvarint(p)
1136 }
1137 p = p[n:]
1138 *pc += uintptr(pcdelta * sys.PCQuantum)
1139 return p, true
1140 }
1141
1142
1143 func readvarint(p []byte) (read uint32, val uint32) {
1144 var v, shift, n uint32
1145 for {
1146 b := p[n]
1147 n++
1148 v |= uint32(b&0x7F) << (shift & 31)
1149 if b&0x80 == 0 {
1150 break
1151 }
1152 shift += 7
1153 }
1154 return n, v
1155 }
1156
1157 type stackmap struct {
1158 n int32
1159 nbit int32
1160 bytedata [1]byte
1161 }
1162
1163
1164 func stackmapdata(stkmap *stackmap, n int32) bitvector {
1165
1166
1167
1168 if stackDebug > 0 && (n < 0 || n >= stkmap.n) {
1169 throw("stackmapdata: index out of range")
1170 }
1171 return bitvector{stkmap.nbit, addb(&stkmap.bytedata[0], uintptr(n*((stkmap.nbit+7)>>3)))}
1172 }
1173
1174
1175 type inlinedCall struct {
1176 parent int16
1177 funcID funcID
1178 _ byte
1179 file int32
1180 line int32
1181 func_ int32
1182 parentPc int32
1183 }
1184
View as plain text