github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/loader/funcdata.go (about) 1 /** 2 * Copyright 2023 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package loader 18 19 import ( 20 "encoding" 21 "encoding/binary" 22 "fmt" 23 "reflect" 24 "strings" 25 "sync" 26 "unsafe" 27 ) 28 29 const ( 30 _MinLC uint8 = 1 31 _PtrSize uint8 = 8 32 ) 33 34 const ( 35 _N_FUNCDATA = 8 36 _INVALID_FUNCDATA_OFFSET = ^uint32(0) 37 _FUNC_SIZE = unsafe.Sizeof(_func{}) 38 39 _MINFUNC = 16 // minimum size for a function 40 _BUCKETSIZE = 256 * _MINFUNC 41 _SUBBUCKETS = 16 42 _SUB_BUCKETSIZE = _BUCKETSIZE / _SUBBUCKETS 43 ) 44 45 // Note: This list must match the list in runtime/symtab.go. 46 const ( 47 FuncFlag_TOPFRAME = 1 << iota 48 FuncFlag_SPWRITE 49 FuncFlag_ASM 50 ) 51 52 // PCDATA and FUNCDATA table indexes. 53 // 54 // See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go. 55 const ( 56 _FUNCDATA_ArgsPointerMaps = 0 57 _FUNCDATA_LocalsPointerMaps = 1 58 _FUNCDATA_StackObjects = 2 59 _FUNCDATA_InlTree = 3 60 _FUNCDATA_OpenCodedDeferInfo = 4 61 _FUNCDATA_ArgInfo = 5 62 _FUNCDATA_ArgLiveInfo = 6 63 _FUNCDATA_WrapInfo = 7 64 65 // ArgsSizeUnknown is set in Func.argsize to mark all functions 66 // whose argument size is unknown (C vararg functions, and 67 // assembly code without an explicit specification). 68 // This value is generated by the compiler, assembler, or linker. 69 ArgsSizeUnknown = -0x80000000 70 ) 71 72 // moduledata used to cache the funcdata and findfuncbucket of one module 73 var moduleCache = struct { 74 m map[*moduledata][]byte 75 sync.Mutex 76 }{ 77 m: make(map[*moduledata][]byte), 78 } 79 80 // Func contains information about a function. 81 type Func struct { 82 ID uint8 // see runtime/symtab.go 83 Flag uint8 // see runtime/symtab.go 84 ArgsSize int32 // args byte size 85 EntryOff uint32 // start pc, offset to moduledata.text 86 TextSize uint32 // size of func text 87 DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any. 88 FileIndex uint32 // index into filetab 89 Name string // name of function 90 91 // PC data 92 Pcsp *Pcdata // PC -> SP delta 93 Pcfile *Pcdata // PC -> file index 94 Pcline *Pcdata // PC -> line number 95 PcUnsafePoint *Pcdata // PC -> unsafe point, must be PCDATA_UnsafePointSafe or PCDATA_UnsafePointUnsafe 96 PcStackMapIndex *Pcdata // PC -> stack map index, relative to ArgsPointerMaps and LocalsPointerMaps 97 PcInlTreeIndex *Pcdata // PC -> inlining tree index, relative to InlTree 98 PcArgLiveIndex *Pcdata // PC -> arg live index, relative to ArgLiveInfo 99 100 // Func data, must implement encoding.BinaryMarshaler 101 ArgsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap 102 LocalsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap 103 StackObjects encoding.BinaryMarshaler 104 InlTree encoding.BinaryMarshaler 105 OpenCodedDeferInfo encoding.BinaryMarshaler 106 ArgInfo encoding.BinaryMarshaler 107 ArgLiveInfo encoding.BinaryMarshaler 108 WrapInfo encoding.BinaryMarshaler 109 } 110 111 func getOffsetOf(data interface{}, field string) uintptr { 112 t := reflect.TypeOf(data) 113 fv, ok := t.FieldByName(field) 114 if !ok { 115 panic(fmt.Sprintf("field %s not found in struct %s", field, t.Name())) 116 } 117 return fv.Offset 118 } 119 120 func rnd(v int64, r int64) int64 { 121 if r <= 0 { 122 return v 123 } 124 v += r - 1 125 c := v % r 126 if c < 0 { 127 c += r 128 } 129 v -= c 130 return v 131 } 132 133 var ( 134 byteOrder binary.ByteOrder = binary.LittleEndian 135 ) 136 137 func funcNameParts(name string) (string, string, string) { 138 i := strings.IndexByte(name, '[') 139 if i < 0 { 140 return name, "", "" 141 } 142 // TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5. 143 j := len(name) - 1 144 for j > i && name[j] != ']' { 145 j-- 146 } 147 if j <= i { 148 return name, "", "" 149 } 150 return name[:i], "[...]", name[j+1:] 151 } 152 153 // func name table format: 154 // 155 // nameOff[0] -> namePartA namePartB namePartC \x00 156 // nameOff[1] -> namePartA namePartB namePartC \x00 157 // ... 158 func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) { 159 offs = make([]int32, len(funcs)) 160 offset := 1 161 tab = []byte{0} 162 163 for i, f := range funcs { 164 offs[i] = int32(offset) 165 166 a, b, c := funcNameParts(f.Name) 167 tab = append(tab, a...) 168 tab = append(tab, b...) 169 tab = append(tab, c...) 170 tab = append(tab, 0) 171 offset += len(a) + len(b) + len(c) + 1 172 } 173 174 return 175 } 176 177 // CU table format: 178 // 179 // cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1] 180 // cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1] 181 // ... 182 // 183 // file name table format: 184 // 185 // filetabOffset[0] -> CUs[0].fileNames[0] \x00 186 // ... 187 // filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00 188 // ... 189 // filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00 190 func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) { 191 cuOffsets = make([]uint32, len(cus)) 192 cuOffset := 0 193 fileOffset := 0 194 195 for i, cu := range cus { 196 cuOffsets[i] = uint32(cuOffset) 197 198 for _, name := range cu.fileNames { 199 cutab = append(cutab, uint32(fileOffset)) 200 201 fileOffset += len(name) + 1 202 filetab = append(filetab, name...) 203 filetab = append(filetab, 0) 204 } 205 206 cuOffset += len(cu.fileNames) 207 } 208 209 return 210 } 211 212 func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) { 213 fstart = len(*out) 214 *out = append(*out, byte(0)) 215 offs := uint32(1) 216 217 funcdataOffs = make([][]uint32, len(funcs)) 218 for i, f := range funcs { 219 220 var writer = func(fd encoding.BinaryMarshaler) { 221 var ab []byte 222 var err error 223 if fd != nil { 224 ab, err = fd.MarshalBinary() 225 if err != nil { 226 panic(err) 227 } 228 funcdataOffs[i] = append(funcdataOffs[i], offs) 229 } else { 230 ab = []byte{0} 231 funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET) 232 } 233 *out = append(*out, ab...) 234 offs += uint32(len(ab)) 235 } 236 237 writer(f.ArgsPointerMaps) 238 writer(f.LocalsPointerMaps) 239 writer(f.StackObjects) 240 writer(f.InlTree) 241 writer(f.OpenCodedDeferInfo) 242 writer(f.ArgInfo) 243 writer(f.ArgLiveInfo) 244 writer(f.WrapInfo) 245 } 246 return 247 }