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/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 }
    464