1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime 6 7 import "unsafe" 8 9 // NOTE: Func does not expose the actual unexported fields, because we return *Func 10 // values to users, and we want to keep them from being able to overwrite the data 11 // with (say) *f = Func{}. 12 // All code operating on a *Func must call raw to get the *_func instead. 13 14 // A Func represents a Go function in the running binary. 15 type Func struct { 16 opaque struct{} // unexported field to disallow conversions 17 } 18 19 func (f *Func) raw() *_func { 20 return (*_func)(unsafe.Pointer(f)) 21 } 22 23 // funcdata.h 24 const ( 25 _PCDATA_StackMapIndex = 0 26 _FUNCDATA_ArgsPointerMaps = 0 27 _FUNCDATA_LocalsPointerMaps = 1 28 _FUNCDATA_DeadValueMaps = 2 29 _ArgsSizeUnknown = -0x80000000 30 ) 31 32 // moduledata records information about the layout of the executable 33 // image. It is written by the linker. Any changes here must be 34 // matched changes to the code in cmd/internal/ld/symtab.go:symtab. 35 // moduledata is stored in read-only memory; none of the pointers here 36 // are visible to the garbage collector. 37 type moduledata struct { 38 pclntable []byte 39 ftab []functab 40 filetab []uint32 41 findfunctab uintptr 42 minpc, maxpc uintptr 43 44 text, etext uintptr 45 noptrdata, enoptrdata uintptr 46 data, edata uintptr 47 bss, ebss uintptr 48 noptrbss, enoptrbss uintptr 49 end, gcdata, gcbss uintptr 50 51 typelinks []*_type 52 53 modulename string 54 modulehashes []modulehash 55 56 gcdatamask, gcbssmask bitvector 57 58 next *moduledata 59 } 60 61 // For each shared library a module links against, the linker creates an entry in the 62 // moduledata.modulehashes slice containing the name of the module, the abi hash seen 63 // at link time and a pointer to the runtime abi hash. These are checked in 64 // moduledataverify1 below. 65 type modulehash struct { 66 modulename string 67 linktimehash string 68 runtimehash *string 69 } 70 71 var firstmoduledata moduledata // linker symbol 72 var lastmoduledatap *moduledata // linker symbol 73 74 type functab struct { 75 entry uintptr 76 funcoff uintptr 77 } 78 79 const minfunc = 16 // minimum function size 80 const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table 81 82 // findfunctab is an array of these structures. 83 // Each bucket represents 4096 bytes of the text segment. 84 // Each subbucket represents 256 bytes of the text segment. 85 // To find a function given a pc, locate the bucket and subbucket for 86 // that pc. Add together the idx and subbucket value to obtain a 87 // function index. Then scan the functab array starting at that 88 // index to find the target function. 89 // This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead. 90 type findfuncbucket struct { 91 idx uint32 92 subbuckets [16]byte 93 } 94 95 func moduledataverify() { 96 for datap := &firstmoduledata; datap != nil; datap = datap.next { 97 moduledataverify1(datap) 98 } 99 } 100 101 const debugPcln = false 102 103 func moduledataverify1(datap *moduledata) { 104 // See golang.org/s/go12symtab for header: 0xfffffffb, 105 // two zero bytes, a byte giving the PC quantum, 106 // and a byte giving the pointer width in bytes. 107 pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable)) 108 pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable)) 109 if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != _PCQuantum || pcln[7] != ptrSize { 110 println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7])) 111 throw("invalid function symbol table\n") 112 } 113 114 // ftab is lookup table for function by program counter. 115 nftab := len(datap.ftab) - 1 116 for i := 0; i < nftab; i++ { 117 // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function. 118 if datap.ftab[i].entry > datap.ftab[i+1].entry { 119 f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])) 120 f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])) 121 f2name := "end" 122 if i+1 < nftab { 123 f2name = funcname(f2) 124 } 125 println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name) 126 for j := 0; j <= i; j++ { 127 print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n") 128 } 129 throw("invalid runtime symbol table") 130 } 131 132 if debugPcln || nftab-i < 5 { 133 // Check a PC near but not at the very end. 134 // The very end might be just padding that is not covered by the tables. 135 // No architecture rounds function entries to more than 16 bytes, 136 // but if one came along we'd need to subtract more here. 137 // But don't use the next PC if it corresponds to a foreign object chunk 138 // (no pcln table, f2.pcln == 0). That chunk might have an alignment 139 // more than 16 bytes. 140 f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff])) 141 end := f.entry 142 if i+1 < nftab { 143 f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff])) 144 if f2.pcln != 0 { 145 end = f2.entry - 16 146 if end < f.entry { 147 end = f.entry 148 } 149 } 150 } 151 pcvalue(f, f.pcfile, end, true) 152 pcvalue(f, f.pcln, end, true) 153 pcvalue(f, f.pcsp, end, true) 154 } 155 } 156 157 if datap.minpc != datap.ftab[0].entry || 158 datap.maxpc != datap.ftab[nftab].entry { 159 throw("minpc or maxpc invalid") 160 } 161 162 for _, modulehash := range datap.modulehashes { 163 if modulehash.linktimehash != *modulehash.runtimehash { 164 println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename) 165 throw("abi mismatch") 166 } 167 } 168 } 169 170 // FuncForPC returns a *Func describing the function that contains the 171 // given program counter address, or else nil. 172 func FuncForPC(pc uintptr) *Func { 173 return (*Func)(unsafe.Pointer(findfunc(pc))) 174 } 175 176 // Name returns the name of the function. 177 func (f *Func) Name() string { 178 return funcname(f.raw()) 179 } 180 181 // Entry returns the entry address of the function. 182 func (f *Func) Entry() uintptr { 183 return f.raw().entry 184 } 185 186 // FileLine returns the file name and line number of the 187 // source code corresponding to the program counter pc. 188 // The result will not be accurate if pc is not a program 189 // counter within f. 190 func (f *Func) FileLine(pc uintptr) (file string, line int) { 191 // Pass strict=false here, because anyone can call this function, 192 // and they might just be wrong about targetpc belonging to f. 193 file, line32 := funcline1(f.raw(), pc, false) 194 return file, int(line32) 195 } 196 197 func findmoduledatap(pc uintptr) *moduledata { 198 for datap := &firstmoduledata; datap != nil; datap = datap.next { 199 if datap.minpc <= pc && pc <= datap.maxpc { 200 return datap 201 } 202 } 203 return nil 204 } 205 206 func findfunc(pc uintptr) *_func { 207 datap := findmoduledatap(pc) 208 if datap == nil { 209 return nil 210 } 211 const nsub = uintptr(len(findfuncbucket{}.subbuckets)) 212 213 x := pc - datap.minpc 214 b := x / pcbucketsize 215 i := x % pcbucketsize / (pcbucketsize / nsub) 216 217 ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{}))) 218 idx := ffb.idx + uint32(ffb.subbuckets[i]) 219 if pc < datap.ftab[idx].entry { 220 throw("findfunc: bad findfunctab entry") 221 } 222 223 // linear search to find func with pc >= entry. 224 for datap.ftab[idx+1].entry <= pc { 225 idx++ 226 } 227 return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])) 228 } 229 230 func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 { 231 if off == 0 { 232 return -1 233 } 234 datap := findmoduledatap(f.entry) // inefficient 235 if datap == nil { 236 if strict && panicking == 0 { 237 print("runtime: no module data for ", hex(f.entry), "\n") 238 throw("no module data") 239 } 240 return -1 241 } 242 p := datap.pclntable[off:] 243 pc := f.entry 244 val := int32(-1) 245 for { 246 var ok bool 247 p, ok = step(p, &pc, &val, pc == f.entry) 248 if !ok { 249 break 250 } 251 if targetpc < pc { 252 return val 253 } 254 } 255 256 // If there was a table, it should have covered all program counters. 257 // If not, something is wrong. 258 if panicking != 0 || !strict { 259 return -1 260 } 261 262 print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n") 263 264 p = datap.pclntable[off:] 265 pc = f.entry 266 val = -1 267 for { 268 var ok bool 269 p, ok = step(p, &pc, &val, pc == f.entry) 270 if !ok { 271 break 272 } 273 print("\tvalue=", val, " until pc=", hex(pc), "\n") 274 } 275 276 throw("invalid runtime symbol table") 277 return -1 278 } 279 280 func cfuncname(f *_func) *byte { 281 if f == nil || f.nameoff == 0 { 282 return nil 283 } 284 datap := findmoduledatap(f.entry) // inefficient 285 if datap == nil { 286 return nil 287 } 288 return (*byte)(unsafe.Pointer(&datap.pclntable[f.nameoff])) 289 } 290 291 func funcname(f *_func) string { 292 return gostringnocopy(cfuncname(f)) 293 } 294 295 func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) { 296 datap := findmoduledatap(f.entry) // inefficient 297 if datap == nil { 298 return "?", 0 299 } 300 fileno := int(pcvalue(f, f.pcfile, targetpc, strict)) 301 line = pcvalue(f, f.pcln, targetpc, strict) 302 if fileno == -1 || line == -1 || fileno >= len(datap.filetab) { 303 // print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n") 304 return "?", 0 305 } 306 file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]]) 307 return 308 } 309 310 func funcline(f *_func, targetpc uintptr) (file string, line int32) { 311 return funcline1(f, targetpc, true) 312 } 313 314 func funcspdelta(f *_func, targetpc uintptr) int32 { 315 x := pcvalue(f, f.pcsp, targetpc, true) 316 if x&(ptrSize-1) != 0 { 317 print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n") 318 } 319 return x 320 } 321 322 func pcdatavalue(f *_func, table int32, targetpc uintptr) int32 { 323 if table < 0 || table >= f.npcdata { 324 return -1 325 } 326 off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4)) 327 return pcvalue(f, off, targetpc, true) 328 } 329 330 func funcdata(f *_func, i int32) unsafe.Pointer { 331 if i < 0 || i >= f.nfuncdata { 332 return nil 333 } 334 p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4) 335 if ptrSize == 8 && uintptr(p)&4 != 0 { 336 if uintptr(unsafe.Pointer(f))&4 != 0 { 337 println("runtime: misaligned func", f) 338 } 339 p = add(p, 4) 340 } 341 return *(*unsafe.Pointer)(add(p, uintptr(i)*ptrSize)) 342 } 343 344 // step advances to the next pc, value pair in the encoded table. 345 func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) { 346 p, uvdelta := readvarint(p) 347 if uvdelta == 0 && !first { 348 return nil, false 349 } 350 if uvdelta&1 != 0 { 351 uvdelta = ^(uvdelta >> 1) 352 } else { 353 uvdelta >>= 1 354 } 355 vdelta := int32(uvdelta) 356 p, pcdelta := readvarint(p) 357 *pc += uintptr(pcdelta * _PCQuantum) 358 *val += vdelta 359 return p, true 360 } 361 362 // readvarint reads a varint from p. 363 func readvarint(p []byte) (newp []byte, val uint32) { 364 var v, shift uint32 365 for { 366 b := p[0] 367 p = p[1:] 368 v |= (uint32(b) & 0x7F) << shift 369 if b&0x80 == 0 { 370 break 371 } 372 shift += 7 373 } 374 return p, v 375 } 376 377 type stackmap struct { 378 n int32 // number of bitmaps 379 nbit int32 // number of bits in each bitmap 380 bytedata [1]byte // bitmaps, each starting on a 32-bit boundary 381 } 382 383 //go:nowritebarrier 384 func stackmapdata(stkmap *stackmap, n int32) bitvector { 385 if n < 0 || n >= stkmap.n { 386 throw("stackmapdata: index out of range") 387 } 388 return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))} 389 } 390