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