| // 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 := goobj2.Sym{} |
| sym.Read(rr, rr.SymOff(i)) |
| return SymID{sym.Name, 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 := goobj2.Sym{} |
| osym.Read(rr, rr.SymOff(i)) |
| if osym.Name == "" { |
| 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, `"".`, 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 |
| nreloc := rr.NReloc(i) |
| sym.Reloc = make([]Reloc, nreloc) |
| for j := 0; j < nreloc; j++ { |
| rel := goobj2.Reloc{} |
| rel.Read(rr, rr.RelocOff(i, 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) |
| naux := rr.NAux(i) |
| for j := 0; j < naux; j++ { |
| a := goobj2.Aux{} |
| a.Read(rr, rr.AuxOff(i, 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: info.NoSplit != 0, |
| 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), |
| } |
| } |
| } |
| } |