dwarf.go raw

   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  // Writes dwarf information to object files.
   6  
   7  package obj
   8  
   9  import (
  10  	"github.com/twitchyliquid64/golang-asm/dwarf"
  11  	"github.com/twitchyliquid64/golang-asm/objabi"
  12  	"github.com/twitchyliquid64/golang-asm/src"
  13  	"fmt"
  14  	"sort"
  15  	"sync"
  16  )
  17  
  18  // Generate a sequence of opcodes that is as short as possible.
  19  // See section 6.2.5
  20  const (
  21  	LINE_BASE   = -4
  22  	LINE_RANGE  = 10
  23  	PC_RANGE    = (255 - OPCODE_BASE) / LINE_RANGE
  24  	OPCODE_BASE = 11
  25  )
  26  
  27  // generateDebugLinesSymbol fills the debug lines symbol of a given function.
  28  //
  29  // It's worth noting that this function doesn't generate the full debug_lines
  30  // DWARF section, saving that for the linker. This function just generates the
  31  // state machine part of debug_lines. The full table is generated by the
  32  // linker.  Also, we use the file numbers from the full package (not just the
  33  // function in question) when generating the state machine. We do this so we
  34  // don't have to do a fixup on the indices when writing the full section.
  35  func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
  36  	dctxt := dwCtxt{ctxt}
  37  
  38  	// Emit a LNE_set_address extended opcode, so as to establish the
  39  	// starting text address of this function.
  40  	dctxt.AddUint8(lines, 0)
  41  	dwarf.Uleb128put(dctxt, lines, 1+int64(ctxt.Arch.PtrSize))
  42  	dctxt.AddUint8(lines, dwarf.DW_LNE_set_address)
  43  	dctxt.AddAddress(lines, s, 0)
  44  
  45  	// Set up the debug_lines state machine to the default values
  46  	// we expect at the start of a new sequence.
  47  	stmt := true
  48  	line := int64(1)
  49  	pc := s.Func.Text.Pc
  50  	var lastpc int64 // last PC written to line table, not last PC in func
  51  	name := ""
  52  	prologue, wrotePrologue := false, false
  53  	// Walk the progs, generating the DWARF table.
  54  	for p := s.Func.Text; p != nil; p = p.Link {
  55  		prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
  56  		// If we're not at a real instruction, keep looping!
  57  		if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) {
  58  			continue
  59  		}
  60  		newStmt := p.Pos.IsStmt() != src.PosNotStmt
  61  		newName, newLine := linkgetlineFromPos(ctxt, p.Pos)
  62  
  63  		// Output debug info.
  64  		wrote := false
  65  		if name != newName {
  66  			newFile := ctxt.PosTable.FileIndex(newName) + 1 // 1 indexing for the table.
  67  			dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
  68  			dwarf.Uleb128put(dctxt, lines, int64(newFile))
  69  			name = newName
  70  			wrote = true
  71  		}
  72  		if prologue && !wrotePrologue {
  73  			dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end))
  74  			wrotePrologue = true
  75  			wrote = true
  76  		}
  77  		if stmt != newStmt {
  78  			dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt))
  79  			stmt = newStmt
  80  			wrote = true
  81  		}
  82  
  83  		if line != int64(newLine) || wrote {
  84  			pcdelta := p.Pc - pc
  85  			lastpc = p.Pc
  86  			putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line)
  87  			line, pc = int64(newLine), p.Pc
  88  		}
  89  	}
  90  
  91  	// Because these symbols will be concatenated together by the
  92  	// linker, we need to reset the state machine that controls the
  93  	// debug symbols. Do this using an end-of-sequence operator.
  94  	//
  95  	// Note: at one point in time, Delve did not support multiple end
  96  	// sequence ops within a compilation unit (bug for this:
  97  	// https://github.com/go-delve/delve/issues/1694), however the bug
  98  	// has since been fixed (Oct 2019).
  99  	//
 100  	// Issue 38192: the DWARF standard specifies that when you issue
 101  	// an end-sequence op, the PC value should be one past the last
 102  	// text address in the translation unit, so apply a delta to the
 103  	// text address before the end sequence op. If this isn't done,
 104  	// GDB will assign a line number of zero the last row in the line
 105  	// table, which we don't want.
 106  	lastlen := uint64(s.Size - (lastpc - s.Func.Text.Pc))
 107  	putpclcdelta(ctxt, dctxt, lines, lastlen, 0)
 108  	dctxt.AddUint8(lines, 0) // start extended opcode
 109  	dwarf.Uleb128put(dctxt, lines, 1)
 110  	dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence)
 111  }
 112  
 113  func putpclcdelta(linkctxt *Link, dctxt dwCtxt, s *LSym, deltaPC uint64, deltaLC int64) {
 114  	// Choose a special opcode that minimizes the number of bytes needed to
 115  	// encode the remaining PC delta and LC delta.
 116  	var opcode int64
 117  	if deltaLC < LINE_BASE {
 118  		if deltaPC >= PC_RANGE {
 119  			opcode = OPCODE_BASE + (LINE_RANGE * PC_RANGE)
 120  		} else {
 121  			opcode = OPCODE_BASE + (LINE_RANGE * int64(deltaPC))
 122  		}
 123  	} else if deltaLC < LINE_BASE+LINE_RANGE {
 124  		if deltaPC >= PC_RANGE {
 125  			opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * PC_RANGE)
 126  			if opcode > 255 {
 127  				opcode -= LINE_RANGE
 128  			}
 129  		} else {
 130  			opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * int64(deltaPC))
 131  		}
 132  	} else {
 133  		if deltaPC <= PC_RANGE {
 134  			opcode = OPCODE_BASE + (LINE_RANGE - 1) + (LINE_RANGE * int64(deltaPC))
 135  			if opcode > 255 {
 136  				opcode = 255
 137  			}
 138  		} else {
 139  			// Use opcode 249 (pc+=23, lc+=5) or 255 (pc+=24, lc+=1).
 140  			//
 141  			// Let x=deltaPC-PC_RANGE.  If we use opcode 255, x will be the remaining
 142  			// deltaPC that we need to encode separately before emitting 255.  If we
 143  			// use opcode 249, we will need to encode x+1.  If x+1 takes one more
 144  			// byte to encode than x, then we use opcode 255.
 145  			//
 146  			// In all other cases x and x+1 take the same number of bytes to encode,
 147  			// so we use opcode 249, which may save us a byte in encoding deltaLC,
 148  			// for similar reasons.
 149  			switch deltaPC - PC_RANGE {
 150  			// PC_RANGE is the largest deltaPC we can encode in one byte, using
 151  			// DW_LNS_const_add_pc.
 152  			//
 153  			// (1<<16)-1 is the largest deltaPC we can encode in three bytes, using
 154  			// DW_LNS_fixed_advance_pc.
 155  			//
 156  			// (1<<(7n))-1 is the largest deltaPC we can encode in n+1 bytes for
 157  			// n=1,3,4,5,..., using DW_LNS_advance_pc.
 158  			case PC_RANGE, (1 << 7) - 1, (1 << 16) - 1, (1 << 21) - 1, (1 << 28) - 1,
 159  				(1 << 35) - 1, (1 << 42) - 1, (1 << 49) - 1, (1 << 56) - 1, (1 << 63) - 1:
 160  				opcode = 255
 161  			default:
 162  				opcode = OPCODE_BASE + LINE_RANGE*PC_RANGE - 1 // 249
 163  			}
 164  		}
 165  	}
 166  	if opcode < OPCODE_BASE || opcode > 255 {
 167  		panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
 168  	}
 169  
 170  	// Subtract from deltaPC and deltaLC the amounts that the opcode will add.
 171  	deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE)
 172  	deltaLC -= (opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE
 173  
 174  	// Encode deltaPC.
 175  	if deltaPC != 0 {
 176  		if deltaPC <= PC_RANGE {
 177  			// Adjust the opcode so that we can use the 1-byte DW_LNS_const_add_pc
 178  			// instruction.
 179  			opcode -= LINE_RANGE * int64(PC_RANGE-deltaPC)
 180  			if opcode < OPCODE_BASE {
 181  				panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
 182  			}
 183  			dctxt.AddUint8(s, dwarf.DW_LNS_const_add_pc)
 184  		} else if (1<<14) <= deltaPC && deltaPC < (1<<16) {
 185  			dctxt.AddUint8(s, dwarf.DW_LNS_fixed_advance_pc)
 186  			dctxt.AddUint16(s, uint16(deltaPC))
 187  		} else {
 188  			dctxt.AddUint8(s, dwarf.DW_LNS_advance_pc)
 189  			dwarf.Uleb128put(dctxt, s, int64(deltaPC))
 190  		}
 191  	}
 192  
 193  	// Encode deltaLC.
 194  	if deltaLC != 0 {
 195  		dctxt.AddUint8(s, dwarf.DW_LNS_advance_line)
 196  		dwarf.Sleb128put(dctxt, s, deltaLC)
 197  	}
 198  
 199  	// Output the special opcode.
 200  	dctxt.AddUint8(s, uint8(opcode))
 201  }
 202  
 203  // implement dwarf.Context
 204  type dwCtxt struct{ *Link }
 205  
 206  func (c dwCtxt) PtrSize() int {
 207  	return c.Arch.PtrSize
 208  }
 209  func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
 210  	ls := s.(*LSym)
 211  	ls.WriteInt(c.Link, ls.Size, size, i)
 212  }
 213  func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
 214  	c.AddInt(s, 2, int64(i))
 215  }
 216  func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
 217  	b := []byte{byte(i)}
 218  	c.AddBytes(s, b)
 219  }
 220  func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
 221  	ls := s.(*LSym)
 222  	ls.WriteBytes(c.Link, ls.Size, b)
 223  }
 224  func (c dwCtxt) AddString(s dwarf.Sym, v string) {
 225  	ls := s.(*LSym)
 226  	ls.WriteString(c.Link, ls.Size, len(v), v)
 227  	ls.WriteInt(c.Link, ls.Size, 1, 0)
 228  }
 229  func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
 230  	ls := s.(*LSym)
 231  	size := c.PtrSize()
 232  	if data != nil {
 233  		rsym := data.(*LSym)
 234  		ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
 235  	} else {
 236  		ls.WriteInt(c.Link, ls.Size, size, value)
 237  	}
 238  }
 239  func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
 240  	ls := s.(*LSym)
 241  	rsym := data.(*LSym)
 242  	ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
 243  }
 244  func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
 245  	panic("should be used only in the linker")
 246  }
 247  func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
 248  	size := 4
 249  	if isDwarf64(c.Link) {
 250  		size = 8
 251  	}
 252  
 253  	ls := s.(*LSym)
 254  	rsym := t.(*LSym)
 255  	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
 256  	r := &ls.R[len(ls.R)-1]
 257  	r.Type = objabi.R_DWARFSECREF
 258  }
 259  
 260  func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
 261  	ls := s.(*LSym)
 262  	rsym := f.(*LSym)
 263  	fidx := c.Link.PosTable.FileIndex(rsym.Name)
 264  	// Note the +1 here -- the value we're writing is going to be an
 265  	// index into the DWARF line table file section, whose entries
 266  	// are numbered starting at 1, not 0.
 267  	ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
 268  }
 269  
 270  func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
 271  	ls := s.(*LSym)
 272  	return ls.Size
 273  }
 274  
 275  // Here "from" is a symbol corresponding to an inlined or concrete
 276  // function, "to" is the symbol for the corresponding abstract
 277  // function, and "dclIdx" is the index of the symbol of interest with
 278  // respect to the Dcl slice of the original pre-optimization version
 279  // of the inlined function.
 280  func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
 281  	ls := from.(*LSym)
 282  	tls := to.(*LSym)
 283  	ridx := len(ls.R) - 1
 284  	c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
 285  }
 286  
 287  func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
 288  	ls := s.(*LSym)
 289  	c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
 290  }
 291  
 292  func (c dwCtxt) Logf(format string, args ...interface{}) {
 293  	c.Link.Logf(format, args...)
 294  }
 295  
 296  func isDwarf64(ctxt *Link) bool {
 297  	return ctxt.Headtype == objabi.Haix
 298  }
 299  
 300  func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
 301  	if s.Type != objabi.STEXT {
 302  		ctxt.Diag("dwarfSym of non-TEXT %v", s)
 303  	}
 304  	if s.Func.dwarfInfoSym == nil {
 305  		s.Func.dwarfInfoSym = &LSym{
 306  			Type: objabi.SDWARFFCN,
 307  		}
 308  		if ctxt.Flag_locationlists {
 309  			s.Func.dwarfLocSym = &LSym{
 310  				Type: objabi.SDWARFLOC,
 311  			}
 312  		}
 313  		s.Func.dwarfRangesSym = &LSym{
 314  			Type: objabi.SDWARFRANGE,
 315  		}
 316  		s.Func.dwarfDebugLinesSym = &LSym{
 317  			Type: objabi.SDWARFLINES,
 318  		}
 319  		if s.WasInlined() {
 320  			s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
 321  		}
 322  	}
 323  	return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
 324  }
 325  
 326  func (s *LSym) Length(dwarfContext interface{}) int64 {
 327  	return s.Size
 328  }
 329  
 330  // fileSymbol returns a symbol corresponding to the source file of the
 331  // first instruction (prog) of the specified function. This will
 332  // presumably be the file in which the function is defined.
 333  func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
 334  	p := fn.Func.Text
 335  	if p != nil {
 336  		f, _ := linkgetlineFromPos(ctxt, p.Pos)
 337  		fsym := ctxt.Lookup(f)
 338  		return fsym
 339  	}
 340  	return nil
 341  }
 342  
 343  // populateDWARF fills in the DWARF Debugging Information Entries for
 344  // TEXT symbol 's'. The various DWARF symbols must already have been
 345  // initialized in InitTextSym.
 346  func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
 347  	info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
 348  	if info.Size != 0 {
 349  		ctxt.Diag("makeFuncDebugEntry double process %v", s)
 350  	}
 351  	var scopes []dwarf.Scope
 352  	var inlcalls dwarf.InlCalls
 353  	if ctxt.DebugInfo != nil {
 354  		scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
 355  	}
 356  	var err error
 357  	dwctxt := dwCtxt{ctxt}
 358  	filesym := ctxt.fileSymbol(s)
 359  	fnstate := &dwarf.FnState{
 360  		Name:          s.Name,
 361  		Importpath:    myimportpath,
 362  		Info:          info,
 363  		Filesym:       filesym,
 364  		Loc:           loc,
 365  		Ranges:        ranges,
 366  		Absfn:         absfunc,
 367  		StartPC:       s,
 368  		Size:          s.Size,
 369  		External:      !s.Static(),
 370  		Scopes:        scopes,
 371  		InlCalls:      inlcalls,
 372  		UseBASEntries: ctxt.UseBASEntries,
 373  	}
 374  	if absfunc != nil {
 375  		err = dwarf.PutAbstractFunc(dwctxt, fnstate)
 376  		if err != nil {
 377  			ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
 378  		}
 379  		err = dwarf.PutConcreteFunc(dwctxt, fnstate)
 380  	} else {
 381  		err = dwarf.PutDefaultFunc(dwctxt, fnstate)
 382  	}
 383  	if err != nil {
 384  		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
 385  	}
 386  	// Fill in the debug lines symbol.
 387  	ctxt.generateDebugLinesSymbol(s, lines)
 388  }
 389  
 390  // DwarfIntConst creates a link symbol for an integer constant with the
 391  // given name, type and value.
 392  func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
 393  	if myimportpath == "" {
 394  		return
 395  	}
 396  	s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
 397  		s.Type = objabi.SDWARFCONST
 398  		ctxt.Data = append(ctxt.Data, s)
 399  	})
 400  	dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
 401  }
 402  
 403  func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
 404  	absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
 405  	if absfn.Size != 0 {
 406  		ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
 407  	}
 408  	if s.Func == nil {
 409  		s.Func = new(FuncInfo)
 410  	}
 411  	scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
 412  	dwctxt := dwCtxt{ctxt}
 413  	filesym := ctxt.fileSymbol(s)
 414  	fnstate := dwarf.FnState{
 415  		Name:          s.Name,
 416  		Importpath:    myimportpath,
 417  		Info:          absfn,
 418  		Filesym:       filesym,
 419  		Absfn:         absfn,
 420  		External:      !s.Static(),
 421  		Scopes:        scopes,
 422  		UseBASEntries: ctxt.UseBASEntries,
 423  	}
 424  	if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
 425  		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
 426  	}
 427  }
 428  
 429  // This table is designed to aid in the creation of references between
 430  // DWARF subprogram DIEs.
 431  //
 432  // In most cases when one DWARF DIE has to refer to another DWARF DIE,
 433  // the target of the reference has an LSym, which makes it easy to use
 434  // the existing relocation mechanism. For DWARF inlined routine DIEs,
 435  // however, the subprogram DIE has to refer to a child
 436  // parameter/variable DIE of the abstract subprogram. This child DIE
 437  // doesn't have an LSym, and also of interest is the fact that when
 438  // DWARF generation is happening for inlined function F within caller
 439  // G, it's possible that DWARF generation hasn't happened yet for F,
 440  // so there is no way to know the offset of a child DIE within F's
 441  // abstract function. Making matters more complex, each inlined
 442  // instance of F may refer to a subset of the original F's variables
 443  // (depending on what happens with optimization, some vars may be
 444  // eliminated).
 445  //
 446  // The fixup table below helps overcome this hurdle. At the point
 447  // where a parameter/variable reference is made (via a call to
 448  // "ReferenceChildDIE"), a fixup record is generate that records
 449  // the relocation that is targeting that child variable. At a later
 450  // point when the abstract function DIE is emitted, there will be
 451  // a call to "RegisterChildDIEOffsets", at which point the offsets
 452  // needed to apply fixups are captured. Finally, once the parallel
 453  // portion of the compilation is done, fixups can actually be applied
 454  // during the "Finalize" method (this can't be done during the
 455  // parallel portion of the compile due to the possibility of data
 456  // races).
 457  //
 458  // This table is also used to record the "precursor" function node for
 459  // each function that is the target of an inline -- child DIE references
 460  // have to be made with respect to the original pre-optimization
 461  // version of the function (to allow for the fact that each inlined
 462  // body may be optimized differently).
 463  type DwarfFixupTable struct {
 464  	ctxt      *Link
 465  	mu        sync.Mutex
 466  	symtab    map[*LSym]int // maps abstract fn LSYM to index in svec
 467  	svec      []symFixups
 468  	precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
 469  }
 470  
 471  type symFixups struct {
 472  	fixups   []relFixup
 473  	doffsets []declOffset
 474  	inlIndex int32
 475  	defseen  bool
 476  }
 477  
 478  type declOffset struct {
 479  	// Index of variable within DCL list of pre-optimization function
 480  	dclIdx int32
 481  	// Offset of var's child DIE with respect to containing subprogram DIE
 482  	offset int32
 483  }
 484  
 485  type relFixup struct {
 486  	refsym *LSym
 487  	relidx int32
 488  	dclidx int32
 489  }
 490  
 491  type fnState struct {
 492  	// precursor function (really *gc.Node)
 493  	precursor interface{}
 494  	// abstract function symbol
 495  	absfn *LSym
 496  }
 497  
 498  func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
 499  	return &DwarfFixupTable{
 500  		ctxt:      ctxt,
 501  		symtab:    make(map[*LSym]int),
 502  		precursor: make(map[*LSym]fnState),
 503  	}
 504  }
 505  
 506  func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
 507  	if fnstate, found := ft.precursor[s]; found {
 508  		return fnstate.precursor
 509  	}
 510  	return nil
 511  }
 512  
 513  func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
 514  	if _, found := ft.precursor[s]; found {
 515  		ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
 516  	}
 517  
 518  	// initialize abstract function symbol now. This is done here so
 519  	// as to avoid data races later on during the parallel portion of
 520  	// the back end.
 521  	absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
 522  	absfn.Set(AttrDuplicateOK, true)
 523  	absfn.Type = objabi.SDWARFABSFCN
 524  	ft.ctxt.Data = append(ft.ctxt.Data, absfn)
 525  
 526  	// In the case of "late" inlining (inlines that happen during
 527  	// wrapper generation as opposed to the main inlining phase) it's
 528  	// possible that we didn't cache the abstract function sym for the
 529  	// text symbol -- do so now if needed. See issue 38068.
 530  	if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
 531  		s.Func.dwarfAbsFnSym = absfn
 532  	}
 533  
 534  	ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
 535  }
 536  
 537  // Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
 538  // is targeting child 'c' of DIE with symbol 'tgt'.
 539  func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
 540  	// Protect against concurrent access if multiple backend workers
 541  	ft.mu.Lock()
 542  	defer ft.mu.Unlock()
 543  
 544  	// Create entry for symbol if not already present.
 545  	idx, found := ft.symtab[tgt]
 546  	if !found {
 547  		ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
 548  		idx = len(ft.svec) - 1
 549  		ft.symtab[tgt] = idx
 550  	}
 551  
 552  	// Do we have child DIE offsets available? If so, then apply them,
 553  	// otherwise create a fixup record.
 554  	sf := &ft.svec[idx]
 555  	if len(sf.doffsets) > 0 {
 556  		found := false
 557  		for _, do := range sf.doffsets {
 558  			if do.dclIdx == int32(dclidx) {
 559  				off := do.offset
 560  				s.R[ridx].Add += int64(off)
 561  				found = true
 562  				break
 563  			}
 564  		}
 565  		if !found {
 566  			ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
 567  		}
 568  	} else {
 569  		sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
 570  	}
 571  }
 572  
 573  // Called once DWARF generation is complete for a given abstract function,
 574  // whose children might have been referenced via a call above. Stores
 575  // the offsets for any child DIEs (vars, params) so that they can be
 576  // consumed later in on DwarfFixupTable.Finalize, which applies any
 577  // outstanding fixups.
 578  func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
 579  	// Length of these two slices should agree
 580  	if len(vars) != len(coffsets) {
 581  		ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
 582  		return
 583  	}
 584  
 585  	// Generate the slice of declOffset's based in vars/coffsets
 586  	doffsets := make([]declOffset, len(coffsets))
 587  	for i := range coffsets {
 588  		doffsets[i].dclIdx = vars[i].ChildIndex
 589  		doffsets[i].offset = coffsets[i]
 590  	}
 591  
 592  	ft.mu.Lock()
 593  	defer ft.mu.Unlock()
 594  
 595  	// Store offsets for this symbol.
 596  	idx, found := ft.symtab[s]
 597  	if !found {
 598  		sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
 599  		ft.svec = append(ft.svec, sf)
 600  		ft.symtab[s] = len(ft.svec) - 1
 601  	} else {
 602  		sf := &ft.svec[idx]
 603  		sf.doffsets = doffsets
 604  		sf.defseen = true
 605  	}
 606  }
 607  
 608  func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
 609  	sf := &ft.svec[slot]
 610  	for _, f := range sf.fixups {
 611  		dfound := false
 612  		for _, doffset := range sf.doffsets {
 613  			if doffset.dclIdx == f.dclidx {
 614  				f.refsym.R[f.relidx].Add += int64(doffset.offset)
 615  				dfound = true
 616  				break
 617  			}
 618  		}
 619  		if !dfound {
 620  			ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
 621  		}
 622  	}
 623  }
 624  
 625  // return the LSym corresponding to the 'abstract subprogram' DWARF
 626  // info entry for a function.
 627  func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
 628  	// Protect against concurrent access if multiple backend workers
 629  	ft.mu.Lock()
 630  	defer ft.mu.Unlock()
 631  
 632  	if fnstate, found := ft.precursor[fnsym]; found {
 633  		return fnstate.absfn
 634  	}
 635  	ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
 636  	return nil
 637  }
 638  
 639  // Called after all functions have been compiled; the main job of this
 640  // function is to identify cases where there are outstanding fixups.
 641  // This scenario crops up when we have references to variables of an
 642  // inlined routine, but that routine is defined in some other package.
 643  // This helper walks through and locate these fixups, then invokes a
 644  // helper to create an abstract subprogram DIE for each one.
 645  func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
 646  	if trace {
 647  		ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
 648  	}
 649  
 650  	// Collect up the keys from the precursor map, then sort the
 651  	// resulting list (don't want to rely on map ordering here).
 652  	fns := make([]*LSym, len(ft.precursor))
 653  	idx := 0
 654  	for fn := range ft.precursor {
 655  		fns[idx] = fn
 656  		idx++
 657  	}
 658  	sort.Sort(BySymName(fns))
 659  
 660  	// Should not be called during parallel portion of compilation.
 661  	if ft.ctxt.InParallel {
 662  		ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
 663  	}
 664  
 665  	// Generate any missing abstract functions.
 666  	for _, s := range fns {
 667  		absfn := ft.AbsFuncDwarfSym(s)
 668  		slot, found := ft.symtab[absfn]
 669  		if !found || !ft.svec[slot].defseen {
 670  			ft.ctxt.GenAbstractFunc(s)
 671  		}
 672  	}
 673  
 674  	// Apply fixups.
 675  	for _, s := range fns {
 676  		absfn := ft.AbsFuncDwarfSym(s)
 677  		slot, found := ft.symtab[absfn]
 678  		if !found {
 679  			ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
 680  		} else {
 681  			ft.processFixups(slot, s)
 682  		}
 683  	}
 684  }
 685  
 686  type BySymName []*LSym
 687  
 688  func (s BySymName) Len() int           { return len(s) }
 689  func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
 690  func (s BySymName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 691