Source file src/cmd/link/internal/ld/pcln.go

     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/goobj"
     9  	"cmd/internal/objabi"
    10  	"cmd/internal/sys"
    11  	"cmd/link/internal/loader"
    12  	"cmd/link/internal/sym"
    13  	"fmt"
    14  	"internal/buildcfg"
    15  	"os"
    16  	"path/filepath"
    17  	"strings"
    18  )
    19  
    20  const funcSize = 10 * 4 // funcSize is the size of the _func object in runtime/runtime2.go
    21  
    22  // pclntab holds the state needed for pclntab generation.
    23  type pclntab struct {
    24  	// The first and last functions found.
    25  	firstFunc, lastFunc loader.Sym
    26  
    27  	// Running total size of pclntab.
    28  	size int64
    29  
    30  	// runtime.pclntab's symbols
    31  	carrier     loader.Sym
    32  	pclntab     loader.Sym
    33  	pcheader    loader.Sym
    34  	funcnametab loader.Sym
    35  	findfunctab loader.Sym
    36  	cutab       loader.Sym
    37  	filetab     loader.Sym
    38  	pctab       loader.Sym
    39  
    40  	// The number of functions + number of TEXT sections - 1. This is such an
    41  	// unexpected value because platforms that have more than one TEXT section
    42  	// get a dummy function inserted between because the external linker can place
    43  	// functions in those areas. We mark those areas as not covered by the Go
    44  	// runtime.
    45  	//
    46  	// On most platforms this is the number of reachable functions.
    47  	nfunc int32
    48  
    49  	// The number of filenames in runtime.filetab.
    50  	nfiles uint32
    51  }
    52  
    53  // addGeneratedSym adds a generator symbol to pclntab, returning the new Sym.
    54  // It is the caller's responsibility to save the symbol in state.
    55  func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, f generatorFunc) loader.Sym {
    56  	size = Rnd(size, int64(ctxt.Arch.PtrSize))
    57  	state.size += size
    58  	s := ctxt.createGeneratorSymbol(name, 0, sym.SPCLNTAB, size, f)
    59  	ctxt.loader.SetAttrReachable(s, true)
    60  	ctxt.loader.SetCarrierSym(s, state.carrier)
    61  	ctxt.loader.SetAttrNotInSymbolTable(s, true)
    62  	return s
    63  }
    64  
    65  // makePclntab makes a pclntab object, and assembles all the compilation units
    66  // we'll need to write pclntab. Returns the pclntab structure, a slice of the
    67  // CompilationUnits we need, and a slice of the function symbols we need to
    68  // generate pclntab.
    69  func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.CompilationUnit, []loader.Sym) {
    70  	ldr := ctxt.loader
    71  	state := new(pclntab)
    72  
    73  	// Gather some basic stats and info.
    74  	seenCUs := make(map[*sym.CompilationUnit]struct{})
    75  	compUnits := []*sym.CompilationUnit{}
    76  	funcs := []loader.Sym{}
    77  
    78  	for _, s := range ctxt.Textp {
    79  		if !emitPcln(ctxt, s, container) {
    80  			continue
    81  		}
    82  		funcs = append(funcs, s)
    83  		state.nfunc++
    84  		if state.firstFunc == 0 {
    85  			state.firstFunc = s
    86  		}
    87  		state.lastFunc = s
    88  
    89  		// We need to keep track of all compilation units we see. Some symbols
    90  		// (eg, go.buildid, _cgoexp_, etc) won't have a compilation unit.
    91  		cu := ldr.SymUnit(s)
    92  		if _, ok := seenCUs[cu]; cu != nil && !ok {
    93  			seenCUs[cu] = struct{}{}
    94  			cu.PclnIndex = len(compUnits)
    95  			compUnits = append(compUnits, cu)
    96  		}
    97  	}
    98  	return state, compUnits, funcs
    99  }
   100  
   101  func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool {
   102  	// We want to generate func table entries only for the "lowest
   103  	// level" symbols, not containers of subsymbols.
   104  	return !container.Has(s)
   105  }
   106  
   107  func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 {
   108  	ldr := ctxt.loader
   109  	target := ctxt.Target
   110  	deferreturn := uint32(0)
   111  	lastWasmAddr := uint32(0)
   112  
   113  	relocs := ldr.Relocs(s)
   114  	for ri := 0; ri < relocs.Count(); ri++ {
   115  		r := relocs.At(ri)
   116  		if target.IsWasm() && r.Type() == objabi.R_ADDR {
   117  			// wasm/ssa.go generates an ARESUMEPOINT just
   118  			// before the deferreturn call. The "PC" of
   119  			// the deferreturn call is stored in the
   120  			// R_ADDR relocation on the ARESUMEPOINT.
   121  			lastWasmAddr = uint32(r.Add())
   122  		}
   123  		if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) {
   124  			if target.IsWasm() {
   125  				deferreturn = lastWasmAddr - 1
   126  			} else {
   127  				// Note: the relocation target is in the call instruction, but
   128  				// is not necessarily the whole instruction (for instance, on
   129  				// x86 the relocation applies to bytes [1:5] of the 5 byte call
   130  				// instruction).
   131  				deferreturn = uint32(r.Off())
   132  				switch target.Arch.Family {
   133  				case sys.AMD64, sys.I386:
   134  					deferreturn--
   135  				case sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64:
   136  					// no change
   137  				case sys.S390X:
   138  					deferreturn -= 2
   139  				default:
   140  					panic(fmt.Sprint("Unhandled architecture:", target.Arch.Family))
   141  				}
   142  			}
   143  			break // only need one
   144  		}
   145  	}
   146  	return deferreturn
   147  }
   148  
   149  // genInlTreeSym generates the InlTree sym for a function with the
   150  // specified FuncInfo.
   151  func genInlTreeSym(ctxt *Link, cu *sym.CompilationUnit, fi loader.FuncInfo, arch *sys.Arch, nameOffsets map[loader.Sym]uint32) loader.Sym {
   152  	ldr := ctxt.loader
   153  	its := ldr.CreateExtSym("", 0)
   154  	inlTreeSym := ldr.MakeSymbolUpdater(its)
   155  	// Note: the generated symbol is given a type of sym.SGOFUNC, as a
   156  	// signal to the symtab() phase that it needs to be grouped in with
   157  	// other similar symbols (gcdata, etc); the dodata() phase will
   158  	// eventually switch the type back to SRODATA.
   159  	inlTreeSym.SetType(sym.SGOFUNC)
   160  	ldr.SetAttrReachable(its, true)
   161  	ldr.SetSymAlign(its, 4) // it has 32-bit fields
   162  	ninl := fi.NumInlTree()
   163  	for i := 0; i < int(ninl); i++ {
   164  		call := fi.InlTree(i)
   165  		val := call.File
   166  		nameoff, ok := nameOffsets[call.Func]
   167  		if !ok {
   168  			panic("couldn't find function name offset")
   169  		}
   170  
   171  		inlTreeSym.SetUint16(arch, int64(i*20+0), uint16(call.Parent))
   172  		inlFunc := ldr.FuncInfo(call.Func)
   173  
   174  		var funcID objabi.FuncID
   175  		if inlFunc.Valid() {
   176  			funcID = inlFunc.FuncID()
   177  		}
   178  		inlTreeSym.SetUint8(arch, int64(i*20+2), uint8(funcID))
   179  
   180  		// byte 3 is unused
   181  		inlTreeSym.SetUint32(arch, int64(i*20+4), uint32(val))
   182  		inlTreeSym.SetUint32(arch, int64(i*20+8), uint32(call.Line))
   183  		inlTreeSym.SetUint32(arch, int64(i*20+12), uint32(nameoff))
   184  		inlTreeSym.SetUint32(arch, int64(i*20+16), uint32(call.ParentPC))
   185  	}
   186  	return its
   187  }
   188  
   189  // makeInlSyms returns a map of loader.Sym that are created inlSyms.
   190  func makeInlSyms(ctxt *Link, funcs []loader.Sym, nameOffsets map[loader.Sym]uint32) map[loader.Sym]loader.Sym {
   191  	ldr := ctxt.loader
   192  	// Create the inline symbols we need.
   193  	inlSyms := make(map[loader.Sym]loader.Sym)
   194  	for _, s := range funcs {
   195  		if fi := ldr.FuncInfo(s); fi.Valid() {
   196  			fi.Preload()
   197  			if fi.NumInlTree() > 0 {
   198  				inlSyms[s] = genInlTreeSym(ctxt, ldr.SymUnit(s), fi, ctxt.Arch, nameOffsets)
   199  			}
   200  		}
   201  	}
   202  	return inlSyms
   203  }
   204  
   205  // generatePCHeader creates the runtime.pcheader symbol, setting it up as a
   206  // generator to fill in its data later.
   207  func (state *pclntab) generatePCHeader(ctxt *Link) {
   208  	ldr := ctxt.loader
   209  	textStartOff := int64(8 + 2*ctxt.Arch.PtrSize)
   210  	size := int64(8 + 8*ctxt.Arch.PtrSize)
   211  	writeHeader := func(ctxt *Link, s loader.Sym) {
   212  		header := ctxt.loader.MakeSymbolUpdater(s)
   213  
   214  		writeSymOffset := func(off int64, ws loader.Sym) int64 {
   215  			diff := ldr.SymValue(ws) - ldr.SymValue(s)
   216  			if diff <= 0 {
   217  				name := ldr.SymName(ws)
   218  				panic(fmt.Sprintf("expected runtime.pcheader(%x) to be placed before %s(%x)", ldr.SymValue(s), name, ldr.SymValue(ws)))
   219  			}
   220  			return header.SetUintptr(ctxt.Arch, off, uintptr(diff))
   221  		}
   222  
   223  		// Write header.
   224  		// Keep in sync with runtime/symtab.go:pcHeader and package debug/gosym.
   225  		header.SetUint32(ctxt.Arch, 0, 0xfffffff0)
   226  		header.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
   227  		header.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
   228  		off := header.SetUint(ctxt.Arch, 8, uint64(state.nfunc))
   229  		off = header.SetUint(ctxt.Arch, off, uint64(state.nfiles))
   230  		if off != textStartOff {
   231  			panic(fmt.Sprintf("pcHeader textStartOff: %d != %d", off, textStartOff))
   232  		}
   233  		off += int64(ctxt.Arch.PtrSize) // skip runtimeText relocation
   234  		off = writeSymOffset(off, state.funcnametab)
   235  		off = writeSymOffset(off, state.cutab)
   236  		off = writeSymOffset(off, state.filetab)
   237  		off = writeSymOffset(off, state.pctab)
   238  		off = writeSymOffset(off, state.pclntab)
   239  		if off != size {
   240  			panic(fmt.Sprintf("pcHeader size: %d != %d", off, size))
   241  		}
   242  	}
   243  
   244  	state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader)
   245  	// Create the runtimeText relocation.
   246  	sb := ldr.MakeSymbolUpdater(state.pcheader)
   247  	sb.SetAddr(ctxt.Arch, textStartOff, ldr.Lookup("runtime.text", 0))
   248  }
   249  
   250  // walkFuncs iterates over the funcs, calling a function for each unique
   251  // function and inlined function.
   252  func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) {
   253  	ldr := ctxt.loader
   254  	seen := make(map[loader.Sym]struct{})
   255  	for _, s := range funcs {
   256  		if _, ok := seen[s]; !ok {
   257  			f(s)
   258  			seen[s] = struct{}{}
   259  		}
   260  
   261  		fi := ldr.FuncInfo(s)
   262  		if !fi.Valid() {
   263  			continue
   264  		}
   265  		fi.Preload()
   266  		for i, ni := 0, fi.NumInlTree(); i < int(ni); i++ {
   267  			call := fi.InlTree(i).Func
   268  			if _, ok := seen[call]; !ok {
   269  				f(call)
   270  				seen[call] = struct{}{}
   271  			}
   272  		}
   273  	}
   274  }
   275  
   276  // generateFuncnametab creates the function name table. Returns a map of
   277  // func symbol to the name offset in runtime.funcnamtab.
   278  func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 {
   279  	nameOffsets := make(map[loader.Sym]uint32, state.nfunc)
   280  
   281  	// The name used by the runtime is the concatenation of the 3 returned strings.
   282  	// For regular functions, only one returned string is nonempty.
   283  	// For generic functions, we use three parts so that we can print everything
   284  	// within the outermost "[]" as "...".
   285  	nameParts := func(name string) (string, string, string) {
   286  		i := strings.IndexByte(name, '[')
   287  		if i < 0 {
   288  			return name, "", ""
   289  		}
   290  		// TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.
   291  		j := len(name) - 1
   292  		for j > i && name[j] != ']' {
   293  			j--
   294  		}
   295  		if j <= i {
   296  			return name, "", ""
   297  		}
   298  		return name[:i], "[...]", name[j+1:]
   299  	}
   300  
   301  	// Write the null terminated strings.
   302  	writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
   303  		symtab := ctxt.loader.MakeSymbolUpdater(s)
   304  		for s, off := range nameOffsets {
   305  			a, b, c := nameParts(ctxt.loader.SymName(s))
   306  			o := int64(off)
   307  			o = symtab.AddStringAt(o, a)
   308  			o = symtab.AddStringAt(o, b)
   309  			_ = symtab.AddCStringAt(o, c)
   310  		}
   311  	}
   312  
   313  	// Loop through the CUs, and calculate the size needed.
   314  	var size int64
   315  	walkFuncs(ctxt, funcs, func(s loader.Sym) {
   316  		nameOffsets[s] = uint32(size)
   317  		a, b, c := nameParts(ctxt.loader.SymName(s))
   318  		size += int64(len(a) + len(b) + len(c) + 1) // NULL terminate
   319  	})
   320  
   321  	state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab)
   322  	return nameOffsets
   323  }
   324  
   325  // walkFilenames walks funcs, calling a function for each filename used in each
   326  // function's line table.
   327  func walkFilenames(ctxt *Link, funcs []loader.Sym, f func(*sym.CompilationUnit, goobj.CUFileIndex)) {
   328  	ldr := ctxt.loader
   329  
   330  	// Loop through all functions, finding the filenames we need.
   331  	for _, s := range funcs {
   332  		fi := ldr.FuncInfo(s)
   333  		if !fi.Valid() {
   334  			continue
   335  		}
   336  		fi.Preload()
   337  
   338  		cu := ldr.SymUnit(s)
   339  		for i, nf := 0, int(fi.NumFile()); i < nf; i++ {
   340  			f(cu, fi.File(i))
   341  		}
   342  		for i, ninl := 0, int(fi.NumInlTree()); i < ninl; i++ {
   343  			call := fi.InlTree(i)
   344  			f(cu, call.File)
   345  		}
   346  	}
   347  }
   348  
   349  // generateFilenameTabs creates LUTs needed for filename lookup. Returns a slice
   350  // of the index at which each CU begins in runtime.cutab.
   351  //
   352  // Function objects keep track of the files they reference to print the stack.
   353  // This function creates a per-CU list of filenames if CU[M] references
   354  // files[1-N], the following is generated:
   355  //
   356  //  runtime.cutab:
   357  //    CU[M]
   358  //     offsetToFilename[0]
   359  //     offsetToFilename[1]
   360  //     ..
   361  //
   362  //  runtime.filetab
   363  //     filename[0]
   364  //     filename[1]
   365  //
   366  // Looking up a filename then becomes:
   367  //  0) Given a func, and filename index [K]
   368  //  1) Get Func.CUIndex:       M := func.cuOffset
   369  //  2) Find filename offset:   fileOffset := runtime.cutab[M+K]
   370  //  3) Get the filename:       getcstring(runtime.filetab[fileOffset])
   371  func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.CompilationUnit, funcs []loader.Sym) []uint32 {
   372  	// On a per-CU basis, keep track of all the filenames we need.
   373  	//
   374  	// Note, that we store the filenames in a separate section in the object
   375  	// files, and deduplicate based on the actual value. It would be better to
   376  	// store the filenames as symbols, using content addressable symbols (and
   377  	// then not loading extra filenames), and just use the hash value of the
   378  	// symbol name to do this cataloging.
   379  	//
   380  	// TODO: Store filenames as symbols. (Note this would be easiest if you
   381  	// also move strings to ALWAYS using the larger content addressable hash
   382  	// function, and use that hash value for uniqueness testing.)
   383  	cuEntries := make([]goobj.CUFileIndex, len(compUnits))
   384  	fileOffsets := make(map[string]uint32)
   385  
   386  	// Walk the filenames.
   387  	// We store the total filename string length we need to load, and the max
   388  	// file index we've seen per CU so we can calculate how large the
   389  	// CU->global table needs to be.
   390  	var fileSize int64
   391  	walkFilenames(ctxt, funcs, func(cu *sym.CompilationUnit, i goobj.CUFileIndex) {
   392  		// Note we use the raw filename for lookup, but use the expanded filename
   393  		// when we save the size.
   394  		filename := cu.FileTable[i]
   395  		if _, ok := fileOffsets[filename]; !ok {
   396  			fileOffsets[filename] = uint32(fileSize)
   397  			fileSize += int64(len(expandFile(filename)) + 1) // NULL terminate
   398  		}
   399  
   400  		// Find the maximum file index we've seen.
   401  		if cuEntries[cu.PclnIndex] < i+1 {
   402  			cuEntries[cu.PclnIndex] = i + 1 // Store max + 1
   403  		}
   404  	})
   405  
   406  	// Calculate the size of the runtime.cutab variable.
   407  	var totalEntries uint32
   408  	cuOffsets := make([]uint32, len(cuEntries))
   409  	for i, entries := range cuEntries {
   410  		// Note, cutab is a slice of uint32, so an offset to a cu's entry is just the
   411  		// running total of all cu indices we've needed to store so far, not the
   412  		// number of bytes we've stored so far.
   413  		cuOffsets[i] = totalEntries
   414  		totalEntries += uint32(entries)
   415  	}
   416  
   417  	// Write cutab.
   418  	writeCutab := func(ctxt *Link, s loader.Sym) {
   419  		sb := ctxt.loader.MakeSymbolUpdater(s)
   420  
   421  		var off int64
   422  		for i, max := range cuEntries {
   423  			// Write the per CU LUT.
   424  			cu := compUnits[i]
   425  			for j := goobj.CUFileIndex(0); j < max; j++ {
   426  				fileOffset, ok := fileOffsets[cu.FileTable[j]]
   427  				if !ok {
   428  					// We're looping through all possible file indices. It's possible a file's
   429  					// been deadcode eliminated, and although it's a valid file in the CU, it's
   430  					// not needed in this binary. When that happens, use an invalid offset.
   431  					fileOffset = ^uint32(0)
   432  				}
   433  				off = sb.SetUint32(ctxt.Arch, off, fileOffset)
   434  			}
   435  		}
   436  	}
   437  	state.cutab = state.addGeneratedSym(ctxt, "runtime.cutab", int64(totalEntries*4), writeCutab)
   438  
   439  	// Write filetab.
   440  	writeFiletab := func(ctxt *Link, s loader.Sym) {
   441  		sb := ctxt.loader.MakeSymbolUpdater(s)
   442  
   443  		// Write the strings.
   444  		for filename, loc := range fileOffsets {
   445  			sb.AddStringAt(int64(loc), expandFile(filename))
   446  		}
   447  	}
   448  	state.nfiles = uint32(len(fileOffsets))
   449  	state.filetab = state.addGeneratedSym(ctxt, "runtime.filetab", fileSize, writeFiletab)
   450  
   451  	return cuOffsets
   452  }
   453  
   454  // generatePctab creates the runtime.pctab variable, holding all the
   455  // deduplicated pcdata.
   456  func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
   457  	ldr := ctxt.loader
   458  
   459  	// Pctab offsets of 0 are considered invalid in the runtime. We respect
   460  	// that by just padding a single byte at the beginning of runtime.pctab,
   461  	// that way no real offsets can be zero.
   462  	size := int64(1)
   463  
   464  	// Walk the functions, finding offset to store each pcdata.
   465  	seen := make(map[loader.Sym]struct{})
   466  	saveOffset := func(pcSym loader.Sym) {
   467  		if _, ok := seen[pcSym]; !ok {
   468  			datSize := ldr.SymSize(pcSym)
   469  			if datSize != 0 {
   470  				ldr.SetSymValue(pcSym, size)
   471  			} else {
   472  				// Invalid PC data, record as zero.
   473  				ldr.SetSymValue(pcSym, 0)
   474  			}
   475  			size += datSize
   476  			seen[pcSym] = struct{}{}
   477  		}
   478  	}
   479  	var pcsp, pcline, pcfile, pcinline loader.Sym
   480  	var pcdata []loader.Sym
   481  	for _, s := range funcs {
   482  		fi := ldr.FuncInfo(s)
   483  		if !fi.Valid() {
   484  			continue
   485  		}
   486  		fi.Preload()
   487  		pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
   488  
   489  		pcSyms := []loader.Sym{pcsp, pcfile, pcline}
   490  		for _, pcSym := range pcSyms {
   491  			saveOffset(pcSym)
   492  		}
   493  		for _, pcSym := range pcdata {
   494  			saveOffset(pcSym)
   495  		}
   496  		if fi.NumInlTree() > 0 {
   497  			saveOffset(pcinline)
   498  		}
   499  	}
   500  
   501  	// TODO: There is no reason we need a generator for this variable, and it
   502  	// could be moved to a carrier symbol. However, carrier symbols containing
   503  	// carrier symbols don't work yet (as of Aug 2020). Once this is fixed,
   504  	// runtime.pctab could just be a carrier sym.
   505  	writePctab := func(ctxt *Link, s loader.Sym) {
   506  		ldr := ctxt.loader
   507  		sb := ldr.MakeSymbolUpdater(s)
   508  		for sym := range seen {
   509  			sb.SetBytesAt(ldr.SymValue(sym), ldr.Data(sym))
   510  		}
   511  	}
   512  
   513  	state.pctab = state.addGeneratedSym(ctxt, "runtime.pctab", size, writePctab)
   514  }
   515  
   516  // numPCData returns the number of PCData syms for the FuncInfo.
   517  // NB: Preload must be called on valid FuncInfos before calling this function.
   518  func numPCData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo) uint32 {
   519  	if !fi.Valid() {
   520  		return 0
   521  	}
   522  	numPCData := uint32(ldr.NumPcdata(s))
   523  	if fi.NumInlTree() > 0 {
   524  		if numPCData < objabi.PCDATA_InlTreeIndex+1 {
   525  			numPCData = objabi.PCDATA_InlTreeIndex + 1
   526  		}
   527  	}
   528  	return numPCData
   529  }
   530  
   531  // generateFunctab creates the runtime.functab
   532  //
   533  // runtime.functab contains two things:
   534  //
   535  //   - pc->func look up table.
   536  //   - array of func objects, interleaved with pcdata and funcdata
   537  func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
   538  	// Calculate the size of the table.
   539  	size, startLocations := state.calculateFunctabSize(ctxt, funcs)
   540  	writePcln := func(ctxt *Link, s loader.Sym) {
   541  		ldr := ctxt.loader
   542  		sb := ldr.MakeSymbolUpdater(s)
   543  		// Write the data.
   544  		writePCToFunc(ctxt, sb, funcs, startLocations)
   545  		writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets)
   546  	}
   547  	state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, writePcln)
   548  }
   549  
   550  // funcData returns the funcdata and offsets for the FuncInfo.
   551  // The funcdata are written into runtime.functab after each func
   552  // object. This is a helper function to make querying the FuncInfo object
   553  // cleaner.
   554  //
   555  // NB: Preload must be called on the FuncInfo before calling.
   556  // NB: fdSyms is used as scratch space.
   557  func funcData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo, inlSym loader.Sym, fdSyms []loader.Sym) []loader.Sym {
   558  	fdSyms = fdSyms[:0]
   559  	if fi.Valid() {
   560  		fdSyms = ldr.Funcdata(s, fdSyms)
   561  		if fi.NumInlTree() > 0 {
   562  			if len(fdSyms) < objabi.FUNCDATA_InlTree+1 {
   563  				fdSyms = append(fdSyms, make([]loader.Sym, objabi.FUNCDATA_InlTree+1-len(fdSyms))...)
   564  			}
   565  			fdSyms[objabi.FUNCDATA_InlTree] = inlSym
   566  		}
   567  	}
   568  	return fdSyms
   569  }
   570  
   571  // calculateFunctabSize calculates the size of the pclntab, and the offsets in
   572  // the output buffer for individual func entries.
   573  func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64, []uint32) {
   574  	ldr := ctxt.loader
   575  	startLocations := make([]uint32, len(funcs))
   576  
   577  	// Allocate space for the pc->func table. This structure consists of a pc offset
   578  	// and an offset to the func structure. After that, we have a single pc
   579  	// value that marks the end of the last function in the binary.
   580  	size := int64(int(state.nfunc)*2*4 + 4)
   581  
   582  	// Now find the space for the func objects. We do this in a running manner,
   583  	// so that we can find individual starting locations.
   584  	for i, s := range funcs {
   585  		size = Rnd(size, int64(ctxt.Arch.PtrSize))
   586  		startLocations[i] = uint32(size)
   587  		fi := ldr.FuncInfo(s)
   588  		size += funcSize
   589  		if fi.Valid() {
   590  			fi.Preload()
   591  			numFuncData := ldr.NumFuncdata(s)
   592  			if fi.NumInlTree() > 0 {
   593  				if numFuncData < objabi.FUNCDATA_InlTree+1 {
   594  					numFuncData = objabi.FUNCDATA_InlTree + 1
   595  				}
   596  			}
   597  			size += int64(numPCData(ldr, s, fi) * 4)
   598  			size += int64(numFuncData * 4)
   599  		}
   600  	}
   601  
   602  	return size, startLocations
   603  }
   604  
   605  // writePCToFunc writes the PC->func lookup table.
   606  func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32) {
   607  	ldr := ctxt.loader
   608  	textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
   609  	pcOff := func(s loader.Sym) uint32 {
   610  		off := ldr.SymValue(s) - textStart
   611  		if off < 0 {
   612  			panic(fmt.Sprintf("expected func %s(%x) to be placed at or after textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart))
   613  		}
   614  		return uint32(off)
   615  	}
   616  	for i, s := range funcs {
   617  		sb.SetUint32(ctxt.Arch, int64(i*2*4), pcOff(s))
   618  		sb.SetUint32(ctxt.Arch, int64((i*2+1)*4), startLocations[i])
   619  	}
   620  
   621  	// Final entry of table is just end pc offset.
   622  	lastFunc := funcs[len(funcs)-1]
   623  	sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, pcOff(lastFunc)+uint32(ldr.SymSize(lastFunc)))
   624  }
   625  
   626  // writeFuncs writes the func structures and pcdata to runtime.functab.
   627  func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
   628  	ldr := ctxt.loader
   629  	deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
   630  	gofunc := ldr.Lookup("go.func.*", 0)
   631  	gofuncBase := ldr.SymValue(gofunc)
   632  	textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
   633  	funcdata := []loader.Sym{}
   634  	var pcsp, pcfile, pcline, pcinline loader.Sym
   635  	var pcdata []loader.Sym
   636  
   637  	// Write the individual func objects.
   638  	for i, s := range funcs {
   639  		fi := ldr.FuncInfo(s)
   640  		if fi.Valid() {
   641  			fi.Preload()
   642  			pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
   643  		}
   644  
   645  		off := int64(startLocations[i])
   646  		// entry uintptr (offset of func entry PC from textStart)
   647  		entryOff := ldr.SymValue(s) - textStart
   648  		if entryOff < 0 {
   649  			panic(fmt.Sprintf("expected func %s(%x) to be placed before or at textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart))
   650  		}
   651  		off = sb.SetUint32(ctxt.Arch, off, uint32(entryOff))
   652  
   653  		// name int32
   654  		nameoff, ok := nameOffsets[s]
   655  		if !ok {
   656  			panic("couldn't find function name offset")
   657  		}
   658  		off = sb.SetUint32(ctxt.Arch, off, uint32(nameoff))
   659  
   660  		// args int32
   661  		// TODO: Move into funcinfo.
   662  		args := uint32(0)
   663  		if fi.Valid() {
   664  			args = uint32(fi.Args())
   665  		}
   666  		off = sb.SetUint32(ctxt.Arch, off, args)
   667  
   668  		// deferreturn
   669  		deferreturn := computeDeferReturn(ctxt, deferReturnSym, s)
   670  		off = sb.SetUint32(ctxt.Arch, off, deferreturn)
   671  
   672  		// pcdata
   673  		if fi.Valid() {
   674  			off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcsp)))
   675  			off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcfile)))
   676  			off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcline)))
   677  		} else {
   678  			off += 12
   679  		}
   680  		off = sb.SetUint32(ctxt.Arch, off, uint32(numPCData(ldr, s, fi)))
   681  
   682  		// Store the offset to compilation unit's file table.
   683  		cuIdx := ^uint32(0)
   684  		if cu := ldr.SymUnit(s); cu != nil {
   685  			cuIdx = cuOffsets[cu.PclnIndex]
   686  		}
   687  		off = sb.SetUint32(ctxt.Arch, off, cuIdx)
   688  
   689  		// funcID uint8
   690  		var funcID objabi.FuncID
   691  		if fi.Valid() {
   692  			funcID = fi.FuncID()
   693  		}
   694  		off = sb.SetUint8(ctxt.Arch, off, uint8(funcID))
   695  
   696  		// flag uint8
   697  		var flag objabi.FuncFlag
   698  		if fi.Valid() {
   699  			flag = fi.FuncFlag()
   700  		}
   701  		off = sb.SetUint8(ctxt.Arch, off, uint8(flag))
   702  
   703  		off += 1 // pad
   704  
   705  		// nfuncdata must be the final entry.
   706  		funcdata = funcData(ldr, s, fi, 0, funcdata)
   707  		off = sb.SetUint8(ctxt.Arch, off, uint8(len(funcdata)))
   708  
   709  		// Output the pcdata.
   710  		if fi.Valid() {
   711  			for j, pcSym := range pcdata {
   712  				sb.SetUint32(ctxt.Arch, off+int64(j*4), uint32(ldr.SymValue(pcSym)))
   713  			}
   714  			if fi.NumInlTree() > 0 {
   715  				sb.SetUint32(ctxt.Arch, off+objabi.PCDATA_InlTreeIndex*4, uint32(ldr.SymValue(pcinline)))
   716  			}
   717  		}
   718  
   719  		// Write funcdata refs as offsets from go.func.* and go.funcrel.*.
   720  		funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata)
   721  		// Missing funcdata will be ^0. See runtime/symtab.go:funcdata.
   722  		off = int64(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4)
   723  		for j := range funcdata {
   724  			dataoff := off + int64(4*j)
   725  			fdsym := funcdata[j]
   726  			if fdsym == 0 {
   727  				sb.SetUint32(ctxt.Arch, dataoff, ^uint32(0)) // ^0 is a sentinel for "no value"
   728  				continue
   729  			}
   730  
   731  			if outer := ldr.OuterSym(fdsym); outer != gofunc {
   732  				panic(fmt.Sprintf("bad carrier sym for symbol %s (funcdata %s#%d), want go.func.* got %s", ldr.SymName(fdsym), ldr.SymName(s), j, ldr.SymName(outer)))
   733  			}
   734  			sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase))
   735  		}
   736  	}
   737  }
   738  
   739  // pclntab initializes the pclntab symbol with
   740  // runtime function and file name information.
   741  
   742  // pclntab generates the pcln table for the link output.
   743  func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
   744  	// Go 1.2's symtab layout is documented in golang.org/s/go12symtab, but the
   745  	// layout and data has changed since that time.
   746  	//
   747  	// As of August 2020, here's the layout of pclntab:
   748  	//
   749  	//  .gopclntab/__gopclntab [elf/macho section]
   750  	//    runtime.pclntab
   751  	//      Carrier symbol for the entire pclntab section.
   752  	//
   753  	//      runtime.pcheader  (see: runtime/symtab.go:pcHeader)
   754  	//        8-byte magic
   755  	//        nfunc [thearch.ptrsize bytes]
   756  	//        offset to runtime.funcnametab from the beginning of runtime.pcheader
   757  	//        offset to runtime.pclntab_old from beginning of runtime.pcheader
   758  	//
   759  	//      runtime.funcnametab
   760  	//        []list of null terminated function names
   761  	//
   762  	//      runtime.cutab
   763  	//        for i=0..#CUs
   764  	//          for j=0..#max used file index in CU[i]
   765  	//            uint32 offset into runtime.filetab for the filename[j]
   766  	//
   767  	//      runtime.filetab
   768  	//        []null terminated filename strings
   769  	//
   770  	//      runtime.pctab
   771  	//        []byte of deduplicated pc data.
   772  	//
   773  	//      runtime.functab
   774  	//        function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
   775  	//        end PC [thearch.ptrsize bytes]
   776  	//        func structures, pcdata offsets, func data.
   777  
   778  	state, compUnits, funcs := makePclntab(ctxt, container)
   779  
   780  	ldr := ctxt.loader
   781  	state.carrier = ldr.LookupOrCreateSym("runtime.pclntab", 0)
   782  	ldr.MakeSymbolUpdater(state.carrier).SetType(sym.SPCLNTAB)
   783  	ldr.SetAttrReachable(state.carrier, true)
   784  	setCarrierSym(sym.SPCLNTAB, state.carrier)
   785  
   786  	state.generatePCHeader(ctxt)
   787  	nameOffsets := state.generateFuncnametab(ctxt, funcs)
   788  	cuOffsets := state.generateFilenameTabs(ctxt, compUnits, funcs)
   789  	state.generatePctab(ctxt, funcs)
   790  	inlSyms := makeInlSyms(ctxt, funcs, nameOffsets)
   791  	state.generateFunctab(ctxt, funcs, inlSyms, cuOffsets, nameOffsets)
   792  
   793  	return state
   794  }
   795  
   796  func gorootFinal() string {
   797  	root := buildcfg.GOROOT
   798  	if final := os.Getenv("GOROOT_FINAL"); final != "" {
   799  		root = final
   800  	}
   801  	return root
   802  }
   803  
   804  func expandGoroot(s string) string {
   805  	const n = len("$GOROOT")
   806  	if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
   807  		return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:]))
   808  	}
   809  	return s
   810  }
   811  
   812  const (
   813  	BUCKETSIZE    = 256 * MINFUNC
   814  	SUBBUCKETS    = 16
   815  	SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
   816  	NOIDX         = 0x7fffffff
   817  )
   818  
   819  // findfunctab generates a lookup table to quickly find the containing
   820  // function for a pc. See src/runtime/symtab.go:findfunc for details.
   821  func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) {
   822  	ldr := ctxt.loader
   823  
   824  	// find min and max address
   825  	min := ldr.SymValue(ctxt.Textp[0])
   826  	lastp := ctxt.Textp[len(ctxt.Textp)-1]
   827  	max := ldr.SymValue(lastp) + ldr.SymSize(lastp)
   828  
   829  	// for each subbucket, compute the minimum of all symbol indexes
   830  	// that map to that subbucket.
   831  	n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
   832  
   833  	nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
   834  
   835  	size := 4*int64(nbuckets) + int64(n)
   836  
   837  	writeFindFuncTab := func(_ *Link, s loader.Sym) {
   838  		t := ldr.MakeSymbolUpdater(s)
   839  
   840  		indexes := make([]int32, n)
   841  		for i := int32(0); i < n; i++ {
   842  			indexes[i] = NOIDX
   843  		}
   844  		idx := int32(0)
   845  		for i, s := range ctxt.Textp {
   846  			if !emitPcln(ctxt, s, container) {
   847  				continue
   848  			}
   849  			p := ldr.SymValue(s)
   850  			var e loader.Sym
   851  			i++
   852  			if i < len(ctxt.Textp) {
   853  				e = ctxt.Textp[i]
   854  			}
   855  			for e != 0 && !emitPcln(ctxt, e, container) && i < len(ctxt.Textp) {
   856  				e = ctxt.Textp[i]
   857  				i++
   858  			}
   859  			q := max
   860  			if e != 0 {
   861  				q = ldr.SymValue(e)
   862  			}
   863  
   864  			//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
   865  			for ; p < q; p += SUBBUCKETSIZE {
   866  				i = int((p - min) / SUBBUCKETSIZE)
   867  				if indexes[i] > idx {
   868  					indexes[i] = idx
   869  				}
   870  			}
   871  
   872  			i = int((q - 1 - min) / SUBBUCKETSIZE)
   873  			if indexes[i] > idx {
   874  				indexes[i] = idx
   875  			}
   876  			idx++
   877  		}
   878  
   879  		// fill in table
   880  		for i := int32(0); i < nbuckets; i++ {
   881  			base := indexes[i*SUBBUCKETS]
   882  			if base == NOIDX {
   883  				Errorf(nil, "hole in findfunctab")
   884  			}
   885  			t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
   886  			for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
   887  				idx = indexes[i*SUBBUCKETS+j]
   888  				if idx == NOIDX {
   889  					Errorf(nil, "hole in findfunctab")
   890  				}
   891  				if idx-base >= 256 {
   892  					Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
   893  				}
   894  
   895  				t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
   896  			}
   897  		}
   898  	}
   899  
   900  	state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SRODATA, size, writeFindFuncTab)
   901  	ldr.SetAttrReachable(state.findfunctab, true)
   902  	ldr.SetAttrLocal(state.findfunctab, true)
   903  }
   904  
   905  // findContainerSyms returns a bitmap, indexed by symbol number, where there's
   906  // a 1 for every container symbol.
   907  func (ctxt *Link) findContainerSyms() loader.Bitmap {
   908  	ldr := ctxt.loader
   909  	container := loader.MakeBitmap(ldr.NSym())
   910  	// Find container symbols and mark them as such.
   911  	for _, s := range ctxt.Textp {
   912  		outer := ldr.OuterSym(s)
   913  		if outer != 0 {
   914  			container.Set(outer)
   915  		}
   916  	}
   917  	return container
   918  }
   919  

View as plain text