Skip to content
Snippets Groups Projects
loader.go 86.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • // container symbol C, but don't set Sub(C). Thus we have two
    // distinct scenarios:
    //
    // - Outer symbol covers the address ranges of its sub-symbols.
    //   Outer.Sub is set in this case.
    // - Outer symbol doesn't conver the address ranges. It is zero-sized
    //   and doesn't have sub-symbols. In the case, the inner symbol is
    //   not actually a "SubSymbol". (Tricky!)
    //
    // This method returns TRUE only for sub-symbols in the first scenario.
    //
    // FIXME: would be better to do away with this and have a better way
    // to represent container symbols.
    
    
    func (l *Loader) AttrSubSymbol(i Sym) bool {
    	// we don't explicitly store this attribute any more -- return
    	// a value based on the sub-symbol setting.
    
    	o := l.OuterSym(i)
    	if o == 0 {
    		return false
    	}
    	return l.SubSym(o) != 0
    
    // Note that we don't have a 'SetAttrSubSymbol' method in the loader;
    // clients should instead use the PrependSub method to establish
    // outer/sub relationships for host object symbols.
    
    // Returns whether the i-th symbol has ReflectMethod attribute set.
    func (l *Loader) IsReflectMethod(i Sym) bool {
    	return l.SymAttr(i)&goobj2.SymFlagReflectMethod != 0
    }
    
    
    // Returns whether the i-th symbol is nosplit.
    func (l *Loader) IsNoSplit(i Sym) bool {
    	return l.SymAttr(i)&goobj2.SymFlagNoSplit != 0
    }
    
    
    // Returns whether this is a Go type symbol.
    func (l *Loader) IsGoType(i Sym) bool {
    	return l.SymAttr(i)&goobj2.SymFlagGoType != 0
    }
    
    
    // Returns whether this symbol should be included in typelink.
    func (l *Loader) IsTypelink(i Sym) bool {
    	return l.SymAttr(i)&goobj2.SymFlagTypelink != 0
    }
    
    
    // Returns whether this is a "go.itablink.*" symbol.
    func (l *Loader) IsItabLink(i Sym) bool {
    	if _, ok := l.itablink[i]; ok {
    		return true
    	}
    	return false
    }
    
    
    // growValues grows the slice used to store symbol values.
    func (l *Loader) growValues(reqLen int) {
    	curLen := len(l.values)
    	if reqLen > curLen {
    		l.values = append(l.values, make([]int64, reqLen+1-curLen)...)
    	}
    }
    
    // SymValue returns the value of the i-th symbol. i is global index.
    func (l *Loader) SymValue(i Sym) int64 {
    	return l.values[i]
    }
    
    // SetSymValue sets the value of the i-th symbol. i is global index.
    func (l *Loader) SetSymValue(i Sym, val int64) {
    	l.values[i] = val
    }
    
    
    // AddToSymValue adds to the value of the i-th symbol. i is the global index.
    func (l *Loader) AddToSymValue(i Sym, val int64) {
    	l.values[i] += val
    }
    
    
    // Returns the symbol content of the i-th symbol. i is global index.
    func (l *Loader) Data(i Sym) []byte {
    
    // Returns the data of the i-th symbol in the output buffer.
    func (l *Loader) OutData(i Sym) []byte {
    	if int(i) < len(l.outdata) && l.outdata[i] != nil {
    		return l.outdata[i]
    	}
    	return l.Data(i)
    }
    
    // SetOutData sets the position of the data of the i-th symbol in the output buffer.
    // i is global index.
    func (l *Loader) SetOutData(i Sym, data []byte) {
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    		if pp != nil {
    			pp.data = data
    			return
    		}
    	}
    	l.outdata[i] = data
    }
    
    // InitOutData initializes the slice used to store symbol output data.
    func (l *Loader) InitOutData() {
    	l.outdata = make([][]byte, l.extStart)
    }
    
    
    // SetExtRelocs sets the section of the i-th symbol. i is global index.
    func (l *Loader) SetExtRelocs(i Sym, relocs []ExtReloc) {
    	l.extRelocs[i] = relocs
    }
    
    // InitExtRelocs initialize the slice used to store external relocations.
    func (l *Loader) InitExtRelocs() {
    	l.extRelocs = make([][]ExtReloc, l.NSym())
    }
    
    
    // SymAlign returns the alignment for a symbol.
    func (l *Loader) SymAlign(i Sym) int32 {
    	// If an alignment has been recorded, return that.
    	if align, ok := l.align[i]; ok {
    		return align
    	}
    	// TODO: would it make sense to return an arch-specific
    	// alignment depending on section type? E.g. STEXT => 32,
    	// SDATA => 1, etc?
    	return 0
    }
    
    // SetSymAlign sets the alignment for a symbol.
    func (l *Loader) SetSymAlign(i Sym, align int32) {
    	// reject bad synbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetSymAlign")
    	}
    	// Reject nonsense alignments.
    	// TODO: do we need this?
    	if align < 0 {
    		panic("bad alignment value")
    	}
    	if align == 0 {
    		delete(l.align, i)
    	} else {
    		// Alignment should be a power of 2.
    		if bits.OnesCount32(uint32(align)) != 1 {
    			panic("bad alignment value")
    		}
    		l.align[i] = align
    	}
    }
    
    
    // SymValue returns the section of the i-th symbol. i is global index.
    func (l *Loader) SymSect(i Sym) *sym.Section {
    
    	if int(i) >= len(l.symSects) {
    		// symSects is extended lazily -- it the sym in question is
    		// outside the range of the existing slice, then we assume its
    		// section has not yet been set.
    		return nil
    	}
    
    }
    
    // SetSymValue sets the section of the i-th symbol. i is global index.
    func (l *Loader) SetSymSect(i Sym, sect *sym.Section) {
    
    	if int(i) >= len(l.symSects) {
    		l.symSects = append(l.symSects, make([]uint16, l.NSym()-len(l.symSects))...)
    	}
    	l.symSects[i] = sect.Index
    }
    
    // growSects grows the slice used to store symbol sections.
    func (l *Loader) growSects(reqLen int) {
    	curLen := len(l.symSects)
    	if reqLen > curLen {
    		l.symSects = append(l.symSects, make([]uint16, reqLen+1-curLen)...)
    	}
    }
    
    // NewSection creates a new (output) section.
    func (l *Loader) NewSection() *sym.Section {
    	sect := new(sym.Section)
    	idx := len(l.sects)
    	if idx != int(uint16(idx)) {
    		panic("too many sections created")
    	}
    	sect.Index = uint16(idx)
    	l.sects = append(l.sects, sect)
    	return sect
    
    // SymDynImplib returns the "dynimplib" attribute for the specified
    // symbol, making up a portion of the info for a symbol specified
    // on a "cgo_import_dynamic" compiler directive.
    func (l *Loader) SymDynimplib(i Sym) string {
    	return l.dynimplib[i]
    }
    
    // SetSymDynimplib sets the "dynimplib" attribute for a symbol.
    func (l *Loader) SetSymDynimplib(i Sym, value string) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetDynimplib")
    	}
    	if value == "" {
    		delete(l.dynimplib, i)
    	} else {
    		l.dynimplib[i] = value
    	}
    }
    
    // SymDynimpvers returns the "dynimpvers" attribute for the specified
    // symbol, making up a portion of the info for a symbol specified
    // on a "cgo_import_dynamic" compiler directive.
    func (l *Loader) SymDynimpvers(i Sym) string {
    	return l.dynimpvers[i]
    }
    
    // SetSymDynimpvers sets the "dynimpvers" attribute for a symbol.
    func (l *Loader) SetSymDynimpvers(i Sym, value string) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetDynimpvers")
    	}
    	if value == "" {
    		delete(l.dynimpvers, i)
    	} else {
    		l.dynimpvers[i] = value
    	}
    }
    
    // SymExtname returns the "extname" value for the specified
    // symbol.
    func (l *Loader) SymExtname(i Sym) string {
    
    	if s, ok := l.extname[i]; ok {
    		return s
    	}
    	return l.SymName(i)
    
    }
    
    // SetSymExtname sets the  "extname" attribute for a symbol.
    func (l *Loader) SetSymExtname(i Sym, value string) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetExtname")
    	}
    	if value == "" {
    		delete(l.extname, i)
    	} else {
    		l.extname[i] = value
    	}
    }
    
    
    // SymElfType returns the previously recorded ELF type for a symbol
    // (used only for symbols read from shared libraries by ldshlibsyms).
    // It is not set for symbols defined by the packages being linked or
    // by symbols read by ldelf (and so is left as elf.STT_NOTYPE).
    func (l *Loader) SymElfType(i Sym) elf.SymType {
    	if et, ok := l.elfType[i]; ok {
    		return et
    	}
    	return elf.STT_NOTYPE
    }
    
    
    // SetSymElfType sets the elf type attribute for a symbol.
    
    func (l *Loader) SetSymElfType(i Sym, et elf.SymType) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetSymElfType")
    	}
    	if et == elf.STT_NOTYPE {
    		delete(l.elfType, i)
    	} else {
    		l.elfType[i] = et
    	}
    }
    
    
    // SymElfSym returns the ELF symbol index for a given loader
    // symbol, assigned during ELF symtab generation.
    func (l *Loader) SymElfSym(i Sym) int32 {
    	return l.elfSym[i]
    }
    
    // SetSymElfSym sets the elf symbol index for a symbol.
    func (l *Loader) SetSymElfSym(i Sym, es int32) {
    	if i == 0 {
    		panic("bad sym index")
    	}
    	if es == 0 {
    		delete(l.elfSym, i)
    	} else {
    		l.elfSym[i] = es
    	}
    }
    
    // SymLocalElfSym returns the "local" ELF symbol index for a given loader
    // symbol, assigned during ELF symtab generation.
    func (l *Loader) SymLocalElfSym(i Sym) int32 {
    	return l.localElfSym[i]
    }
    
    // SetSymLocalElfSym sets the "local" elf symbol index for a symbol.
    func (l *Loader) SetSymLocalElfSym(i Sym, es int32) {
    	if i == 0 {
    		panic("bad sym index")
    	}
    	if es == 0 {
    		delete(l.localElfSym, i)
    	} else {
    		l.localElfSym[i] = es
    	}
    }
    
    
    // SymPlt returns the plt value for pe symbols.
    func (l *Loader) SymPlt(s Sym) int32 {
    	if v, ok := l.plt[s]; ok {
    		return v
    	}
    	return -1
    }
    
    
    // SetPlt sets the plt value for pe symbols.
    func (l *Loader) SetPlt(i Sym, v int32) {
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol for SetPlt")
    	}
    
    // SymGot returns the got value for pe symbols.
    func (l *Loader) SymGot(s Sym) int32 {
    	if v, ok := l.got[s]; ok {
    		return v
    	}
    	return -1
    }
    
    
    // SetGot sets the got value for pe symbols.
    func (l *Loader) SetGot(i Sym, v int32) {
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    // SymDynid returns the "dynid" property for the specified symbol.
    func (l *Loader) SymDynid(i Sym) int32 {
    	if s, ok := l.dynid[i]; ok {
    		return s
    	}
    	return -1
    }
    
    // SetSymDynid sets the "dynid" property for a symbol.
    func (l *Loader) SetSymDynid(i Sym, val int32) {
    	// reject bad symbols
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    		panic("bad symbol index in SetSymDynid")
    	}
    	if val == -1 {
    		delete(l.dynid, i)
    	} else {
    		l.dynid[i] = val
    	}
    }
    
    
    // DynIdSyms returns the set of symbols for which dynID is set to an
    // interesting (non-default) value. This is expected to be a fairly
    // small set.
    func (l *Loader) DynidSyms() []Sym {
    	sl := make([]Sym, 0, len(l.dynid))
    	for s := range l.dynid {
    		sl = append(sl, s)
    	}
    
    	sort.Slice(sl, func(i, j int) bool { return sl[i] < sl[j] })
    
    // SymGoType returns the 'Gotype' property for a given symbol (set by
    // the Go compiler for variable symbols). This version relies on
    // reading aux symbols for the target sym -- it could be that a faster
    // approach would be to check for gotype during preload and copy the
    // results in to a map (might want to try this at some point and see
    // if it helps speed things up).
    func (l *Loader) SymGoType(i Sym) Sym {
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    		return pp.gotype
    	}
    	r, li := l.toLocal(i)
    
    	auxs := r.Auxs(li)
    
    	for j := range auxs {
    		a := &auxs[j]
    		switch a.Type() {
    
    		}
    	}
    	return 0
    }
    
    // SymUnit returns the compilation unit for a given symbol (which will
    // typically be nil for external or linker-manufactured symbols).
    func (l *Loader) SymUnit(i Sym) *sym.CompilationUnit {
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    		if pp.objidx != 0 {
    			r := l.objs[pp.objidx].r
    			return r.unit
    		}
    		return nil
    	}
    	r, _ := l.toLocal(i)
    	return r.unit
    }
    
    
    // SymPkg returns the package where the symbol came from (for
    // regular compiler-generated Go symbols), but in the case of
    // building with "-linkshared" (when a symbol is read from a
    // shared library), will hold the library name.
    // NOTE: this correspondes to sym.Symbol.File field.
    func (l *Loader) SymPkg(i Sym) string {
    
    	if f, ok := l.symPkg[i]; ok {
    		return f
    	}
    
    	if l.IsExternal(i) {
    		pp := l.getPayload(i)
    		if pp.objidx != 0 {
    			r := l.objs[pp.objidx].r
    
    // SetSymPkg sets the package/library for a symbol. This is
    
    // needed mainly for external symbols, specifically those imported
    // from shared libraries.
    
    func (l *Loader) SetSymPkg(i Sym, pkg string) {
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetSymPkg")
    
    // SymLocalentry returns the "local entry" value for the specified
    // symbol.
    func (l *Loader) SymLocalentry(i Sym) uint8 {
    	return l.localentry[i]
    }
    
    
    // SetSymLocalentry sets the "local entry" attribute for a symbol.
    
    func (l *Loader) SetSymLocalentry(i Sym, value uint8) {
    	// reject bad symbols
    
    	if i >= Sym(len(l.objSyms)) || i == 0 {
    
    		panic("bad symbol index in SetSymLocalentry")
    
    	}
    	if value == 0 {
    		delete(l.localentry, i)
    	} else {
    		l.localentry[i] = value
    	}
    }
    
    
    // Returns the number of aux symbols given a global index.
    func (l *Loader) NAux(i Sym) int {
    
    // Returns the "handle" to the j-th aux symbol of the i-th symbol.
    func (l *Loader) Aux2(i Sym, j int) Aux2 {
    	if l.IsExternal(i) {
    		return Aux2{}
    	}
    	r, li := l.toLocal(i)
    	if j >= r.NAux(li) {
    		return Aux2{}
    	}
    
    	return Aux2{r.Aux(li, j), r, l}
    
    // GetFuncDwarfAuxSyms collects and returns the auxiliary DWARF
    // symbols associated with a given function symbol.  Prior to the
    // introduction of the loader, this was done purely using name
    // lookups, e.f. for function with name XYZ we would then look up
    // go.info.XYZ, etc.
    // FIXME: once all of dwarfgen is converted over to the loader,
    // it would save some space to make these aux symbols nameless.
    func (l *Loader) GetFuncDwarfAuxSyms(fnSymIdx Sym) (auxDwarfInfo, auxDwarfLoc, auxDwarfRanges, auxDwarfLines Sym) {
    	if l.SymType(fnSymIdx) != sym.STEXT {
    		log.Fatalf("error: non-function sym %d/%s t=%s passed to GetFuncDwarfAuxSyms", fnSymIdx, l.SymName(fnSymIdx), l.SymType(fnSymIdx).String())
    	}
    	if l.IsExternal(fnSymIdx) {
    		// Current expectation is that any external function will
    		// not have auxsyms.
    		return
    	}
    	r, li := l.toLocal(fnSymIdx)
    
    	auxs := r.Auxs(li)
    
    	for i := range auxs {
    		a := &auxs[i]
    		switch a.Type() {
    
    			auxDwarfInfo = l.resolve(r, a.Sym())
    
    			if l.SymType(auxDwarfInfo) != sym.SDWARFINFO {
    				panic("aux dwarf info sym with wrong type")
    			}
    		case goobj2.AuxDwarfLoc:
    
    			auxDwarfLoc = l.resolve(r, a.Sym())
    
    			if l.SymType(auxDwarfLoc) != sym.SDWARFLOC {
    				panic("aux dwarf loc sym with wrong type")
    			}
    		case goobj2.AuxDwarfRanges:
    
    			auxDwarfRanges = l.resolve(r, a.Sym())
    
    			if l.SymType(auxDwarfRanges) != sym.SDWARFRANGE {
    				panic("aux dwarf ranges sym with wrong type")
    			}
    		case goobj2.AuxDwarfLines:
    
    			auxDwarfLines = l.resolve(r, a.Sym())
    
    			if l.SymType(auxDwarfLines) != sym.SDWARFLINES {
    				panic("aux dwarf lines sym with wrong type")
    			}
    		}
    	}
    	return
    }
    
    
    // PrependSub prepends 'sub' onto the sub list for outer symbol 'outer'.
    // Will panic if 'sub' already has an outer sym or sub sym.
    // FIXME: should this be instead a method on SymbolBuilder?
    func (l *Loader) PrependSub(outer Sym, sub Sym) {
    	// NB: this presupposes that an outer sym can't be a sub symbol of
    	// some other outer-outer sym (I'm assuming this is true, but I
    	// haven't tested exhaustively).
    	if l.OuterSym(outer) != 0 {
    		panic("outer has outer itself")
    	}
    	if l.SubSym(sub) != 0 {
    		panic("sub set for subsym")
    	}
    	if l.OuterSym(sub) != 0 {
    		panic("outer already set for subsym")
    	}
    	l.sub[sub] = l.sub[outer]
    	l.sub[outer] = sub
    	l.outer[sub] = outer
    }
    
    
    // OuterSym gets the outer symbol for host object loaded symbols.
    func (l *Loader) OuterSym(i Sym) Sym {
    
    	// FIXME: add check for isExternal?
    	return l.outer[i]
    
    // SubSym gets the subsymbol for host object loaded symbols.
    
    func (l *Loader) SubSym(i Sym) Sym {
    
    	// NB: note -- no check for l.isExternal(), since I am pretty sure
    	// that later phases in the linker set subsym for "type." syms
    	return l.sub[i]
    
    // SetOuterSym sets the outer symbol of i to o (without setting
    // sub symbols).
    func (l *Loader) SetOuterSym(i Sym, o Sym) {
    	if o != 0 {
    		l.outer[i] = o
    	} else {
    		delete(l.outer, i)
    	}
    }
    
    
    // Initialize Reachable bitmap and its siblings for running deadcode pass.
    
    func (l *Loader) InitReachable() {
    
    	l.growAttrBitmaps(l.NSym() + 1)
    
    type symWithVal struct {
    	s Sym
    	v int64
    }
    type bySymValue []symWithVal
    
    func (s bySymValue) Len() int           { return len(s) }
    func (s bySymValue) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    func (s bySymValue) Less(i, j int) bool { return s[i].v < s[j].v }
    
    // SortSub walks through the sub-symbols for 's' and sorts them
    // in place by increasing value. Return value is the new
    // sub symbol for the specified outer symbol.
    func (l *Loader) SortSub(s Sym) Sym {
    
    	if s == 0 || l.sub[s] == 0 {
    		return s
    	}
    
    	// Sort symbols using a slice first. Use a stable sort on the off
    	// chance that there's more than once symbol with the same value,
    	// so as to preserve reproducible builds.
    	sl := []symWithVal{}
    	for ss := l.sub[s]; ss != 0; ss = l.sub[ss] {
    		sl = append(sl, symWithVal{s: ss, v: l.SymValue(ss)})
    	}
    	sort.Stable(bySymValue(sl))
    
    	// Then apply any changes needed to the sub map.
    	ns := Sym(0)
    	for i := len(sl) - 1; i >= 0; i-- {
    		s := sl[i].s
    		l.sub[s] = ns
    		ns = s
    	}
    
    	// Update sub for outer symbol, then return
    	l.sub[s] = sl[0].s
    	return sl[0].s
    }
    
    
    // Insure that reachable bitmap and its siblings have enough size.
    func (l *Loader) growAttrBitmaps(reqLen int) {
    
    	if reqLen > l.attrReachable.Len() {
    
    		// These are indexed by global symbol
    		l.attrReachable = growBitmap(reqLen, l.attrReachable)
    
    		l.attrOnList = growBitmap(reqLen, l.attrOnList)
    
    		l.attrLocal = growBitmap(reqLen, l.attrLocal)
    
    		l.attrNotInSymbolTable = growBitmap(reqLen, l.attrNotInSymbolTable)
    
    	l.growExtAttrBitmaps()
    }
    
    func (l *Loader) growExtAttrBitmaps() {
    	// These are indexed by external symbol index (e.g. l.extIndex(i))
    	extReqLen := len(l.payloads)
    
    	if extReqLen > l.attrVisibilityHidden.Len() {
    
    		l.attrVisibilityHidden = growBitmap(extReqLen, l.attrVisibilityHidden)
    		l.attrDuplicateOK = growBitmap(extReqLen, l.attrDuplicateOK)
    		l.attrShared = growBitmap(extReqLen, l.attrShared)
    		l.attrExternal = growBitmap(extReqLen, l.attrExternal)
    
    func (relocs *Relocs) Count() int { return len(relocs.rs) }
    
    
    // At2 returns the j-th reloc for a global symbol.
    
    func (relocs *Relocs) At2(j int) Reloc2 {
    	if relocs.l.isExtReader(relocs.r) {
    
    		pp := relocs.l.payloads[relocs.li]
    
    		return Reloc2{&relocs.rs[j], relocs.r, relocs.l, pp.reltypes[j]}
    
    	return Reloc2{&relocs.rs[j], relocs.r, relocs.l, 0}
    
    // Relocs returns a Relocs object for the given global sym.
    func (l *Loader) Relocs(i Sym) Relocs {
    
    	if r == nil {
    		panic(fmt.Sprintf("trying to get oreader for invalid sym %d\n\n", i))
    	}
    
    	return l.relocs(r, li)
    }
    
    // Relocs returns a Relocs object given a local sym index and reader.
    func (l *Loader) relocs(r *oReader, li int) Relocs {
    
    	var rs []goobj2.Reloc
    
    	if l.isExtReader(r) {
    		pp := l.payloads[li]
    
    		rs = r.Relocs(li)
    
    // RelocByOff implements sort.Interface for sorting relocations by offset.
    
    type RelocByOff []Reloc
    
    func (x RelocByOff) Len() int           { return len(x) }
    func (x RelocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
    func (x RelocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
    
    
    // FuncInfo provides hooks to access goobj2.FuncInfo in the objects.
    type FuncInfo struct {
    
    }
    
    func (fi *FuncInfo) Valid() bool { return fi.r != nil }
    
    
    func (fi *FuncInfo) Args() int {
    	return int((*goobj2.FuncInfo)(nil).ReadArgs(fi.data))
    }
    
    
    func (fi *FuncInfo) Locals() int {
    	return int((*goobj2.FuncInfo)(nil).ReadLocals(fi.data))
    }
    
    func (fi *FuncInfo) Pcsp() []byte {
    	pcsp, end := (*goobj2.FuncInfo)(nil).ReadPcsp(fi.data)
    	return fi.r.BytesAt(fi.r.PcdataBase()+pcsp, int(end-pcsp))
    }
    
    
    func (fi *FuncInfo) Pcfile() []byte {
    	pcf, end := (*goobj2.FuncInfo)(nil).ReadPcfile(fi.data)
    	return fi.r.BytesAt(fi.r.PcdataBase()+pcf, int(end-pcf))
    }
    
    func (fi *FuncInfo) Pcline() []byte {
    	pcln, end := (*goobj2.FuncInfo)(nil).ReadPcline(fi.data)
    	return fi.r.BytesAt(fi.r.PcdataBase()+pcln, int(end-pcln))
    }
    
    // Preload has to be called prior to invoking the various methods
    // below related to pcdata, funcdataoff, files, and inltree nodes.
    func (fi *FuncInfo) Preload() {
    	fi.lengths = (*goobj2.FuncInfo)(nil).ReadFuncInfoLengths(fi.data)
    }
    
    func (fi *FuncInfo) Pcinline() []byte {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	pcinl, end := (*goobj2.FuncInfo)(nil).ReadPcinline(fi.data, fi.lengths.PcdataOff)
    	return fi.r.BytesAt(fi.r.PcdataBase()+pcinl, int(end-pcinl))
    }
    
    func (fi *FuncInfo) NumPcdata() uint32 {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	return fi.lengths.NumPcdata
    }
    
    func (fi *FuncInfo) Pcdata(k int) []byte {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	pcdat, end := (*goobj2.FuncInfo)(nil).ReadPcdata(fi.data, fi.lengths.PcdataOff, uint32(k))
    	return fi.r.BytesAt(fi.r.PcdataBase()+pcdat, int(end-pcdat))
    }
    
    func (fi *FuncInfo) NumFuncdataoff() uint32 {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	return fi.lengths.NumFuncdataoff
    }
    
    func (fi *FuncInfo) Funcdataoff(k int) int64 {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	return (*goobj2.FuncInfo)(nil).ReadFuncdataoff(fi.data, fi.lengths.FuncdataoffOff, uint32(k))
    }
    
    
    func (fi *FuncInfo) Funcdata(syms []Sym) []Sym {
    
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	if int(fi.lengths.NumFuncdataoff) > cap(syms) {
    		syms = make([]Sym, 0, fi.lengths.NumFuncdataoff)
    	} else {
    		syms = syms[:0]
    	}
    
    	for j := range fi.auxs {
    		a := &fi.auxs[j]
    
    		if a.Type() == goobj2.AuxFuncdata {
    			syms = append(syms, fi.l.resolve(fi.r, a.Sym()))
    		}
    	}
    	return syms
    }
    
    func (fi *FuncInfo) NumFile() uint32 {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	return fi.lengths.NumFile
    }
    
    func (fi *FuncInfo) File(k int) Sym {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	sr := (*goobj2.FuncInfo)(nil).ReadFile(fi.data, fi.lengths.FileOff, uint32(k))
    	return fi.l.resolve(fi.r, sr)
    }
    
    type InlTreeNode struct {
    	Parent   int32
    	File     Sym
    	Line     int32
    	Func     Sym
    	ParentPC int32
    }
    
    func (fi *FuncInfo) NumInlTree() uint32 {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	return fi.lengths.NumInlTree
    }
    
    func (fi *FuncInfo) InlTree(k int) InlTreeNode {
    	if !fi.lengths.Initialized {
    		panic("need to call Preload first")
    	}
    	node := (*goobj2.FuncInfo)(nil).ReadInlTree(fi.data, fi.lengths.InlTreeOff, uint32(k))
    	return InlTreeNode{
    		Parent:   node.Parent,
    		File:     fi.l.resolve(fi.r, node.File),
    		Line:     node.Line,
    		Func:     fi.l.resolve(fi.r, node.Func),
    		ParentPC: node.ParentPC,
    	}
    }
    
    	var auxs []goobj2.Aux
    
    		pp := l.getPayload(i)
    		if pp.objidx == 0 {
    			return FuncInfo{}
    		}
    		r = l.objs[pp.objidx].r
    		auxs = pp.auxs
    	} else {
    		var li int
    		r, li = l.toLocal(i)
    
    		auxs = r.Auxs(li)
    
    	for j := range auxs {
    		a := &auxs[j]
    		if a.Type() == goobj2.AuxFuncInfo {
    			b := r.Data(int(a.Sym().SymIdx))
    
    			return FuncInfo{l, r, b, auxs, goobj2.FuncInfoLengths{}}
    
    // Preload a package: add autolibs, add defined package symbols to the symbol table.
    // Does not add non-package symbols yet, which will be done in LoadNonpkgSyms.
    // Does not read symbol data.
    
    // Returns the fingerprint of the object.
    func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj2.FingerprintType {
    
    	roObject, readonly, err := f.Slice(uint64(length))
    	if err != nil {
    		log.Fatal("cannot read object file:", err)
    	}
    	r := goobj2.NewReaderFromBytes(roObject, readonly)
    
    		if len(roObject) >= 8 && bytes.Equal(roObject[:8], []byte("\x00go114ld")) {
    			log.Fatalf("found object file %s in old format, but -go115newobj is true\nset -go115newobj consistently in all -gcflags, -asmflags, and -ldflags", f.File().Name())
    		}
    
    		panic("cannot read object file")
    	}
    	localSymVersion := syms.IncVersion()
    	pkgprefix := objabi.PathToPrefix(lib.Pkg) + "."
    
    	ndef := r.NSym()
    	nnonpkgdef := r.NNonpkgdef()
    
    	or := &oReader{r, unit, localSymVersion, r.Flags(), pkgprefix, make([]Sym, ndef+nnonpkgdef+r.NNonpkgref()), ndef, uint32(len(l.objs))}
    
    	lib.Autolib = append(lib.Autolib, r.Autolib()...)
    
    	// DWARF file table
    	nfile := r.NDwarfFile()
    	unit.DWARFFileTable = make([]string, nfile)
    	for i := range unit.DWARFFileTable {
    		unit.DWARFFileTable[i] = r.DwarfFile(i)
    	}
    
    
    	l.addObj(lib.Pkg, or)
    	l.preloadSyms(or, pkgDef)
    
    	// The caller expects us consuming all the data
    	f.MustSeek(length, os.SEEK_CUR)
    
    }
    
    // Preload symbols of given kind from an object.
    func (l *Loader) preloadSyms(r *oReader, kind int) {
    	ndef := r.NSym()
    	nnonpkgdef := r.NNonpkgdef()
    	var start, end int
    	switch kind {
    	case pkgDef:
    		start = 0
    		end = ndef
    	case nonPkgDef:
    		start = ndef
    		end = ndef + nnonpkgdef
    	default:
    		panic("preloadSyms: bad kind")
    	}
    	l.growSyms(len(l.objSyms) + end - start)
    	l.growAttrBitmaps(len(l.objSyms) + end - start)
    	for i := start; i < end; i++ {
    
    		osym := r.Sym(i)
    
    		name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
    		v := abiToVer(osym.ABI(), r.version)
    
    		gi, added := l.AddSym(name, v, r, i, kind, dupok, sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type())])
    
    		if osym.TopFrame() {
    			l.SetAttrTopFrame(gi, true)
    		}
    
    		if osym.Local() {
    			l.SetAttrLocal(gi, true)
    		}
    
    		if strings.HasPrefix(name, "go.itablink.") {
    
    			l.itablink[gi] = struct{}{}
    
    		if strings.HasPrefix(name, "runtime.") {
    
    			if bi := goobj2.BuiltinIdx(name, v); bi != -1 {
    				// This is a definition of a builtin symbol. Record where it is.
    
    		if strings.HasPrefix(name, "go.string.") ||
    
    			strings.HasPrefix(name, "gclocals·") ||
    
    			strings.HasPrefix(name, "runtime.gcbits.") {
    
    			l.SetAttrNotInSymbolTable(gi, true)
    
    		if a := osym.Align(); a != 0 {
    			l.SetSymAlign(gi, int32(a))
    		}
    
    // Add non-package symbols and references to external symbols (which are always
    // named).
    
    func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
    
    	for _, o := range l.objs[1:] {
    		l.preloadSyms(o.r, nonPkgDef)
    	}
    
    func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
    
    	ndef := r.NSym() + r.NNonpkgdef()
    	for i, n := 0, r.NNonpkgref(); i < n; i++ {
    
    		osym := r.Sym(ndef + i)
    
    		name := strings.Replace(osym.Name(r.Reader), "\"\".", r.pkgprefix, -1)
    		v := abiToVer(osym.ABI(), r.version)
    
    		r.syms[ndef+i] = l.LookupOrCreateSym(name, v)
    
    		if osym.Local() {
    			l.SetAttrLocal(gi, true)
    		}
    
    	}
    }
    
    func abiToVer(abi uint16, localSymVersion int) int {
    	var v int
    	if abi == goobj2.SymABIstatic {
    		// Static
    		v = localSymVersion
    	} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {