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