// Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package goobj import ( "cmd/internal/goobj2" "cmd/internal/objabi" "fmt" "strings" ) // Read object file in new format. For now we still fill // the data to the current goobj API. func (r *objReader) readNew() { start := uint32(r.offset) length := r.limit - r.offset objbytes := make([]byte, length) r.readFull(objbytes) rr := goobj2.NewReaderFromBytes(objbytes, false) if rr == nil { panic("cannot read object file") } // Imports r.p.Imports = rr.Autolib() pkglist := rr.Pkglist() abiToVer := func(abi uint16) int64 { var vers int64 if abi == goobj2.SymABIstatic { // Static symbol vers = r.p.MaxVersion } return vers } resolveSymRef := func(s goobj2.SymRef) SymID { var i int switch p := s.PkgIdx; p { case goobj2.PkgIdxInvalid: if s.SymIdx != 0 { panic("bad sym ref") } return SymID{} case goobj2.PkgIdxNone: i = int(s.SymIdx) + rr.NSym() case goobj2.PkgIdxBuiltin: name, abi := goobj2.BuiltinName(int(s.SymIdx)) return SymID{name, int64(abi)} case goobj2.PkgIdxSelf: i = int(s.SymIdx) default: pkg := pkglist[p] return SymID{fmt.Sprintf("%s.<#%d>", pkg, s.SymIdx), 0} } sym := rr.Sym(i) return SymID{sym.Name(rr), abiToVer(sym.ABI())} } // Read things for the current goobj API for now. // Symbols pcdataBase := start + rr.PcdataBase() n := rr.NSym() + rr.NNonpkgdef() + rr.NNonpkgref() ndef := rr.NSym() + rr.NNonpkgdef() for i := 0; i < n; i++ { osym := rr.Sym(i) if osym.Name(rr) == "" { continue // not a real symbol } // In a symbol name in an object file, "". denotes the // prefix for the package in which the object file has been found. // Expand it. name := strings.ReplaceAll(osym.Name(rr), `"".`, r.pkgprefix) symID := SymID{Name: name, Version: abiToVer(osym.ABI())} r.p.SymRefs = append(r.p.SymRefs, symID) if i >= ndef { continue // not a defined symbol from here } // Symbol data dataOff := rr.DataOff(i) siz := int64(rr.DataSize(i)) sym := Sym{ SymID: symID, Kind: objabi.SymKind(osym.Type()), DupOK: osym.Dupok(), Size: int64(osym.Siz()), Data: Data{int64(start + dataOff), siz}, } r.p.Syms = append(r.p.Syms, &sym) // Reloc relocs := rr.Relocs(i) sym.Reloc = make([]Reloc, len(relocs)) for j := range relocs { rel := &relocs[j] sym.Reloc[j] = Reloc{ Offset: int64(rel.Off()), Size: int64(rel.Siz()), Type: objabi.RelocType(rel.Type()), Add: rel.Add(), Sym: resolveSymRef(rel.Sym()), } } // Aux symbol info isym := -1 funcdata := make([]goobj2.SymRef, 0, 4) auxs := rr.Auxs(i) for j := range auxs { a := &auxs[j] switch a.Type() { case goobj2.AuxGotype: sym.Type = resolveSymRef(a.Sym()) case goobj2.AuxFuncInfo: if a.Sym().PkgIdx != goobj2.PkgIdxSelf { panic("funcinfo symbol not defined in current package") } isym = int(a.Sym().SymIdx) case goobj2.AuxFuncdata: funcdata = append(funcdata, a.Sym()) case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines: // nothing to do default: panic("unknown aux type") } } // Symbol Info if isym == -1 { continue } b := rr.BytesAt(rr.DataOff(isym), rr.DataSize(isym)) info := goobj2.FuncInfo{} info.Read(b) info.Pcdata = append(info.Pcdata, info.PcdataEnd) // for the ease of knowing where it ends f := &Func{ Args: int64(info.Args), Frame: int64(info.Locals), NoSplit: osym.NoSplit(), Leaf: osym.Leaf(), TopFrame: osym.TopFrame(), PCSP: Data{int64(pcdataBase + info.Pcsp), int64(info.Pcfile - info.Pcsp)}, PCFile: Data{int64(pcdataBase + info.Pcfile), int64(info.Pcline - info.Pcfile)}, PCLine: Data{int64(pcdataBase + info.Pcline), int64(info.Pcinline - info.Pcline)}, PCInline: Data{int64(pcdataBase + info.Pcinline), int64(info.Pcdata[0] - info.Pcinline)}, PCData: make([]Data, len(info.Pcdata)-1), // -1 as we appended one above FuncData: make([]FuncData, len(info.Funcdataoff)), File: make([]string, len(info.File)), InlTree: make([]InlinedCall, len(info.InlTree)), } sym.Func = f for k := range f.PCData { f.PCData[k] = Data{int64(pcdataBase + info.Pcdata[k]), int64(info.Pcdata[k+1] - info.Pcdata[k])} } for k := range f.FuncData { symID := resolveSymRef(funcdata[k]) f.FuncData[k] = FuncData{symID, int64(info.Funcdataoff[k])} } for k := range f.File { symID := resolveSymRef(info.File[k]) f.File[k] = symID.Name } for k := range f.InlTree { inl := &info.InlTree[k] f.InlTree[k] = InlinedCall{ Parent: int64(inl.Parent), File: resolveSymRef(inl.File).Name, Line: int64(inl.Line), Func: resolveSymRef(inl.Func), ParentPC: int64(inl.ParentPC), } } } }