github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/cmd/link/internal/ld/pcln.go (about)

     1  // Copyright 2013 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 ld
     6  
     7  import (
     8  	"cmd/internal/objabi"
     9  	"cmd/internal/src"
    10  	"cmd/link/internal/sym"
    11  	"log"
    12  	"os"
    13  	"path/filepath"
    14  )
    15  
    16  // iteration over encoded pcdata tables.
    17  
    18  func getvarint(pp *[]byte) uint32 {
    19  	v := uint32(0)
    20  	p := *pp
    21  	for shift := 0; ; shift += 7 {
    22  		v |= uint32(p[0]&0x7F) << uint(shift)
    23  		tmp4 := p
    24  		p = p[1:]
    25  		if tmp4[0]&0x80 == 0 {
    26  			break
    27  		}
    28  	}
    29  
    30  	*pp = p
    31  	return v
    32  }
    33  
    34  func pciternext(it *Pciter) {
    35  	it.pc = it.nextpc
    36  	if it.done != 0 {
    37  		return
    38  	}
    39  	if -cap(it.p) >= -cap(it.d.P[len(it.d.P):]) {
    40  		it.done = 1
    41  		return
    42  	}
    43  
    44  	// value delta
    45  	v := getvarint(&it.p)
    46  
    47  	if v == 0 && it.start == 0 {
    48  		it.done = 1
    49  		return
    50  	}
    51  
    52  	it.start = 0
    53  	dv := int32(v>>1) ^ (int32(v<<31) >> 31)
    54  	it.value += dv
    55  
    56  	// pc delta
    57  	v = getvarint(&it.p)
    58  
    59  	it.nextpc = it.pc + v*it.pcscale
    60  }
    61  
    62  func pciterinit(ctxt *Link, it *Pciter, d *sym.Pcdata) {
    63  	it.d = *d
    64  	it.p = it.d.P
    65  	it.pc = 0
    66  	it.nextpc = 0
    67  	it.value = -1
    68  	it.start = 1
    69  	it.done = 0
    70  	it.pcscale = uint32(ctxt.Arch.MinLC)
    71  	pciternext(it)
    72  }
    73  
    74  func addvarint(d *sym.Pcdata, val uint32) {
    75  	n := int32(0)
    76  	for v := val; v >= 0x80; v >>= 7 {
    77  		n++
    78  	}
    79  	n++
    80  
    81  	old := len(d.P)
    82  	for cap(d.P) < len(d.P)+int(n) {
    83  		d.P = append(d.P[:cap(d.P)], 0)
    84  	}
    85  	d.P = d.P[:old+int(n)]
    86  
    87  	p := d.P[old:]
    88  	var v uint32
    89  	for v = val; v >= 0x80; v >>= 7 {
    90  		p[0] = byte(v | 0x80)
    91  		p = p[1:]
    92  	}
    93  	p[0] = byte(v)
    94  }
    95  
    96  func addpctab(ctxt *Link, ftab *sym.Symbol, off int32, d *sym.Pcdata) int32 {
    97  	var start int32
    98  	if len(d.P) > 0 {
    99  		start = int32(len(ftab.P))
   100  		ftab.AddBytes(d.P)
   101  	}
   102  	return int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(start)))
   103  }
   104  
   105  func ftabaddstring(ctxt *Link, ftab *sym.Symbol, s string) int32 {
   106  	n := int32(len(s)) + 1
   107  	start := int32(len(ftab.P))
   108  	ftab.Grow(int64(start) + int64(n) + 1)
   109  	copy(ftab.P[start:], s)
   110  	return start
   111  }
   112  
   113  // numberfile assigns a file number to the file if it hasn't been assigned already.
   114  func numberfile(ctxt *Link, file *sym.Symbol) {
   115  	if file.Type != sym.SFILEPATH {
   116  		ctxt.Filesyms = append(ctxt.Filesyms, file)
   117  		file.Value = int64(len(ctxt.Filesyms))
   118  		file.Type = sym.SFILEPATH
   119  		path := file.Name[len(src.FileSymPrefix):]
   120  		file.Name = expandGoroot(path)
   121  	}
   122  }
   123  
   124  func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
   125  	var f *sym.Symbol
   126  
   127  	// Give files numbers.
   128  	for i := 0; i < len(files); i++ {
   129  		f = files[i]
   130  		numberfile(ctxt, f)
   131  	}
   132  
   133  	newval := int32(-1)
   134  	var out sym.Pcdata
   135  	var it Pciter
   136  	for pciterinit(ctxt, &it, d); it.done == 0; pciternext(&it) {
   137  		// value delta
   138  		oldval := it.value
   139  
   140  		var val int32
   141  		if oldval == -1 {
   142  			val = -1
   143  		} else {
   144  			if oldval < 0 || oldval >= int32(len(files)) {
   145  				log.Fatalf("bad pcdata %d", oldval)
   146  			}
   147  			val = int32(files[oldval].Value)
   148  		}
   149  
   150  		dv := val - newval
   151  		newval = val
   152  		v := (uint32(dv) << 1) ^ uint32(dv>>31)
   153  		addvarint(&out, v)
   154  
   155  		// pc delta
   156  		addvarint(&out, (it.nextpc-it.pc)/it.pcscale)
   157  	}
   158  
   159  	// terminating value delta
   160  	addvarint(&out, 0)
   161  
   162  	*d = out
   163  }
   164  
   165  // onlycsymbol reports whether this is a cgo symbol provided by the
   166  // runtime and only used from C code.
   167  func onlycsymbol(s *sym.Symbol) bool {
   168  	switch s.Name {
   169  	case "_cgo_topofstack", "_cgo_panic", "crosscall2":
   170  		return true
   171  	}
   172  	return false
   173  }
   174  
   175  func emitPcln(ctxt *Link, s *sym.Symbol) bool {
   176  	if s == nil {
   177  		return true
   178  	}
   179  	if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(s) {
   180  		return false
   181  	}
   182  	// We want to generate func table entries only for the "lowest level" symbols,
   183  	// not containers of subsymbols.
   184  	if s.Attr.Container() {
   185  		return true
   186  	}
   187  	return true
   188  }
   189  
   190  // pclntab initializes the pclntab symbol with
   191  // runtime function and file name information.
   192  
   193  var pclntabZpcln sym.FuncInfo
   194  
   195  // These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
   196  var pclntabNfunc int32
   197  var pclntabFiletabOffset int32
   198  var pclntabPclntabOffset int32
   199  var pclntabFirstFunc *sym.Symbol
   200  var pclntabLastFunc *sym.Symbol
   201  
   202  func (ctxt *Link) pclntab() {
   203  	funcdataBytes := int64(0)
   204  	ftab := ctxt.Syms.Lookup("runtime.pclntab", 0)
   205  	ftab.Type = sym.SPCLNTAB
   206  	ftab.Attr |= sym.AttrReachable
   207  
   208  	// See golang.org/s/go12symtab for the format. Briefly:
   209  	//	8-byte header
   210  	//	nfunc [thearch.ptrsize bytes]
   211  	//	function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
   212  	//	end PC [thearch.ptrsize bytes]
   213  	//	offset to file table [4 bytes]
   214  	nfunc := int32(0)
   215  
   216  	// Find container symbols and mark them as such.
   217  	for _, s := range ctxt.Textp {
   218  		if s.Outer != nil {
   219  			s.Outer.Attr |= sym.AttrContainer
   220  		}
   221  	}
   222  
   223  	for _, s := range ctxt.Textp {
   224  		if emitPcln(ctxt, s) {
   225  			nfunc++
   226  		}
   227  	}
   228  
   229  	pclntabNfunc = nfunc
   230  	ftab.Grow(8 + int64(ctxt.Arch.PtrSize) + int64(nfunc)*2*int64(ctxt.Arch.PtrSize) + int64(ctxt.Arch.PtrSize) + 4)
   231  	ftab.SetUint32(ctxt.Arch, 0, 0xfffffffb)
   232  	ftab.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
   233  	ftab.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
   234  	ftab.SetUint(ctxt.Arch, 8, uint64(nfunc))
   235  	pclntabPclntabOffset = int32(8 + ctxt.Arch.PtrSize)
   236  
   237  	funcnameoff := make(map[string]int32)
   238  	nameToOffset := func(name string) int32 {
   239  		nameoff, ok := funcnameoff[name]
   240  		if !ok {
   241  			nameoff = ftabaddstring(ctxt, ftab, name)
   242  			funcnameoff[name] = nameoff
   243  		}
   244  		return nameoff
   245  	}
   246  
   247  	nfunc = 0
   248  	var last *sym.Symbol
   249  	for _, s := range ctxt.Textp {
   250  		last = s
   251  		if !emitPcln(ctxt, s) {
   252  			continue
   253  		}
   254  		pcln := s.FuncInfo
   255  		if pcln == nil {
   256  			pcln = &pclntabZpcln
   257  		}
   258  
   259  		if pclntabFirstFunc == nil {
   260  			pclntabFirstFunc = s
   261  		}
   262  
   263  		if len(pcln.InlTree) > 0 {
   264  			if len(pcln.Pcdata) <= objabi.PCDATA_InlTreeIndex {
   265  				// Create inlining pcdata table.
   266  				pcdata := make([]sym.Pcdata, objabi.PCDATA_InlTreeIndex+1)
   267  				copy(pcdata, pcln.Pcdata)
   268  				pcln.Pcdata = pcdata
   269  			}
   270  
   271  			if len(pcln.Funcdataoff) <= objabi.FUNCDATA_InlTree {
   272  				// Create inline tree funcdata.
   273  				funcdata := make([]*sym.Symbol, objabi.FUNCDATA_InlTree+1)
   274  				funcdataoff := make([]int64, objabi.FUNCDATA_InlTree+1)
   275  				copy(funcdata, pcln.Funcdata)
   276  				copy(funcdataoff, pcln.Funcdataoff)
   277  				pcln.Funcdata = funcdata
   278  				pcln.Funcdataoff = funcdataoff
   279  			}
   280  		}
   281  
   282  		funcstart := int32(len(ftab.P))
   283  		funcstart += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1)
   284  
   285  		ftab.SetAddr(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), s)
   286  		ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint64(funcstart))
   287  
   288  		// Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func
   289  		// and package debug/gosym.
   290  
   291  		// fixed size of struct, checked below
   292  		off := funcstart
   293  
   294  		end := funcstart + int32(ctxt.Arch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(ctxt.Arch.PtrSize)
   295  		if len(pcln.Funcdata) > 0 && (end&int32(ctxt.Arch.PtrSize-1) != 0) {
   296  			end += 4
   297  		}
   298  		ftab.Grow(int64(end))
   299  
   300  		// entry uintptr
   301  		off = int32(ftab.SetAddr(ctxt.Arch, int64(off), s))
   302  
   303  		// name int32
   304  		nameoff := nameToOffset(s.Name)
   305  		off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(nameoff)))
   306  
   307  		// args int32
   308  		// TODO: Move into funcinfo.
   309  		args := uint32(0)
   310  		if s.FuncInfo != nil {
   311  			args = uint32(s.FuncInfo.Args)
   312  		}
   313  		off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
   314  
   315  		// funcID uint32
   316  		funcID := objabi.FuncID_normal
   317  		switch s.Name {
   318  		case "runtime.goexit":
   319  			funcID = objabi.FuncID_goexit
   320  		case "runtime.jmpdefer":
   321  			funcID = objabi.FuncID_jmpdefer
   322  		case "runtime.mcall":
   323  			funcID = objabi.FuncID_mcall
   324  		case "runtime.morestack":
   325  			funcID = objabi.FuncID_morestack
   326  		case "runtime.mstart":
   327  			funcID = objabi.FuncID_mstart
   328  		case "runtime.rt0_go":
   329  			funcID = objabi.FuncID_rt0_go
   330  		case "runtime.asmcgocall":
   331  			funcID = objabi.FuncID_asmcgocall
   332  		case "runtime.sigpanic":
   333  			funcID = objabi.FuncID_sigpanic
   334  		case "runtime.runfinq":
   335  			funcID = objabi.FuncID_runfinq
   336  		case "runtime.bgsweep":
   337  			funcID = objabi.FuncID_bgsweep
   338  		case "runtime.forcegchelper":
   339  			funcID = objabi.FuncID_forcegchelper
   340  		case "runtime.timerproc":
   341  			funcID = objabi.FuncID_timerproc
   342  		case "runtime.gcBgMarkWorker":
   343  			funcID = objabi.FuncID_gcBgMarkWorker
   344  		case "runtime.systemstack_switch":
   345  			funcID = objabi.FuncID_systemstack_switch
   346  		case "runtime.systemstack":
   347  			funcID = objabi.FuncID_systemstack
   348  		case "runtime.cgocallback_gofunc":
   349  			funcID = objabi.FuncID_cgocallback_gofunc
   350  		case "runtime.gogo":
   351  			funcID = objabi.FuncID_gogo
   352  		case "runtime.externalthreadhandler":
   353  			funcID = objabi.FuncID_externalthreadhandler
   354  		}
   355  		off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(funcID)))
   356  
   357  		if pcln != &pclntabZpcln {
   358  			renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
   359  			if false {
   360  				// Sanity check the new numbering
   361  				var it Pciter
   362  				for pciterinit(ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
   363  					if it.value < 1 || it.value > int32(len(ctxt.Filesyms)) {
   364  						Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(ctxt.Filesyms))
   365  						errorexit()
   366  					}
   367  				}
   368  			}
   369  		}
   370  
   371  		if len(pcln.InlTree) > 0 {
   372  			inlTreeSym := ctxt.Syms.Lookup("inltree."+s.Name, 0)
   373  			inlTreeSym.Type = sym.SRODATA
   374  			inlTreeSym.Attr |= sym.AttrReachable | sym.AttrDuplicateOK
   375  
   376  			for i, call := range pcln.InlTree {
   377  				// Usually, call.File is already numbered since the file
   378  				// shows up in the Pcfile table. However, two inlined calls
   379  				// might overlap exactly so that only the innermost file
   380  				// appears in the Pcfile table. In that case, this assigns
   381  				// the outer file a number.
   382  				numberfile(ctxt, call.File)
   383  				nameoff := nameToOffset(call.Func.Name)
   384  
   385  				inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+0), uint32(call.Parent))
   386  				inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+4), uint32(call.File.Value))
   387  				inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+8), uint32(call.Line))
   388  				inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+12), uint32(nameoff))
   389  			}
   390  
   391  			pcln.Funcdata[objabi.FUNCDATA_InlTree] = inlTreeSym
   392  			pcln.Pcdata[objabi.PCDATA_InlTreeIndex] = pcln.Pcinline
   393  		}
   394  
   395  		// pcdata
   396  		off = addpctab(ctxt, ftab, off, &pcln.Pcsp)
   397  
   398  		off = addpctab(ctxt, ftab, off, &pcln.Pcfile)
   399  		off = addpctab(ctxt, ftab, off, &pcln.Pcline)
   400  		off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcln.Pcdata))))
   401  		off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcln.Funcdata))))
   402  		for i := 0; i < len(pcln.Pcdata); i++ {
   403  			off = addpctab(ctxt, ftab, off, &pcln.Pcdata[i])
   404  		}
   405  
   406  		// funcdata, must be pointer-aligned and we're only int32-aligned.
   407  		// Missing funcdata will be 0 (nil pointer).
   408  		if len(pcln.Funcdata) > 0 {
   409  			if off&int32(ctxt.Arch.PtrSize-1) != 0 {
   410  				off += 4
   411  			}
   412  			for i := 0; i < len(pcln.Funcdata); i++ {
   413  				if pcln.Funcdata[i] == nil {
   414  					ftab.SetUint(ctxt.Arch, int64(off)+int64(ctxt.Arch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]))
   415  				} else {
   416  					// TODO: Dedup.
   417  					funcdataBytes += pcln.Funcdata[i].Size
   418  
   419  					ftab.SetAddrPlus(ctxt.Arch, int64(off)+int64(ctxt.Arch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
   420  				}
   421  			}
   422  
   423  			off += int32(len(pcln.Funcdata)) * int32(ctxt.Arch.PtrSize)
   424  		}
   425  
   426  		if off != end {
   427  			Errorf(s, "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), ctxt.Arch.PtrSize)
   428  			errorexit()
   429  		}
   430  
   431  		nfunc++
   432  	}
   433  
   434  	pclntabLastFunc = last
   435  	// Final entry of table is just end pc.
   436  	ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, last.Size)
   437  
   438  	// Start file table.
   439  	start := int32(len(ftab.P))
   440  
   441  	start += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1)
   442  	pclntabFiletabOffset = start
   443  	ftab.SetUint32(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint32(start))
   444  
   445  	ftab.Grow(int64(start) + (int64(len(ctxt.Filesyms))+1)*4)
   446  	ftab.SetUint32(ctxt.Arch, int64(start), uint32(len(ctxt.Filesyms)+1))
   447  	for i := len(ctxt.Filesyms) - 1; i >= 0; i-- {
   448  		s := ctxt.Filesyms[i]
   449  		ftab.SetUint32(ctxt.Arch, int64(start)+s.Value*4, uint32(ftabaddstring(ctxt, ftab, s.Name)))
   450  	}
   451  
   452  	ftab.Size = int64(len(ftab.P))
   453  
   454  	if ctxt.Debugvlog != 0 {
   455  		ctxt.Logf("%5.2f pclntab=%d bytes, funcdata total %d bytes\n", Cputime(), ftab.Size, funcdataBytes)
   456  	}
   457  }
   458  
   459  func gorootFinal() string {
   460  	root := objabi.GOROOT
   461  	if final := os.Getenv("GOROOT_FINAL"); final != "" {
   462  		root = final
   463  	}
   464  	return root
   465  }
   466  
   467  func expandGoroot(s string) string {
   468  	const n = len("$GOROOT")
   469  	if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
   470  		return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:]))
   471  	}
   472  	return s
   473  }
   474  
   475  const (
   476  	BUCKETSIZE    = 256 * MINFUNC
   477  	SUBBUCKETS    = 16
   478  	SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
   479  	NOIDX         = 0x7fffffff
   480  )
   481  
   482  // findfunctab generates a lookup table to quickly find the containing
   483  // function for a pc. See src/runtime/symtab.go:findfunc for details.
   484  func (ctxt *Link) findfunctab() {
   485  	t := ctxt.Syms.Lookup("runtime.findfunctab", 0)
   486  	t.Type = sym.SRODATA
   487  	t.Attr |= sym.AttrReachable
   488  	t.Attr |= sym.AttrLocal
   489  
   490  	// find min and max address
   491  	min := ctxt.Textp[0].Value
   492  	max := int64(0)
   493  	for _, s := range ctxt.Textp {
   494  		max = s.Value + s.Size
   495  	}
   496  
   497  	// for each subbucket, compute the minimum of all symbol indexes
   498  	// that map to that subbucket.
   499  	n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
   500  
   501  	indexes := make([]int32, n)
   502  	for i := int32(0); i < n; i++ {
   503  		indexes[i] = NOIDX
   504  	}
   505  	idx := int32(0)
   506  	for i, s := range ctxt.Textp {
   507  		if !emitPcln(ctxt, s) {
   508  			continue
   509  		}
   510  		p := s.Value
   511  		var e *sym.Symbol
   512  		i++
   513  		if i < len(ctxt.Textp) {
   514  			e = ctxt.Textp[i]
   515  		}
   516  		for !emitPcln(ctxt, e) && i < len(ctxt.Textp) {
   517  			e = ctxt.Textp[i]
   518  			i++
   519  		}
   520  		q := max
   521  		if e != nil {
   522  			q = e.Value
   523  		}
   524  
   525  		//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
   526  		for ; p < q; p += SUBBUCKETSIZE {
   527  			i = int((p - min) / SUBBUCKETSIZE)
   528  			if indexes[i] > idx {
   529  				indexes[i] = idx
   530  			}
   531  		}
   532  
   533  		i = int((q - 1 - min) / SUBBUCKETSIZE)
   534  		if indexes[i] > idx {
   535  			indexes[i] = idx
   536  		}
   537  		idx++
   538  	}
   539  
   540  	// allocate table
   541  	nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
   542  
   543  	t.Grow(4*int64(nbuckets) + int64(n))
   544  
   545  	// fill in table
   546  	for i := int32(0); i < nbuckets; i++ {
   547  		base := indexes[i*SUBBUCKETS]
   548  		if base == NOIDX {
   549  			Errorf(nil, "hole in findfunctab")
   550  		}
   551  		t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
   552  		for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
   553  			idx = indexes[i*SUBBUCKETS+j]
   554  			if idx == NOIDX {
   555  				Errorf(nil, "hole in findfunctab")
   556  			}
   557  			if idx-base >= 256 {
   558  				Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
   559  			}
   560  
   561  			t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
   562  		}
   563  	}
   564  }