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