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