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