github.com/letsencrypt/go@v0.0.0-20160714163537-4054769a31f6/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  // Frames may be used to get function/file/line information for a
    13  // slice of PC values returned by Callers.
    14  type Frames struct {
    15  	callers []uintptr
    16  
    17  	// If previous caller in iteration was a panic, then
    18  	// ci.callers[0] is the address of the faulting instruction
    19  	// instead of the return address of the call.
    20  	wasPanic bool
    21  
    22  	// Frames to return for subsequent calls to the Next method.
    23  	// Used for non-Go frames.
    24  	frames *[]Frame
    25  }
    26  
    27  // Frame is the information returned by Frames for each call frame.
    28  type Frame struct {
    29  	// Program counter for this frame; multiple frames may have
    30  	// the same PC value.
    31  	PC uintptr
    32  
    33  	// Func for this frame; may be nil for non-Go code or fully
    34  	// inlined functions.
    35  	Func *Func
    36  
    37  	// Function name, file name, and line number for this call frame.
    38  	// May be the empty string or zero if not known.
    39  	// If Func is not nil then Function == Func.Name().
    40  	Function string
    41  	File     string
    42  	Line     int
    43  
    44  	// Entry point for the function; may be zero if not known.
    45  	// If Func is not nil then Entry == Func.Entry().
    46  	Entry uintptr
    47  }
    48  
    49  // CallersFrames takes a slice of PC values returned by Callers and
    50  // prepares to return function/file/line information.
    51  // Do not change the slice until you are done with the Frames.
    52  func CallersFrames(callers []uintptr) *Frames {
    53  	return &Frames{callers: callers}
    54  }
    55  
    56  // Next returns frame information for the next caller.
    57  // If more is false, there are no more callers (the Frame value is valid).
    58  func (ci *Frames) Next() (frame Frame, more bool) {
    59  	if ci.frames != nil {
    60  		// We have saved up frames to return.
    61  		f := (*ci.frames)[0]
    62  		if len(*ci.frames) == 1 {
    63  			ci.frames = nil
    64  		} else {
    65  			*ci.frames = (*ci.frames)[1:]
    66  		}
    67  		return f, ci.frames != nil || len(ci.callers) > 0
    68  	}
    69  
    70  	if len(ci.callers) == 0 {
    71  		ci.wasPanic = false
    72  		return Frame{}, false
    73  	}
    74  	pc := ci.callers[0]
    75  	ci.callers = ci.callers[1:]
    76  	more = len(ci.callers) > 0
    77  	f := FuncForPC(pc)
    78  	if f == nil {
    79  		ci.wasPanic = false
    80  		if cgoSymbolizer != nil {
    81  			return ci.cgoNext(pc, more)
    82  		}
    83  		return Frame{}, more
    84  	}
    85  
    86  	entry := f.Entry()
    87  	xpc := pc
    88  	if xpc > entry && !ci.wasPanic {
    89  		xpc--
    90  	}
    91  	file, line := f.FileLine(xpc)
    92  
    93  	function := f.Name()
    94  	ci.wasPanic = entry == sigpanicPC
    95  
    96  	frame = Frame{
    97  		PC:       xpc,
    98  		Func:     f,
    99  		Function: function,
   100  		File:     file,
   101  		Line:     line,
   102  		Entry:    entry,
   103  	}
   104  
   105  	return frame, more
   106  }
   107  
   108  // cgoNext returns frame information for pc, known to be a non-Go function,
   109  // using the cgoSymbolizer hook.
   110  func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) {
   111  	arg := cgoSymbolizerArg{pc: pc}
   112  	callCgoSymbolizer(&arg)
   113  
   114  	if arg.file == nil && arg.funcName == nil {
   115  		// No useful information from symbolizer.
   116  		return Frame{}, more
   117  	}
   118  
   119  	var frames []Frame
   120  	for {
   121  		frames = append(frames, Frame{
   122  			PC:       pc,
   123  			Func:     nil,
   124  			Function: gostring(arg.funcName),
   125  			File:     gostring(arg.file),
   126  			Line:     int(arg.lineno),
   127  			Entry:    arg.entry,
   128  		})
   129  		if arg.more == 0 {
   130  			break
   131  		}
   132  		callCgoSymbolizer(&arg)
   133  	}
   134  
   135  	// No more frames for this PC. Tell the symbolizer we are done.
   136  	// We don't try to maintain a single cgoSymbolizerArg for the
   137  	// whole use of Frames, because there would be no good way to tell
   138  	// the symbolizer when we are done.
   139  	arg.pc = 0
   140  	callCgoSymbolizer(&arg)
   141  
   142  	if len(frames) == 1 {
   143  		// Return a single frame.
   144  		return frames[0], more
   145  	}
   146  
   147  	// Return the first frame we saw and store the rest to be
   148  	// returned by later calls to Next.
   149  	rf := frames[0]
   150  	frames = frames[1:]
   151  	ci.frames = new([]Frame)
   152  	*ci.frames = frames
   153  	return rf, true
   154  }
   155  
   156  // NOTE: Func does not expose the actual unexported fields, because we return *Func
   157  // values to users, and we want to keep them from being able to overwrite the data
   158  // with (say) *f = Func{}.
   159  // All code operating on a *Func must call raw to get the *_func instead.
   160  
   161  // A Func represents a Go function in the running binary.
   162  type Func struct {
   163  	opaque struct{} // unexported field to disallow conversions
   164  }
   165  
   166  func (f *Func) raw() *_func {
   167  	return (*_func)(unsafe.Pointer(f))
   168  }
   169  
   170  // funcdata.h
   171  const (
   172  	_PCDATA_StackMapIndex       = 0
   173  	_FUNCDATA_ArgsPointerMaps   = 0
   174  	_FUNCDATA_LocalsPointerMaps = 1
   175  	_ArgsSizeUnknown            = -0x80000000
   176  )
   177  
   178  // moduledata records information about the layout of the executable
   179  // image. It is written by the linker. Any changes here must be
   180  // matched changes to the code in cmd/internal/ld/symtab.go:symtab.
   181  // moduledata is stored in read-only memory; none of the pointers here
   182  // are visible to the garbage collector.
   183  type moduledata struct {
   184  	pclntable    []byte
   185  	ftab         []functab
   186  	filetab      []uint32
   187  	findfunctab  uintptr
   188  	minpc, maxpc uintptr
   189  
   190  	text, etext           uintptr
   191  	noptrdata, enoptrdata uintptr
   192  	data, edata           uintptr
   193  	bss, ebss             uintptr
   194  	noptrbss, enoptrbss   uintptr
   195  	end, gcdata, gcbss    uintptr
   196  	types, etypes         uintptr
   197  
   198  	typelinks []int32 // offsets from types
   199  	itablinks []*itab
   200  
   201  	modulename   string
   202  	modulehashes []modulehash
   203  
   204  	gcdatamask, gcbssmask bitvector
   205  
   206  	typemap map[typeOff]*_type // offset to *_rtype in previous module
   207  
   208  	next *moduledata
   209  }
   210  
   211  // For each shared library a module links against, the linker creates an entry in the
   212  // moduledata.modulehashes slice containing the name of the module, the abi hash seen
   213  // at link time and a pointer to the runtime abi hash. These are checked in
   214  // moduledataverify1 below.
   215  type modulehash struct {
   216  	modulename   string
   217  	linktimehash string
   218  	runtimehash  *string
   219  }
   220  
   221  var firstmoduledata moduledata  // linker symbol
   222  var lastmoduledatap *moduledata // linker symbol
   223  
   224  type functab struct {
   225  	entry   uintptr
   226  	funcoff uintptr
   227  }
   228  
   229  const minfunc = 16                 // minimum function size
   230  const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
   231  
   232  // findfunctab is an array of these structures.
   233  // Each bucket represents 4096 bytes of the text segment.
   234  // Each subbucket represents 256 bytes of the text segment.
   235  // To find a function given a pc, locate the bucket and subbucket for
   236  // that pc. Add together the idx and subbucket value to obtain a
   237  // function index. Then scan the functab array starting at that
   238  // index to find the target function.
   239  // This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
   240  type findfuncbucket struct {
   241  	idx        uint32
   242  	subbuckets [16]byte
   243  }
   244  
   245  func moduledataverify() {
   246  	for datap := &firstmoduledata; datap != nil; datap = datap.next {
   247  		moduledataverify1(datap)
   248  	}
   249  }
   250  
   251  const debugPcln = false
   252  
   253  func moduledataverify1(datap *moduledata) {
   254  	// See golang.org/s/go12symtab for header: 0xfffffffb,
   255  	// two zero bytes, a byte giving the PC quantum,
   256  	// and a byte giving the pointer width in bytes.
   257  	pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
   258  	pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
   259  	if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != sys.PCQuantum || pcln[7] != sys.PtrSize {
   260  		println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
   261  		throw("invalid function symbol table\n")
   262  	}
   263  
   264  	// ftab is lookup table for function by program counter.
   265  	nftab := len(datap.ftab) - 1
   266  	var pcCache pcvalueCache
   267  	for i := 0; i < nftab; i++ {
   268  		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
   269  		if datap.ftab[i].entry > datap.ftab[i+1].entry {
   270  			f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
   271  			f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
   272  			f2name := "end"
   273  			if i+1 < nftab {
   274  				f2name = funcname(f2)
   275  			}
   276  			println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
   277  			for j := 0; j <= i; j++ {
   278  				print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
   279  			}
   280  			throw("invalid runtime symbol table")
   281  		}
   282  
   283  		if debugPcln || nftab-i < 5 {
   284  			// Check a PC near but not at the very end.
   285  			// The very end might be just padding that is not covered by the tables.
   286  			// No architecture rounds function entries to more than 16 bytes,
   287  			// but if one came along we'd need to subtract more here.
   288  			// But don't use the next PC if it corresponds to a foreign object chunk
   289  			// (no pcln table, f2.pcln == 0). That chunk might have an alignment
   290  			// more than 16 bytes.
   291  			f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
   292  			end := f.entry
   293  			if i+1 < nftab {
   294  				f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
   295  				if f2.pcln != 0 {
   296  					end = f2.entry - 16
   297  					if end < f.entry {
   298  						end = f.entry
   299  					}
   300  				}
   301  			}
   302  			pcvalue(f, f.pcfile, end, &pcCache, true)
   303  			pcvalue(f, f.pcln, end, &pcCache, true)
   304  			pcvalue(f, f.pcsp, end, &pcCache, true)
   305  		}
   306  	}
   307  
   308  	if datap.minpc != datap.ftab[0].entry ||
   309  		datap.maxpc != datap.ftab[nftab].entry {
   310  		throw("minpc or maxpc invalid")
   311  	}
   312  
   313  	for _, modulehash := range datap.modulehashes {
   314  		if modulehash.linktimehash != *modulehash.runtimehash {
   315  			println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
   316  			throw("abi mismatch")
   317  		}
   318  	}
   319  }
   320  
   321  // FuncForPC returns a *Func describing the function that contains the
   322  // given program counter address, or else nil.
   323  func FuncForPC(pc uintptr) *Func {
   324  	return (*Func)(unsafe.Pointer(findfunc(pc)))
   325  }
   326  
   327  // Name returns the name of the function.
   328  func (f *Func) Name() string {
   329  	return funcname(f.raw())
   330  }
   331  
   332  // Entry returns the entry address of the function.
   333  func (f *Func) Entry() uintptr {
   334  	return f.raw().entry
   335  }
   336  
   337  // FileLine returns the file name and line number of the
   338  // source code corresponding to the program counter pc.
   339  // The result will not be accurate if pc is not a program
   340  // counter within f.
   341  func (f *Func) FileLine(pc uintptr) (file string, line int) {
   342  	// Pass strict=false here, because anyone can call this function,
   343  	// and they might just be wrong about targetpc belonging to f.
   344  	file, line32 := funcline1(f.raw(), pc, false)
   345  	return file, int(line32)
   346  }
   347  
   348  func findmoduledatap(pc uintptr) *moduledata {
   349  	for datap := &firstmoduledata; datap != nil; datap = datap.next {
   350  		if datap.minpc <= pc && pc < datap.maxpc {
   351  			return datap
   352  		}
   353  	}
   354  	return nil
   355  }
   356  
   357  func findfunc(pc uintptr) *_func {
   358  	datap := findmoduledatap(pc)
   359  	if datap == nil {
   360  		return nil
   361  	}
   362  	const nsub = uintptr(len(findfuncbucket{}.subbuckets))
   363  
   364  	x := pc - datap.minpc
   365  	b := x / pcbucketsize
   366  	i := x % pcbucketsize / (pcbucketsize / nsub)
   367  
   368  	ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
   369  	idx := ffb.idx + uint32(ffb.subbuckets[i])
   370  	if pc < datap.ftab[idx].entry {
   371  		throw("findfunc: bad findfunctab entry")
   372  	}
   373  
   374  	// linear search to find func with pc >= entry.
   375  	for datap.ftab[idx+1].entry <= pc {
   376  		idx++
   377  	}
   378  	return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
   379  }
   380  
   381  type pcvalueCache struct {
   382  	entries [16]pcvalueCacheEnt
   383  }
   384  
   385  type pcvalueCacheEnt struct {
   386  	// targetpc and off together are the key of this cache entry.
   387  	targetpc uintptr
   388  	off      int32
   389  	// val is the value of this cached pcvalue entry.
   390  	val int32
   391  }
   392  
   393  func pcvalue(f *_func, off int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
   394  	if off == 0 {
   395  		return -1
   396  	}
   397  
   398  	// Check the cache. This speeds up walks of deep stacks, which
   399  	// tend to have the same recursive functions over and over.
   400  	//
   401  	// This cache is small enough that full associativity is
   402  	// cheaper than doing the hashing for a less associative
   403  	// cache.
   404  	if cache != nil {
   405  		for _, ent := range cache.entries {
   406  			// We check off first because we're more
   407  			// likely to have multiple entries with
   408  			// different offsets for the same targetpc
   409  			// than the other way around, so we'll usually
   410  			// fail in the first clause.
   411  			if ent.off == off && ent.targetpc == targetpc {
   412  				return ent.val
   413  			}
   414  		}
   415  	}
   416  
   417  	datap := findmoduledatap(f.entry) // inefficient
   418  	if datap == nil {
   419  		if strict && panicking == 0 {
   420  			print("runtime: no module data for ", hex(f.entry), "\n")
   421  			throw("no module data")
   422  		}
   423  		return -1
   424  	}
   425  	p := datap.pclntable[off:]
   426  	pc := f.entry
   427  	val := int32(-1)
   428  	for {
   429  		var ok bool
   430  		p, ok = step(p, &pc, &val, pc == f.entry)
   431  		if !ok {
   432  			break
   433  		}
   434  		if targetpc < pc {
   435  			// Replace a random entry in the cache. Random
   436  			// replacement prevents a performance cliff if
   437  			// a recursive stack's cycle is slightly
   438  			// larger than the cache.
   439  			if cache != nil {
   440  				ci := fastrand1() % uint32(len(cache.entries))
   441  				cache.entries[ci] = pcvalueCacheEnt{
   442  					targetpc: targetpc,
   443  					off:      off,
   444  					val:      val,
   445  				}
   446  			}
   447  
   448  			return val
   449  		}
   450  	}
   451  
   452  	// If there was a table, it should have covered all program counters.
   453  	// If not, something is wrong.
   454  	if panicking != 0 || !strict {
   455  		return -1
   456  	}
   457  
   458  	print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
   459  
   460  	p = datap.pclntable[off:]
   461  	pc = f.entry
   462  	val = -1
   463  	for {
   464  		var ok bool
   465  		p, ok = step(p, &pc, &val, pc == f.entry)
   466  		if !ok {
   467  			break
   468  		}
   469  		print("\tvalue=", val, " until pc=", hex(pc), "\n")
   470  	}
   471  
   472  	throw("invalid runtime symbol table")
   473  	return -1
   474  }
   475  
   476  func cfuncname(f *_func) *byte {
   477  	if f == nil || f.nameoff == 0 {
   478  		return nil
   479  	}
   480  	datap := findmoduledatap(f.entry) // inefficient
   481  	if datap == nil {
   482  		return nil
   483  	}
   484  	return &datap.pclntable[f.nameoff]
   485  }
   486  
   487  func funcname(f *_func) string {
   488  	return gostringnocopy(cfuncname(f))
   489  }
   490  
   491  func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
   492  	datap := findmoduledatap(f.entry) // inefficient
   493  	if datap == nil {
   494  		return "?", 0
   495  	}
   496  	fileno := int(pcvalue(f, f.pcfile, targetpc, nil, strict))
   497  	line = pcvalue(f, f.pcln, targetpc, nil, strict)
   498  	if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
   499  		// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
   500  		return "?", 0
   501  	}
   502  	file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
   503  	return
   504  }
   505  
   506  func funcline(f *_func, targetpc uintptr) (file string, line int32) {
   507  	return funcline1(f, targetpc, true)
   508  }
   509  
   510  func funcspdelta(f *_func, targetpc uintptr, cache *pcvalueCache) int32 {
   511  	x := pcvalue(f, f.pcsp, targetpc, cache, true)
   512  	if x&(sys.PtrSize-1) != 0 {
   513  		print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
   514  	}
   515  	return x
   516  }
   517  
   518  func pcdatavalue(f *_func, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
   519  	if table < 0 || table >= f.npcdata {
   520  		return -1
   521  	}
   522  	off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
   523  	return pcvalue(f, off, targetpc, cache, true)
   524  }
   525  
   526  func funcdata(f *_func, i int32) unsafe.Pointer {
   527  	if i < 0 || i >= f.nfuncdata {
   528  		return nil
   529  	}
   530  	p := add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(f.npcdata)*4)
   531  	if sys.PtrSize == 8 && uintptr(p)&4 != 0 {
   532  		if uintptr(unsafe.Pointer(f))&4 != 0 {
   533  			println("runtime: misaligned func", f)
   534  		}
   535  		p = add(p, 4)
   536  	}
   537  	return *(*unsafe.Pointer)(add(p, uintptr(i)*sys.PtrSize))
   538  }
   539  
   540  // step advances to the next pc, value pair in the encoded table.
   541  func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) {
   542  	p, uvdelta := readvarint(p)
   543  	if uvdelta == 0 && !first {
   544  		return nil, false
   545  	}
   546  	if uvdelta&1 != 0 {
   547  		uvdelta = ^(uvdelta >> 1)
   548  	} else {
   549  		uvdelta >>= 1
   550  	}
   551  	vdelta := int32(uvdelta)
   552  	p, pcdelta := readvarint(p)
   553  	*pc += uintptr(pcdelta * sys.PCQuantum)
   554  	*val += vdelta
   555  	return p, true
   556  }
   557  
   558  // readvarint reads a varint from p.
   559  func readvarint(p []byte) (newp []byte, val uint32) {
   560  	var v, shift uint32
   561  	for {
   562  		b := p[0]
   563  		p = p[1:]
   564  		v |= (uint32(b) & 0x7F) << shift
   565  		if b&0x80 == 0 {
   566  			break
   567  		}
   568  		shift += 7
   569  	}
   570  	return p, v
   571  }
   572  
   573  type stackmap struct {
   574  	n        int32   // number of bitmaps
   575  	nbit     int32   // number of bits in each bitmap
   576  	bytedata [1]byte // bitmaps, each starting on a 32-bit boundary
   577  }
   578  
   579  //go:nowritebarrier
   580  func stackmapdata(stkmap *stackmap, n int32) bitvector {
   581  	if n < 0 || n >= stkmap.n {
   582  		throw("stackmapdata: index out of range")
   583  	}
   584  	return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))}
   585  }