Home | History | Annotate | Download | only in runtime
      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