github.com/aloncn/graphics-go@v0.0.1/src/runtime/symtab.go (about)

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