Skip to content
Snippets Groups Projects
readnew.go 4.99 KiB
Newer Older
  • Learn to ignore specific revisions
  • // 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"
    
    )
    
    // 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
    
    	autolib := rr.Autolib()
    	for _, p := range autolib {
    		r.p.Imports = append(r.p.Imports, p.Pkg)
    		// Ignore fingerprint (for tools like objdump which only reads one object).
    	}
    
    	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()),
    
    			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]
    
    				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() {
    
    				sym.Type = resolveSymRef(a.Sym())
    
    				if a.Sym().PkgIdx != goobj2.PkgIdxSelf {
    
    					panic("funcinfo symbol not defined in current package")
    				}
    
    				isym = int(a.Sym().SymIdx)
    
    				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),
    
    			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),
    			}
    		}