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