github.com/primecitizens/pcz/std@v0.2.1/core/abi/func.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 // 4 // Copyright 2017 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 package abi 9 10 import ( 11 "unsafe" 12 13 "github.com/primecitizens/pcz/std/core/mark" 14 ) 15 16 type FuncVal struct { 17 Fn uintptr 18 // variable-size, fn-specific data here 19 } 20 21 // Layout of in-memory per-function information prepared by linker 22 // See https://golang.org/s/go12symtab. 23 // Keep in sync with linker (../cmd/link/internal/ld/pcln.go:/pclntab) 24 // and with package debug/gosym and with symtab.go in package runtime. 25 // 26 // see $GOROOT/src/runtime/runtime2.go#type:_func 27 type Func struct { 28 _ mark.NotInHeap // Only in static data 29 30 entryOff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart 31 nameOff NameOff // function name, as index into moduledata.funcnametab. 32 33 args int32 // in/out args size 34 DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any. 35 36 PCSP uint32 37 PCFile uint32 38 PCLn uint32 39 npcdata uint32 40 cuOffset uint32 // runtime.cutab offset of this function's CU 41 StartLine int32 // line number of start of function (func keyword/TEXT directive) 42 FuncID FuncID // set for certain special runtime functions 43 Flag FuncFlag 44 _ [1]byte // pad 45 nfuncdata uint8 // must be last, must end on a uint32-aligned boundary 46 47 // The end of the struct is followed immediately by two variable-length 48 // arrays that reference the pcdata and funcdata locations for this 49 // function. 50 51 // pcdata contains the offset into moduledata.pctab for the start of 52 // that index's table. e.g., 53 // &moduledata.pctab[_func.pcdata[_PCDATA_UnsafePoint]] is the start of 54 // the unsafe point table. 55 // 56 // An offset of 0 indicates that there is no table. 57 // 58 // pcdata [npcdata]uint32 59 60 // funcdata contains the offset past moduledata.gofunc which contains a 61 // pointer to that index's funcdata. e.g., 62 // *(moduledata.gofunc + _func.funcdata[_FUNCDATA_ArgsPointerMaps]) is 63 // the argument pointer map. 64 // 65 // An offset of ^uint32(0) indicates that there is no entry. 66 // 67 // funcdata [nfuncdata]uint32 68 } 69 70 // IsInlined reports whether f should be re-interpreted as a *funcinl. 71 func (f *Func) IsInlined() bool { 72 return f.entryOff == ^uint32(0) // see comment for funcinl.ones 73 } 74 75 // Pseudo-Func that is returned for PCs that occur in inlined code. 76 // A *Func can be either a *_func or a *FuncInl, and they are distinguished 77 // by the first uintptr. 78 // 79 // TODO(austin): Can we merge this with inlinedCall? 80 type FuncInl struct { 81 ones uint32 // set to ^0 to distinguish from _func 82 entry uintptr // entry of the real (the "outermost") frame 83 name string 84 file string 85 line int32 86 startLine int32 87 } 88 89 type FuncInfo struct { 90 *Func 91 Datap *ModuleData 92 } 93 94 func (f FuncInfo) Valid() bool { 95 return f.Func != nil 96 } 97 98 // Name is something like "main.(*T).F". 99 func (f FuncInfo) Name() string { 100 if !f.Valid() { 101 return "" 102 } 103 104 return f.Datap.funcName(f.nameOff) 105 } 106 107 // Entry returns the entry PC for f. 108 func (f FuncInfo) Entry() uintptr { 109 return f.Datap.textAddr(f.entryOff) 110 } 111 112 // findfuncbucket is an array of these structures. 113 // Each bucket represents 4096 bytes of the text segment. 114 // Each subbucket represents 256 bytes of the text segment. 115 // To find a function given a pc, locate the bucket and subbucket for 116 // that pc. Add together the idx and subbucket value to obtain a 117 // function index. Then scan the functab array starting at that 118 // index to find the target function. 119 // This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead. 120 type findfuncbucket struct { 121 idx uint32 122 subbuckets [16]byte 123 } 124 125 // FindFunc looks up function metadata for a PC. 126 // 127 // It is nosplit because it's part of the isgoexception 128 // implementation. 129 // 130 //go:nosplit 131 func FindFunc(pc uintptr) FuncInfo { 132 datap := findModuleForPC(pc) 133 if datap == nil { 134 return FuncInfo{} 135 } 136 137 const nsub = uintptr(len(findfuncbucket{}.subbuckets)) 138 139 pcOff, ok := datap.textOff(pc) 140 if !ok { 141 return FuncInfo{} 142 } 143 144 x := uintptr(pcOff) + datap.Text - datap.MinPC // TODO: are datap.text and datap.minpc always equal? 145 b := x / pcbucketsize 146 i := x % pcbucketsize / (pcbucketsize / nsub) 147 148 ffb := (*findfuncbucket)(unsafe.Add(unsafe.Pointer(datap.FindFuncTab), b*unsafe.Sizeof(findfuncbucket{}))) 149 idx := ffb.idx + uint32(ffb.subbuckets[i]) 150 151 // Find the ftab entry. 152 for datap.FTab[idx+1].Entryoff <= pcOff { 153 idx++ 154 } 155 156 funcoff := datap.FTab[idx].Funcoff 157 return FuncInfo{ 158 Func: (*Func)(unsafe.Pointer(&datap.PCLnTable[funcoff])), 159 Datap: datap, 160 } 161 } 162 163 func findModuleForPC(pc uintptr) (md *ModuleData) { 164 for i, iter := 0, ModuleIter(0); ; i++ { 165 md, ok := iter.Nth(i) 166 if !ok { 167 break 168 } 169 170 if md.MinPC <= pc && pc < md.MaxPC { 171 return md 172 } 173 } 174 175 return nil 176 }