github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/goobj/readnew.go (about)

     1  // Copyright 2019 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 goobj
     6  
     7  import (
     8  	"github.com/gagliardetto/golang-go/cmd/internal/goobj2"
     9  	"github.com/gagliardetto/golang-go/cmd/internal/objabi"
    10  	"fmt"
    11  	"strings"
    12  )
    13  
    14  // Read object file in new format. For now we still fill
    15  // the data to the current goobj API.
    16  func (r *objReader) readNew() {
    17  	start := uint32(r.offset)
    18  
    19  	length := r.limit - r.offset
    20  	objbytes := make([]byte, length)
    21  	r.readFull(objbytes)
    22  	rr := goobj2.NewReaderFromBytes(objbytes, false)
    23  	if rr == nil {
    24  		panic("cannot read object file")
    25  	}
    26  
    27  	// Imports
    28  	r.p.Imports = rr.Autolib()
    29  
    30  	pkglist := rr.Pkglist()
    31  
    32  	abiToVer := func(abi uint16) int64 {
    33  		var vers int64
    34  		if abi == goobj2.SymABIstatic {
    35  			// Static symbol
    36  			vers = r.p.MaxVersion
    37  		}
    38  		return vers
    39  	}
    40  
    41  	resolveSymRef := func(s goobj2.SymRef) SymID {
    42  		var i int
    43  		switch p := s.PkgIdx; p {
    44  		case goobj2.PkgIdxInvalid:
    45  			if s.SymIdx != 0 {
    46  				panic("bad sym ref")
    47  			}
    48  			return SymID{}
    49  		case goobj2.PkgIdxNone:
    50  			i = int(s.SymIdx) + rr.NSym()
    51  		case goobj2.PkgIdxBuiltin:
    52  			name, abi := goobj2.BuiltinName(int(s.SymIdx))
    53  			return SymID{name, int64(abi)}
    54  		case goobj2.PkgIdxSelf:
    55  			i = int(s.SymIdx)
    56  		default:
    57  			pkg := pkglist[p]
    58  			return SymID{fmt.Sprintf("%s.<#%d>", pkg, s.SymIdx), 0}
    59  		}
    60  		sym := goobj2.Sym{}
    61  		sym.Read(rr, rr.SymOff(i))
    62  		return SymID{sym.Name, abiToVer(sym.ABI)}
    63  	}
    64  
    65  	// Read things for the current goobj API for now.
    66  
    67  	// Symbols
    68  	pcdataBase := start + rr.PcdataBase()
    69  	n := rr.NSym() + rr.NNonpkgdef() + rr.NNonpkgref()
    70  	ndef := rr.NSym() + rr.NNonpkgdef()
    71  	for i := 0; i < n; i++ {
    72  		osym := goobj2.Sym{}
    73  		osym.Read(rr, rr.SymOff(i))
    74  		if osym.Name == "" {
    75  			continue // not a real symbol
    76  		}
    77  		// In a symbol name in an object file, "". denotes the
    78  		// prefix for the package in which the object file has been found.
    79  		// Expand it.
    80  		name := strings.ReplaceAll(osym.Name, `"".`, r.pkgprefix)
    81  		symID := SymID{Name: name, Version: abiToVer(osym.ABI)}
    82  		r.p.SymRefs = append(r.p.SymRefs, symID)
    83  
    84  		if i >= ndef {
    85  			continue // not a defined symbol from here
    86  		}
    87  
    88  		// Symbol data
    89  		dataOff := rr.DataOff(i)
    90  		siz := int64(rr.DataSize(i))
    91  
    92  		sym := Sym{
    93  			SymID: symID,
    94  			Kind:  objabi.SymKind(osym.Type),
    95  			DupOK: osym.Dupok(),
    96  			Size:  int64(osym.Siz),
    97  			Data:  Data{int64(start + dataOff), siz},
    98  		}
    99  		r.p.Syms = append(r.p.Syms, &sym)
   100  
   101  		// Reloc
   102  		nreloc := rr.NReloc(i)
   103  		sym.Reloc = make([]Reloc, nreloc)
   104  		for j := 0; j < nreloc; j++ {
   105  			rel := goobj2.Reloc{}
   106  			rel.Read(rr, rr.RelocOff(i, j))
   107  			sym.Reloc[j] = Reloc{
   108  				Offset: int64(rel.Off),
   109  				Size:   int64(rel.Siz),
   110  				Type:   objabi.RelocType(rel.Type),
   111  				Add:    rel.Add,
   112  				Sym:    resolveSymRef(rel.Sym),
   113  			}
   114  		}
   115  
   116  		// Aux symbol info
   117  		isym := -1
   118  		funcdata := make([]goobj2.SymRef, 0, 4)
   119  		naux := rr.NAux(i)
   120  		for j := 0; j < naux; j++ {
   121  			a := goobj2.Aux{}
   122  			a.Read(rr, rr.AuxOff(i, j))
   123  			switch a.Type {
   124  			case goobj2.AuxGotype:
   125  				sym.Type = resolveSymRef(a.Sym)
   126  			case goobj2.AuxFuncInfo:
   127  				if a.Sym.PkgIdx != goobj2.PkgIdxSelf {
   128  					panic("funcinfo symbol not defined in current package")
   129  				}
   130  				isym = int(a.Sym.SymIdx)
   131  			case goobj2.AuxFuncdata:
   132  				funcdata = append(funcdata, a.Sym)
   133  			case goobj2.AuxDwarfInfo, goobj2.AuxDwarfLoc, goobj2.AuxDwarfRanges, goobj2.AuxDwarfLines:
   134  				// nothing to do
   135  			default:
   136  				panic("unknown aux type")
   137  			}
   138  		}
   139  
   140  		// Symbol Info
   141  		if isym == -1 {
   142  			continue
   143  		}
   144  		b := rr.BytesAt(rr.DataOff(isym), rr.DataSize(isym))
   145  		info := goobj2.FuncInfo{}
   146  		info.Read(b)
   147  
   148  		info.Pcdata = append(info.Pcdata, info.PcdataEnd) // for the ease of knowing where it ends
   149  		f := &Func{
   150  			Args:     int64(info.Args),
   151  			Frame:    int64(info.Locals),
   152  			NoSplit:  info.NoSplit != 0,
   153  			Leaf:     osym.Leaf(),
   154  			TopFrame: osym.TopFrame(),
   155  			PCSP:     Data{int64(pcdataBase + info.Pcsp), int64(info.Pcfile - info.Pcsp)},
   156  			PCFile:   Data{int64(pcdataBase + info.Pcfile), int64(info.Pcline - info.Pcfile)},
   157  			PCLine:   Data{int64(pcdataBase + info.Pcline), int64(info.Pcinline - info.Pcline)},
   158  			PCInline: Data{int64(pcdataBase + info.Pcinline), int64(info.Pcdata[0] - info.Pcinline)},
   159  			PCData:   make([]Data, len(info.Pcdata)-1), // -1 as we appended one above
   160  			FuncData: make([]FuncData, len(info.Funcdataoff)),
   161  			File:     make([]string, len(info.File)),
   162  			InlTree:  make([]InlinedCall, len(info.InlTree)),
   163  		}
   164  		sym.Func = f
   165  		for k := range f.PCData {
   166  			f.PCData[k] = Data{int64(pcdataBase + info.Pcdata[k]), int64(info.Pcdata[k+1] - info.Pcdata[k])}
   167  		}
   168  		for k := range f.FuncData {
   169  			symID := resolveSymRef(funcdata[k])
   170  			f.FuncData[k] = FuncData{symID, int64(info.Funcdataoff[k])}
   171  		}
   172  		for k := range f.File {
   173  			symID := resolveSymRef(info.File[k])
   174  			f.File[k] = symID.Name
   175  		}
   176  		for k := range f.InlTree {
   177  			inl := &info.InlTree[k]
   178  			f.InlTree[k] = InlinedCall{
   179  				Parent:   int64(inl.Parent),
   180  				File:     resolveSymRef(inl.File).Name,
   181  				Line:     int64(inl.Line),
   182  				Func:     resolveSymRef(inl.Func),
   183  				ParentPC: int64(inl.ParentPC),
   184  			}
   185  		}
   186  	}
   187  }