github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/internal/obj/objfile.go (about)

     1  // Copyright 2013 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  // Writing of Go object files.
     6  
     7  package obj
     8  
     9  import (
    10  	"bufio"
    11  	"cmd/internal/dwarf"
    12  	"cmd/internal/objabi"
    13  	"cmd/internal/sys"
    14  	"fmt"
    15  	"log"
    16  	"path/filepath"
    17  	"sort"
    18  	"sync"
    19  )
    20  
    21  // objWriter writes Go object files.
    22  type objWriter struct {
    23  	wr   *bufio.Writer
    24  	ctxt *Link
    25  	// Temporary buffer for zigzag int writing.
    26  	varintbuf [10]uint8
    27  
    28  	// Provide the index of a symbol reference by symbol name.
    29  	// One map for versioned symbols and one for unversioned symbols.
    30  	// Used for deduplicating the symbol reference list.
    31  	refIdx  map[string]int
    32  	vrefIdx map[string]int
    33  
    34  	// Number of objects written of each type.
    35  	nRefs     int
    36  	nData     int
    37  	nReloc    int
    38  	nPcdata   int
    39  	nAutom    int
    40  	nFuncdata int
    41  	nFile     int
    42  }
    43  
    44  func (w *objWriter) addLengths(s *LSym) {
    45  	w.nData += len(s.P)
    46  	w.nReloc += len(s.R)
    47  
    48  	if s.Type != objabi.STEXT {
    49  		return
    50  	}
    51  
    52  	pc := &s.Func.Pcln
    53  
    54  	data := 0
    55  	data += len(pc.Pcsp.P)
    56  	data += len(pc.Pcfile.P)
    57  	data += len(pc.Pcline.P)
    58  	data += len(pc.Pcinline.P)
    59  	for i := 0; i < len(pc.Pcdata); i++ {
    60  		data += len(pc.Pcdata[i].P)
    61  	}
    62  
    63  	w.nData += data
    64  	w.nPcdata += len(pc.Pcdata)
    65  
    66  	w.nAutom += len(s.Func.Autom)
    67  	w.nFuncdata += len(pc.Funcdataoff)
    68  	w.nFile += len(pc.File)
    69  }
    70  
    71  func (w *objWriter) writeLengths() {
    72  	w.writeInt(int64(w.nData))
    73  	w.writeInt(int64(w.nReloc))
    74  	w.writeInt(int64(w.nPcdata))
    75  	w.writeInt(int64(w.nAutom))
    76  	w.writeInt(int64(w.nFuncdata))
    77  	w.writeInt(int64(w.nFile))
    78  }
    79  
    80  func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
    81  	return &objWriter{
    82  		ctxt:    ctxt,
    83  		wr:      b,
    84  		vrefIdx: make(map[string]int),
    85  		refIdx:  make(map[string]int),
    86  	}
    87  }
    88  
    89  func WriteObjFile(ctxt *Link, b *bufio.Writer) {
    90  	w := newObjWriter(ctxt, b)
    91  
    92  	// Magic header
    93  	w.wr.WriteString("\x00\x00go19ld")
    94  
    95  	// Version
    96  	w.wr.WriteByte(1)
    97  
    98  	// Autolib
    99  	for _, pkg := range ctxt.Imports {
   100  		w.writeString(pkg)
   101  	}
   102  	w.writeString("")
   103  
   104  	// Symbol references
   105  	for _, s := range ctxt.Text {
   106  		w.writeRefs(s)
   107  		w.addLengths(s)
   108  	}
   109  	for _, s := range ctxt.Data {
   110  		w.writeRefs(s)
   111  		w.addLengths(s)
   112  	}
   113  	// End symbol references
   114  	w.wr.WriteByte(0xff)
   115  
   116  	// Lengths
   117  	w.writeLengths()
   118  
   119  	// Data block
   120  	for _, s := range ctxt.Text {
   121  		w.wr.Write(s.P)
   122  		pc := &s.Func.Pcln
   123  		w.wr.Write(pc.Pcsp.P)
   124  		w.wr.Write(pc.Pcfile.P)
   125  		w.wr.Write(pc.Pcline.P)
   126  		w.wr.Write(pc.Pcinline.P)
   127  		for i := 0; i < len(pc.Pcdata); i++ {
   128  			w.wr.Write(pc.Pcdata[i].P)
   129  		}
   130  	}
   131  	for _, s := range ctxt.Data {
   132  		if len(s.P) > 0 {
   133  			switch s.Type {
   134  			case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
   135  				ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name)
   136  			}
   137  		}
   138  		w.wr.Write(s.P)
   139  	}
   140  
   141  	// Symbols
   142  	for _, s := range ctxt.Text {
   143  		w.writeSym(s)
   144  	}
   145  	for _, s := range ctxt.Data {
   146  		w.writeSym(s)
   147  	}
   148  
   149  	// Magic footer
   150  	w.wr.WriteString("\xff\xffgo19ld")
   151  }
   152  
   153  // Symbols are prefixed so their content doesn't get confused with the magic footer.
   154  const symPrefix = 0xfe
   155  
   156  func (w *objWriter) writeRef(s *LSym, isPath bool) {
   157  	if s == nil || s.RefIdx != 0 {
   158  		return
   159  	}
   160  	var m map[string]int
   161  	if !s.Static() {
   162  		m = w.refIdx
   163  	} else {
   164  		m = w.vrefIdx
   165  	}
   166  
   167  	if idx := m[s.Name]; idx != 0 {
   168  		s.RefIdx = idx
   169  		return
   170  	}
   171  	w.wr.WriteByte(symPrefix)
   172  	if isPath {
   173  		w.writeString(filepath.ToSlash(s.Name))
   174  	} else {
   175  		w.writeString(s.Name)
   176  	}
   177  	// Write "version".
   178  	if s.Static() {
   179  		w.writeInt(1)
   180  	} else {
   181  		w.writeInt(0)
   182  	}
   183  	w.nRefs++
   184  	s.RefIdx = w.nRefs
   185  	m[s.Name] = w.nRefs
   186  }
   187  
   188  func (w *objWriter) writeRefs(s *LSym) {
   189  	w.writeRef(s, false)
   190  	w.writeRef(s.Gotype, false)
   191  	for i := range s.R {
   192  		w.writeRef(s.R[i].Sym, false)
   193  	}
   194  
   195  	if s.Type == objabi.STEXT {
   196  		for _, a := range s.Func.Autom {
   197  			w.writeRef(a.Asym, false)
   198  			w.writeRef(a.Gotype, false)
   199  		}
   200  		pc := &s.Func.Pcln
   201  		for _, d := range pc.Funcdata {
   202  			w.writeRef(d, false)
   203  		}
   204  		for _, f := range pc.File {
   205  			fsym := w.ctxt.Lookup(f)
   206  			w.writeRef(fsym, true)
   207  		}
   208  		for _, call := range pc.InlTree.nodes {
   209  			w.writeRef(call.Func, false)
   210  			f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
   211  			fsym := w.ctxt.Lookup(f)
   212  			w.writeRef(fsym, true)
   213  		}
   214  	}
   215  }
   216  
   217  func (w *objWriter) writeSymDebug(s *LSym) {
   218  	ctxt := w.ctxt
   219  	fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
   220  	if s.Type != 0 {
   221  		fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
   222  	}
   223  	if s.Static() {
   224  		fmt.Fprint(ctxt.Bso, "static ")
   225  	}
   226  	if s.DuplicateOK() {
   227  		fmt.Fprintf(ctxt.Bso, "dupok ")
   228  	}
   229  	if s.CFunc() {
   230  		fmt.Fprintf(ctxt.Bso, "cfunc ")
   231  	}
   232  	if s.NoSplit() {
   233  		fmt.Fprintf(ctxt.Bso, "nosplit ")
   234  	}
   235  	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
   236  	if s.Type == objabi.STEXT {
   237  		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals))
   238  		if s.Leaf() {
   239  			fmt.Fprintf(ctxt.Bso, " leaf")
   240  		}
   241  	}
   242  	fmt.Fprintf(ctxt.Bso, "\n")
   243  	if s.Type == objabi.STEXT {
   244  		for p := s.Func.Text; p != nil; p = p.Link {
   245  			fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
   246  		}
   247  	}
   248  	for i := 0; i < len(s.P); i += 16 {
   249  		fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
   250  		j := i
   251  		for j = i; j < i+16 && j < len(s.P); j++ {
   252  			fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
   253  		}
   254  		for ; j < i+16; j++ {
   255  			fmt.Fprintf(ctxt.Bso, "   ")
   256  		}
   257  		fmt.Fprintf(ctxt.Bso, "  ")
   258  		for j = i; j < i+16 && j < len(s.P); j++ {
   259  			c := int(s.P[j])
   260  			if ' ' <= c && c <= 0x7e {
   261  				fmt.Fprintf(ctxt.Bso, "%c", c)
   262  			} else {
   263  				fmt.Fprintf(ctxt.Bso, ".")
   264  			}
   265  		}
   266  
   267  		fmt.Fprintf(ctxt.Bso, "\n")
   268  	}
   269  
   270  	sort.Sort(relocByOff(s.R)) // generate stable output
   271  	for _, r := range s.R {
   272  		name := ""
   273  		if r.Sym != nil {
   274  			name = r.Sym.Name
   275  		} else if r.Type == objabi.R_TLS_LE {
   276  			name = "TLS"
   277  		}
   278  		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
   279  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
   280  		} else {
   281  			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
   282  		}
   283  	}
   284  }
   285  
   286  func (w *objWriter) writeSym(s *LSym) {
   287  	ctxt := w.ctxt
   288  	if ctxt.Debugasm {
   289  		w.writeSymDebug(s)
   290  	}
   291  
   292  	w.wr.WriteByte(symPrefix)
   293  	w.wr.WriteByte(byte(s.Type))
   294  	w.writeRefIndex(s)
   295  	flags := int64(0)
   296  	if s.DuplicateOK() {
   297  		flags |= 1
   298  	}
   299  	if s.Local() {
   300  		flags |= 1 << 1
   301  	}
   302  	if s.MakeTypelink() {
   303  		flags |= 1 << 2
   304  	}
   305  	w.writeInt(flags)
   306  	w.writeInt(s.Size)
   307  	w.writeRefIndex(s.Gotype)
   308  	w.writeInt(int64(len(s.P)))
   309  
   310  	w.writeInt(int64(len(s.R)))
   311  	var r *Reloc
   312  	for i := 0; i < len(s.R); i++ {
   313  		r = &s.R[i]
   314  		w.writeInt(int64(r.Off))
   315  		w.writeInt(int64(r.Siz))
   316  		w.writeInt(int64(r.Type))
   317  		w.writeInt(r.Add)
   318  		w.writeRefIndex(r.Sym)
   319  	}
   320  
   321  	if s.Type != objabi.STEXT {
   322  		return
   323  	}
   324  
   325  	w.writeInt(int64(s.Func.Args))
   326  	w.writeInt(int64(s.Func.Locals))
   327  	if s.NoSplit() {
   328  		w.writeInt(1)
   329  	} else {
   330  		w.writeInt(0)
   331  	}
   332  	flags = int64(0)
   333  	if s.Leaf() {
   334  		flags |= 1
   335  	}
   336  	if s.CFunc() {
   337  		flags |= 1 << 1
   338  	}
   339  	if s.ReflectMethod() {
   340  		flags |= 1 << 2
   341  	}
   342  	if ctxt.Flag_shared {
   343  		flags |= 1 << 3
   344  	}
   345  	w.writeInt(flags)
   346  	w.writeInt(int64(len(s.Func.Autom)))
   347  	for _, a := range s.Func.Autom {
   348  		w.writeRefIndex(a.Asym)
   349  		w.writeInt(int64(a.Aoffset))
   350  		if a.Name == NAME_AUTO {
   351  			w.writeInt(objabi.A_AUTO)
   352  		} else if a.Name == NAME_PARAM {
   353  			w.writeInt(objabi.A_PARAM)
   354  		} else if a.Name == NAME_DELETED_AUTO {
   355  			w.writeInt(objabi.A_DELETED_AUTO)
   356  		} else {
   357  			log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
   358  		}
   359  		w.writeRefIndex(a.Gotype)
   360  	}
   361  
   362  	pc := &s.Func.Pcln
   363  	w.writeInt(int64(len(pc.Pcsp.P)))
   364  	w.writeInt(int64(len(pc.Pcfile.P)))
   365  	w.writeInt(int64(len(pc.Pcline.P)))
   366  	w.writeInt(int64(len(pc.Pcinline.P)))
   367  	w.writeInt(int64(len(pc.Pcdata)))
   368  	for i := 0; i < len(pc.Pcdata); i++ {
   369  		w.writeInt(int64(len(pc.Pcdata[i].P)))
   370  	}
   371  	w.writeInt(int64(len(pc.Funcdataoff)))
   372  	for i := 0; i < len(pc.Funcdataoff); i++ {
   373  		w.writeRefIndex(pc.Funcdata[i])
   374  	}
   375  	for i := 0; i < len(pc.Funcdataoff); i++ {
   376  		w.writeInt(pc.Funcdataoff[i])
   377  	}
   378  	w.writeInt(int64(len(pc.File)))
   379  	for _, f := range pc.File {
   380  		fsym := ctxt.Lookup(f)
   381  		w.writeRefIndex(fsym)
   382  	}
   383  	w.writeInt(int64(len(pc.InlTree.nodes)))
   384  	for _, call := range pc.InlTree.nodes {
   385  		w.writeInt(int64(call.Parent))
   386  		f, l := linkgetlineFromPos(w.ctxt, call.Pos)
   387  		fsym := ctxt.Lookup(f)
   388  		w.writeRefIndex(fsym)
   389  		w.writeInt(int64(l))
   390  		w.writeRefIndex(call.Func)
   391  	}
   392  }
   393  
   394  func (w *objWriter) writeInt(sval int64) {
   395  	var v uint64
   396  	uv := (uint64(sval) << 1) ^ uint64(sval>>63)
   397  	p := w.varintbuf[:]
   398  	for v = uv; v >= 0x80; v >>= 7 {
   399  		p[0] = uint8(v | 0x80)
   400  		p = p[1:]
   401  	}
   402  	p[0] = uint8(v)
   403  	p = p[1:]
   404  	w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
   405  }
   406  
   407  func (w *objWriter) writeString(s string) {
   408  	w.writeInt(int64(len(s)))
   409  	w.wr.WriteString(s)
   410  }
   411  
   412  func (w *objWriter) writeRefIndex(s *LSym) {
   413  	if s == nil {
   414  		w.writeInt(0)
   415  		return
   416  	}
   417  	if s.RefIdx == 0 {
   418  		log.Fatalln("writing an unreferenced symbol", s.Name)
   419  	}
   420  	w.writeInt(int64(s.RefIdx))
   421  }
   422  
   423  // relocByOff sorts relocations by their offsets.
   424  type relocByOff []Reloc
   425  
   426  func (x relocByOff) Len() int           { return len(x) }
   427  func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
   428  func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   429  
   430  // implement dwarf.Context
   431  type dwCtxt struct{ *Link }
   432  
   433  func (c dwCtxt) PtrSize() int {
   434  	return c.Arch.PtrSize
   435  }
   436  func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
   437  	ls := s.(*LSym)
   438  	ls.WriteInt(c.Link, ls.Size, size, i)
   439  }
   440  func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
   441  	ls := s.(*LSym)
   442  	ls.WriteBytes(c.Link, ls.Size, b)
   443  }
   444  func (c dwCtxt) AddString(s dwarf.Sym, v string) {
   445  	ls := s.(*LSym)
   446  	ls.WriteString(c.Link, ls.Size, len(v), v)
   447  	ls.WriteInt(c.Link, ls.Size, 1, 0)
   448  }
   449  func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
   450  	ls := s.(*LSym)
   451  	size := c.PtrSize()
   452  	if data != nil {
   453  		rsym := data.(*LSym)
   454  		ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
   455  	} else {
   456  		ls.WriteInt(c.Link, ls.Size, size, value)
   457  	}
   458  }
   459  func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
   460  	ls := s.(*LSym)
   461  	rsym := data.(*LSym)
   462  	ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
   463  }
   464  func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
   465  	ls := s.(*LSym)
   466  	rsym := t.(*LSym)
   467  	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
   468  	r := &ls.R[len(ls.R)-1]
   469  	r.Type = objabi.R_DWARFSECREF
   470  }
   471  func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
   472  	ls := s.(*LSym)
   473  	rsym := f.(*LSym)
   474  	ls.WriteAddr(c.Link, ls.Size, 4, rsym, 0)
   475  	r := &ls.R[len(ls.R)-1]
   476  	r.Type = objabi.R_DWARFFILEREF
   477  }
   478  
   479  func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
   480  	ls := s.(*LSym)
   481  	return ls.Size
   482  }
   483  
   484  // Here "from" is a symbol corresponding to an inlined or concrete
   485  // function, "to" is the symbol for the corresponding abstract
   486  // function, and "dclIdx" is the index of the symbol of interest with
   487  // respect to the Dcl slice of the original pre-optimization version
   488  // of the inlined function.
   489  func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
   490  	ls := from.(*LSym)
   491  	tls := to.(*LSym)
   492  	ridx := len(ls.R) - 1
   493  	c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
   494  }
   495  
   496  func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
   497  	ls := s.(*LSym)
   498  	c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
   499  }
   500  
   501  func (c dwCtxt) Logf(format string, args ...interface{}) {
   502  	c.Link.Logf(format, args...)
   503  }
   504  
   505  func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym *LSym) {
   506  	if s.Type != objabi.STEXT {
   507  		ctxt.Diag("dwarfSym of non-TEXT %v", s)
   508  	}
   509  	if s.Func.dwarfInfoSym == nil {
   510  		s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
   511  		if ctxt.Flag_locationlists {
   512  			s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
   513  		}
   514  		s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
   515  		if s.WasInlined() {
   516  			s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
   517  		}
   518  
   519  	}
   520  	return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym
   521  }
   522  
   523  func (s *LSym) Len() int64 {
   524  	return s.Size
   525  }
   526  
   527  // fileSymbol returns a symbol corresponding to the source file of the
   528  // first instruction (prog) of the specified function. This will
   529  // presumably be the file in which the function is defined.
   530  func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
   531  	p := fn.Func.Text
   532  	if p != nil {
   533  		f, _ := linkgetlineFromPos(ctxt, p.Pos)
   534  		fsym := ctxt.Lookup(f)
   535  		return fsym
   536  	}
   537  	return nil
   538  }
   539  
   540  // populateDWARF fills in the DWARF Debugging Information Entries for
   541  // TEXT symbol 's'. The various DWARF symbols must already have been
   542  // initialized in InitTextSym.
   543  func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
   544  	info, loc, ranges, absfunc := ctxt.dwarfSym(s)
   545  	if info.Size != 0 {
   546  		ctxt.Diag("makeFuncDebugEntry double process %v", s)
   547  	}
   548  	var scopes []dwarf.Scope
   549  	var inlcalls dwarf.InlCalls
   550  	if ctxt.DebugInfo != nil {
   551  		scopes, inlcalls = ctxt.DebugInfo(s, curfn)
   552  	}
   553  	var err error
   554  	dwctxt := dwCtxt{ctxt}
   555  	filesym := ctxt.fileSymbol(s)
   556  	fnstate := &dwarf.FnState{
   557  		Name:       s.Name,
   558  		Importpath: myimportpath,
   559  		Info:       info,
   560  		Filesym:    filesym,
   561  		Loc:        loc,
   562  		Ranges:     ranges,
   563  		Absfn:      absfunc,
   564  		StartPC:    s,
   565  		Size:       s.Size,
   566  		External:   !s.Static(),
   567  		Scopes:     scopes,
   568  		InlCalls:   inlcalls,
   569  	}
   570  	if absfunc != nil {
   571  		err = dwarf.PutAbstractFunc(dwctxt, fnstate)
   572  		if err != nil {
   573  			ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
   574  		}
   575  		err = dwarf.PutConcreteFunc(dwctxt, fnstate)
   576  	} else {
   577  		err = dwarf.PutDefaultFunc(dwctxt, fnstate)
   578  	}
   579  	if err != nil {
   580  		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
   581  	}
   582  }
   583  
   584  // DwarfIntConst creates a link symbol for an integer constant with the
   585  // given name, type and value.
   586  func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
   587  	if myimportpath == "" {
   588  		return
   589  	}
   590  	s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
   591  		s.Type = objabi.SDWARFINFO
   592  		ctxt.Data = append(ctxt.Data, s)
   593  	})
   594  	dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
   595  }
   596  
   597  func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
   598  	absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
   599  	if absfn.Size != 0 {
   600  		ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
   601  	}
   602  	if s.Func == nil {
   603  		s.Func = new(FuncInfo)
   604  	}
   605  	scopes, _ := ctxt.DebugInfo(s, curfn)
   606  	dwctxt := dwCtxt{ctxt}
   607  	filesym := ctxt.fileSymbol(s)
   608  	fnstate := dwarf.FnState{
   609  		Name:       s.Name,
   610  		Importpath: myimportpath,
   611  		Info:       absfn,
   612  		Filesym:    filesym,
   613  		Absfn:      absfn,
   614  		External:   !s.Static(),
   615  		Scopes:     scopes,
   616  	}
   617  	if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
   618  		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
   619  	}
   620  }
   621  
   622  // This table is designed to aid in the creation of references betweeen
   623  // DWARF subprogram DIEs.
   624  //
   625  // In most cases when one DWARF DIE has to refer to another DWARF DIE,
   626  // the target of the reference has an LSym, which makes it easy to use
   627  // the existing relocation mechanism. For DWARF inlined routine DIEs,
   628  // however, the subprogram DIE has to refer to a child
   629  // parameter/variable DIE of the abstract subprogram. This child DIE
   630  // doesn't have an LSym, and also of interest is the fact that when
   631  // DWARF generation is happening for inlined function F within caller
   632  // G, it's possible that DWARF generation hasn't happened yet for F,
   633  // so there is no way to know the offset of a child DIE within F's
   634  // abstract function. Making matters more complex, each inlined
   635  // instance of F may refer to a subset of the original F's variables
   636  // (depending on what happens with optimization, some vars may be
   637  // eliminated).
   638  //
   639  // The fixup table below helps overcome this hurdle. At the point
   640  // where a parameter/variable reference is made (via a call to
   641  // "ReferenceChildDIE"), a fixup record is generate that records
   642  // the relocation that is targeting that child variable. At a later
   643  // point when the abstract function DIE is emitted, there will be
   644  // a call to "RegisterChildDIEOffsets", at which point the offsets
   645  // needed to apply fixups are captured. Finally, once the parallel
   646  // portion of the compilation is done, fixups can actually be applied
   647  // during the "Finalize" method (this can't be done during the
   648  // parallel portion of the compile due to the possibility of data
   649  // races).
   650  //
   651  // This table is also used to record the "precursor" function node for
   652  // each function that is the target of an inline -- child DIE references
   653  // have to be made with respect to the original pre-optimization
   654  // version of the function (to allow for the fact that each inlined
   655  // body may be optimized differently).
   656  type DwarfFixupTable struct {
   657  	ctxt      *Link
   658  	mu        sync.Mutex
   659  	symtab    map[*LSym]int // maps abstract fn LSYM to index in svec
   660  	svec      []symFixups
   661  	precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
   662  }
   663  
   664  type symFixups struct {
   665  	fixups   []relFixup
   666  	doffsets []declOffset
   667  	inlIndex int32
   668  	defseen  bool
   669  }
   670  
   671  type declOffset struct {
   672  	// Index of variable within DCL list of pre-optimization function
   673  	dclIdx int32
   674  	// Offset of var's child DIE with respect to containing subprogram DIE
   675  	offset int32
   676  }
   677  
   678  type relFixup struct {
   679  	refsym *LSym
   680  	relidx int32
   681  	dclidx int32
   682  }
   683  
   684  type fnState struct {
   685  	// precursor function (really *gc.Node)
   686  	precursor interface{}
   687  	// abstract function symbol
   688  	absfn *LSym
   689  }
   690  
   691  func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
   692  	return &DwarfFixupTable{
   693  		ctxt:      ctxt,
   694  		symtab:    make(map[*LSym]int),
   695  		precursor: make(map[*LSym]fnState),
   696  	}
   697  }
   698  
   699  func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
   700  	if fnstate, found := ft.precursor[s]; found {
   701  		return fnstate.precursor
   702  	}
   703  	return nil
   704  }
   705  
   706  func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
   707  	if _, found := ft.precursor[s]; found {
   708  		ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
   709  	}
   710  
   711  	// initialize abstract function symbol now. This is done here so
   712  	// as to avoid data races later on during the parallel portion of
   713  	// the back end.
   714  	absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
   715  	absfn.Set(AttrDuplicateOK, true)
   716  	absfn.Type = objabi.SDWARFINFO
   717  	ft.ctxt.Data = append(ft.ctxt.Data, absfn)
   718  
   719  	ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
   720  }
   721  
   722  // Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
   723  // is targeting child 'c' of DIE with symbol 'tgt'.
   724  func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
   725  	// Protect against concurrent access if multiple backend workers
   726  	ft.mu.Lock()
   727  	defer ft.mu.Unlock()
   728  
   729  	// Create entry for symbol if not already present.
   730  	idx, found := ft.symtab[tgt]
   731  	if !found {
   732  		ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
   733  		idx = len(ft.svec) - 1
   734  		ft.symtab[tgt] = idx
   735  	}
   736  
   737  	// Do we have child DIE offsets available? If so, then apply them,
   738  	// otherwise create a fixup record.
   739  	sf := &ft.svec[idx]
   740  	if len(sf.doffsets) > 0 {
   741  		found := false
   742  		for _, do := range sf.doffsets {
   743  			if do.dclIdx == int32(dclidx) {
   744  				off := do.offset
   745  				s.R[ridx].Add += int64(off)
   746  				found = true
   747  				break
   748  			}
   749  		}
   750  		if !found {
   751  			ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
   752  		}
   753  	} else {
   754  		sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
   755  	}
   756  }
   757  
   758  // Called once DWARF generation is complete for a given abstract function,
   759  // whose children might have been referenced via a call above. Stores
   760  // the offsets for any child DIEs (vars, params) so that they can be
   761  // consumed later in on DwarfFixupTable.Finalize, which applies any
   762  // outstanding fixups.
   763  func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
   764  	// Length of these two slices should agree
   765  	if len(vars) != len(coffsets) {
   766  		ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
   767  		return
   768  	}
   769  
   770  	// Generate the slice of declOffset's based in vars/coffsets
   771  	doffsets := make([]declOffset, len(coffsets))
   772  	for i := 0; i < len(coffsets); i++ {
   773  		doffsets[i].dclIdx = vars[i].ChildIndex
   774  		doffsets[i].offset = coffsets[i]
   775  	}
   776  
   777  	ft.mu.Lock()
   778  	defer ft.mu.Unlock()
   779  
   780  	// Store offsets for this symbol.
   781  	idx, found := ft.symtab[s]
   782  	if !found {
   783  		sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
   784  		ft.svec = append(ft.svec, sf)
   785  		ft.symtab[s] = len(ft.svec) - 1
   786  	} else {
   787  		sf := &ft.svec[idx]
   788  		sf.doffsets = doffsets
   789  		sf.defseen = true
   790  	}
   791  }
   792  
   793  func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
   794  	sf := &ft.svec[slot]
   795  	for _, f := range sf.fixups {
   796  		dfound := false
   797  		for i := 0; i < len(sf.doffsets); i++ {
   798  			if sf.doffsets[i].dclIdx == f.dclidx {
   799  				f.refsym.R[f.relidx].Add += int64(sf.doffsets[i].offset)
   800  				dfound = true
   801  				break
   802  			}
   803  		}
   804  		if !dfound {
   805  			ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
   806  		}
   807  	}
   808  }
   809  
   810  // return the LSym corresponding to the 'abstract subprogram' DWARF
   811  // info entry for a function.
   812  func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
   813  	// Protect against concurrent access if multiple backend workers
   814  	ft.mu.Lock()
   815  	defer ft.mu.Unlock()
   816  
   817  	if fnstate, found := ft.precursor[fnsym]; found {
   818  		return fnstate.absfn
   819  	}
   820  	ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
   821  	return nil
   822  }
   823  
   824  // Called after all functions have been compiled; the main job of this
   825  // function is to identify cases where there are outstanding fixups.
   826  // This scenario crops up when we have references to variables of an
   827  // inlined routine, but that routine is defined in some other package.
   828  // This helper walks through and locate these fixups, then invokes a
   829  // helper to create an abstract subprogram DIE for each one.
   830  func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
   831  	if trace {
   832  		ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
   833  	}
   834  
   835  	// Collect up the keys from the precursor map, then sort the
   836  	// resulting list (don't want to rely on map ordering here).
   837  	fns := make([]*LSym, len(ft.precursor))
   838  	idx := 0
   839  	for fn, _ := range ft.precursor {
   840  		fns[idx] = fn
   841  		idx++
   842  	}
   843  	sort.Sort(bySymName(fns))
   844  
   845  	// Should not be called during parallel portion of compilation.
   846  	if ft.ctxt.InParallel {
   847  		ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
   848  	}
   849  
   850  	// Generate any missing abstract functions.
   851  	for i := 0; i < len(fns); i++ {
   852  		s := fns[i]
   853  		absfn := ft.AbsFuncDwarfSym(s)
   854  		slot, found := ft.symtab[absfn]
   855  		if !found || !ft.svec[slot].defseen {
   856  			ft.ctxt.GenAbstractFunc(s)
   857  		}
   858  	}
   859  
   860  	// Apply fixups.
   861  	for i := 0; i < len(fns); i++ {
   862  		s := fns[i]
   863  		absfn := ft.AbsFuncDwarfSym(s)
   864  		slot, found := ft.symtab[absfn]
   865  		if !found {
   866  			ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
   867  		} else {
   868  			ft.processFixups(slot, s)
   869  		}
   870  	}
   871  }
   872  
   873  type bySymName []*LSym
   874  
   875  func (s bySymName) Len() int           { return len(s) }
   876  func (s bySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
   877  func (s bySymName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }