Home | History | Annotate | Download | only in ld
      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 		// frame int32
    316 		// This has been removed (it was never set quite correctly anyway).
    317 		// Nothing should use it.
    318 		// Leave an obviously incorrect value.
    319 		// TODO: Remove entirely.
    320 		off = int32(ftab.SetUint32(ctxt.Arch, int64(off), 0x1234567))
    321 
    322 		if pcln != &pclntabZpcln {
    323 			renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
    324 			if false {
    325 				// Sanity check the new numbering
    326 				var it Pciter
    327 				for pciterinit(ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
    328 					if it.value < 1 || it.value > int32(len(ctxt.Filesyms)) {
    329 						Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(ctxt.Filesyms))
    330 						errorexit()
    331 					}
    332 				}
    333 			}
    334 		}
    335 
    336 		if len(pcln.InlTree) > 0 {
    337 			inlTreeSym := ctxt.Syms.Lookup("inltree."+s.Name, 0)
    338 			inlTreeSym.Type = sym.SRODATA
    339 			inlTreeSym.Attr |= sym.AttrReachable | sym.AttrDuplicateOK
    340 
    341 			for i, call := range pcln.InlTree {
    342 				// Usually, call.File is already numbered since the file
    343 				// shows up in the Pcfile table. However, two inlined calls
    344 				// might overlap exactly so that only the innermost file
    345 				// appears in the Pcfile table. In that case, this assigns
    346 				// the outer file a number.
    347 				numberfile(ctxt, call.File)
    348 				nameoff := nameToOffset(call.Func.Name)
    349 
    350 				inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+0), uint32(call.Parent))
    351 				inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+4), uint32(call.File.Value))
    352 				inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+8), uint32(call.Line))
    353 				inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+12), uint32(nameoff))
    354 			}
    355 
    356 			pcln.Funcdata[objabi.FUNCDATA_InlTree] = inlTreeSym
    357 			pcln.Pcdata[objabi.PCDATA_InlTreeIndex] = pcln.Pcinline
    358 		}
    359 
    360 		// pcdata
    361 		off = addpctab(ctxt, ftab, off, &pcln.Pcsp)
    362 
    363 		off = addpctab(ctxt, ftab, off, &pcln.Pcfile)
    364 		off = addpctab(ctxt, ftab, off, &pcln.Pcline)
    365 		off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcln.Pcdata))))
    366 		off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcln.Funcdata))))
    367 		for i := 0; i < len(pcln.Pcdata); i++ {
    368 			off = addpctab(ctxt, ftab, off, &pcln.Pcdata[i])
    369 		}
    370 
    371 		// funcdata, must be pointer-aligned and we're only int32-aligned.
    372 		// Missing funcdata will be 0 (nil pointer).
    373 		if len(pcln.Funcdata) > 0 {
    374 			if off&int32(ctxt.Arch.PtrSize-1) != 0 {
    375 				off += 4
    376 			}
    377 			for i := 0; i < len(pcln.Funcdata); i++ {
    378 				if pcln.Funcdata[i] == nil {
    379 					ftab.SetUint(ctxt.Arch, int64(off)+int64(ctxt.Arch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]))
    380 				} else {
    381 					// TODO: Dedup.
    382 					funcdataBytes += pcln.Funcdata[i].Size
    383 
    384 					ftab.SetAddrPlus(ctxt.Arch, int64(off)+int64(ctxt.Arch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
    385 				}
    386 			}
    387 
    388 			off += int32(len(pcln.Funcdata)) * int32(ctxt.Arch.PtrSize)
    389 		}
    390 
    391 		if off != end {
    392 			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)
    393 			errorexit()
    394 		}
    395 
    396 		nfunc++
    397 	}
    398 
    399 	pclntabLastFunc = last
    400 	// Final entry of table is just end pc.
    401 	ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, last.Size)
    402 
    403 	// Start file table.
    404 	start := int32(len(ftab.P))
    405 
    406 	start += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1)
    407 	pclntabFiletabOffset = start
    408 	ftab.SetUint32(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint32(start))
    409 
    410 	ftab.Grow(int64(start) + (int64(len(ctxt.Filesyms))+1)*4)
    411 	ftab.SetUint32(ctxt.Arch, int64(start), uint32(len(ctxt.Filesyms)+1))
    412 	for i := len(ctxt.Filesyms) - 1; i >= 0; i-- {
    413 		s := ctxt.Filesyms[i]
    414 		ftab.SetUint32(ctxt.Arch, int64(start)+s.Value*4, uint32(ftabaddstring(ctxt, ftab, s.Name)))
    415 	}
    416 
    417 	ftab.Size = int64(len(ftab.P))
    418 
    419 	if ctxt.Debugvlog != 0 {
    420 		ctxt.Logf("%5.2f pclntab=%d bytes, funcdata total %d bytes\n", Cputime(), ftab.Size, funcdataBytes)
    421 	}
    422 }
    423 
    424 func gorootFinal() string {
    425 	root := objabi.GOROOT
    426 	if final := os.Getenv("GOROOT_FINAL"); final != "" {
    427 		root = final
    428 	}
    429 	return root
    430 }
    431 
    432 func expandGoroot(s string) string {
    433 	const n = len("$GOROOT")
    434 	if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
    435 		return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:]))
    436 	}
    437 	return s
    438 }
    439 
    440 const (
    441 	BUCKETSIZE    = 256 * MINFUNC
    442 	SUBBUCKETS    = 16
    443 	SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
    444 	NOIDX         = 0x7fffffff
    445 )
    446 
    447 // findfunctab generates a lookup table to quickly find the containing
    448 // function for a pc. See src/runtime/symtab.go:findfunc for details.
    449 func (ctxt *Link) findfunctab() {
    450 	t := ctxt.Syms.Lookup("runtime.findfunctab", 0)
    451 	t.Type = sym.SRODATA
    452 	t.Attr |= sym.AttrReachable
    453 	t.Attr |= sym.AttrLocal
    454 
    455 	// find min and max address
    456 	min := ctxt.Textp[0].Value
    457 	max := int64(0)
    458 	for _, s := range ctxt.Textp {
    459 		max = s.Value + s.Size
    460 	}
    461 
    462 	// for each subbucket, compute the minimum of all symbol indexes
    463 	// that map to that subbucket.
    464 	n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
    465 
    466 	indexes := make([]int32, n)
    467 	for i := int32(0); i < n; i++ {
    468 		indexes[i] = NOIDX
    469 	}
    470 	idx := int32(0)
    471 	for i, s := range ctxt.Textp {
    472 		if !emitPcln(ctxt, s) {
    473 			continue
    474 		}
    475 		p := s.Value
    476 		var e *sym.Symbol
    477 		i++
    478 		if i < len(ctxt.Textp) {
    479 			e = ctxt.Textp[i]
    480 		}
    481 		for !emitPcln(ctxt, e) && i < len(ctxt.Textp) {
    482 			e = ctxt.Textp[i]
    483 			i++
    484 		}
    485 		q := max
    486 		if e != nil {
    487 			q = e.Value
    488 		}
    489 
    490 		//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
    491 		for ; p < q; p += SUBBUCKETSIZE {
    492 			i = int((p - min) / SUBBUCKETSIZE)
    493 			if indexes[i] > idx {
    494 				indexes[i] = idx
    495 			}
    496 		}
    497 
    498 		i = int((q - 1 - min) / SUBBUCKETSIZE)
    499 		if indexes[i] > idx {
    500 			indexes[i] = idx
    501 		}
    502 		idx++
    503 	}
    504 
    505 	// allocate table
    506 	nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
    507 
    508 	t.Grow(4*int64(nbuckets) + int64(n))
    509 
    510 	// fill in table
    511 	for i := int32(0); i < nbuckets; i++ {
    512 		base := indexes[i*SUBBUCKETS]
    513 		if base == NOIDX {
    514 			Errorf(nil, "hole in findfunctab")
    515 		}
    516 		t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
    517 		for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
    518 			idx = indexes[i*SUBBUCKETS+j]
    519 			if idx == NOIDX {
    520 				Errorf(nil, "hole in findfunctab")
    521 			}
    522 			if idx-base >= 256 {
    523 				Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
    524 			}
    525 
    526 			t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
    527 		}
    528 	}
    529 }
    530