github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/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 "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  }