podman
690 строк · 22.0 Кб
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"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
20const (
21LINE_BASE = -4
22LINE_RANGE = 10
23PC_RANGE = (255 - OPCODE_BASE) / LINE_RANGE
24OPCODE_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) {
36dctxt := dwCtxt{ctxt}
37
38// Emit a LNE_set_address extended opcode, so as to establish the
39// starting text address of this function.
40dctxt.AddUint8(lines, 0)
41dwarf.Uleb128put(dctxt, lines, 1+int64(ctxt.Arch.PtrSize))
42dctxt.AddUint8(lines, dwarf.DW_LNE_set_address)
43dctxt.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.
47stmt := true
48line := int64(1)
49pc := s.Func.Text.Pc
50var lastpc int64 // last PC written to line table, not last PC in func
51name := ""
52prologue, wrotePrologue := false, false
53// Walk the progs, generating the DWARF table.
54for p := s.Func.Text; p != nil; p = p.Link {
55prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
56// If we're not at a real instruction, keep looping!
57if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) {
58continue
59}
60newStmt := p.Pos.IsStmt() != src.PosNotStmt
61newName, newLine := linkgetlineFromPos(ctxt, p.Pos)
62
63// Output debug info.
64wrote := false
65if name != newName {
66newFile := ctxt.PosTable.FileIndex(newName) + 1 // 1 indexing for the table.
67dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
68dwarf.Uleb128put(dctxt, lines, int64(newFile))
69name = newName
70wrote = true
71}
72if prologue && !wrotePrologue {
73dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end))
74wrotePrologue = true
75wrote = true
76}
77if stmt != newStmt {
78dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt))
79stmt = newStmt
80wrote = true
81}
82
83if line != int64(newLine) || wrote {
84pcdelta := p.Pc - pc
85lastpc = p.Pc
86putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line)
87line, 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.
106lastlen := uint64(s.Size - (lastpc - s.Func.Text.Pc))
107putpclcdelta(ctxt, dctxt, lines, lastlen, 0)
108dctxt.AddUint8(lines, 0) // start extended opcode
109dwarf.Uleb128put(dctxt, lines, 1)
110dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence)
111}
112
113func 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.
116var opcode int64
117if deltaLC < LINE_BASE {
118if deltaPC >= PC_RANGE {
119opcode = OPCODE_BASE + (LINE_RANGE * PC_RANGE)
120} else {
121opcode = OPCODE_BASE + (LINE_RANGE * int64(deltaPC))
122}
123} else if deltaLC < LINE_BASE+LINE_RANGE {
124if deltaPC >= PC_RANGE {
125opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * PC_RANGE)
126if opcode > 255 {
127opcode -= LINE_RANGE
128}
129} else {
130opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * int64(deltaPC))
131}
132} else {
133if deltaPC <= PC_RANGE {
134opcode = OPCODE_BASE + (LINE_RANGE - 1) + (LINE_RANGE * int64(deltaPC))
135if opcode > 255 {
136opcode = 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.
149switch 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.
158case 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:
160opcode = 255
161default:
162opcode = OPCODE_BASE + LINE_RANGE*PC_RANGE - 1 // 249
163}
164}
165}
166if opcode < OPCODE_BASE || opcode > 255 {
167panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
168}
169
170// Subtract from deltaPC and deltaLC the amounts that the opcode will add.
171deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE)
172deltaLC -= (opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE
173
174// Encode deltaPC.
175if deltaPC != 0 {
176if deltaPC <= PC_RANGE {
177// Adjust the opcode so that we can use the 1-byte DW_LNS_const_add_pc
178// instruction.
179opcode -= LINE_RANGE * int64(PC_RANGE-deltaPC)
180if opcode < OPCODE_BASE {
181panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
182}
183dctxt.AddUint8(s, dwarf.DW_LNS_const_add_pc)
184} else if (1<<14) <= deltaPC && deltaPC < (1<<16) {
185dctxt.AddUint8(s, dwarf.DW_LNS_fixed_advance_pc)
186dctxt.AddUint16(s, uint16(deltaPC))
187} else {
188dctxt.AddUint8(s, dwarf.DW_LNS_advance_pc)
189dwarf.Uleb128put(dctxt, s, int64(deltaPC))
190}
191}
192
193// Encode deltaLC.
194if deltaLC != 0 {
195dctxt.AddUint8(s, dwarf.DW_LNS_advance_line)
196dwarf.Sleb128put(dctxt, s, deltaLC)
197}
198
199// Output the special opcode.
200dctxt.AddUint8(s, uint8(opcode))
201}
202
203// implement dwarf.Context
204type dwCtxt struct{ *Link }
205
206func (c dwCtxt) PtrSize() int {
207return c.Arch.PtrSize
208}
209func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
210ls := s.(*LSym)
211ls.WriteInt(c.Link, ls.Size, size, i)
212}
213func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
214c.AddInt(s, 2, int64(i))
215}
216func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
217b := []byte{byte(i)}
218c.AddBytes(s, b)
219}
220func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
221ls := s.(*LSym)
222ls.WriteBytes(c.Link, ls.Size, b)
223}
224func (c dwCtxt) AddString(s dwarf.Sym, v string) {
225ls := s.(*LSym)
226ls.WriteString(c.Link, ls.Size, len(v), v)
227ls.WriteInt(c.Link, ls.Size, 1, 0)
228}
229func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
230ls := s.(*LSym)
231size := c.PtrSize()
232if data != nil {
233rsym := data.(*LSym)
234ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
235} else {
236ls.WriteInt(c.Link, ls.Size, size, value)
237}
238}
239func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
240ls := s.(*LSym)
241rsym := data.(*LSym)
242ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
243}
244func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
245panic("should be used only in the linker")
246}
247func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
248size := 4
249if isDwarf64(c.Link) {
250size = 8
251}
252
253ls := s.(*LSym)
254rsym := t.(*LSym)
255ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
256r := &ls.R[len(ls.R)-1]
257r.Type = objabi.R_DWARFSECREF
258}
259
260func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
261ls := s.(*LSym)
262rsym := f.(*LSym)
263fidx := 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.
267ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
268}
269
270func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
271ls := s.(*LSym)
272return 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.
280func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
281ls := from.(*LSym)
282tls := to.(*LSym)
283ridx := len(ls.R) - 1
284c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
285}
286
287func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
288ls := s.(*LSym)
289c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
290}
291
292func (c dwCtxt) Logf(format string, args ...interface{}) {
293c.Link.Logf(format, args...)
294}
295
296func isDwarf64(ctxt *Link) bool {
297return ctxt.Headtype == objabi.Haix
298}
299
300func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
301if s.Type != objabi.STEXT {
302ctxt.Diag("dwarfSym of non-TEXT %v", s)
303}
304if s.Func.dwarfInfoSym == nil {
305s.Func.dwarfInfoSym = &LSym{
306Type: objabi.SDWARFFCN,
307}
308if ctxt.Flag_locationlists {
309s.Func.dwarfLocSym = &LSym{
310Type: objabi.SDWARFLOC,
311}
312}
313s.Func.dwarfRangesSym = &LSym{
314Type: objabi.SDWARFRANGE,
315}
316s.Func.dwarfDebugLinesSym = &LSym{
317Type: objabi.SDWARFLINES,
318}
319if s.WasInlined() {
320s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
321}
322}
323return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
324}
325
326func (s *LSym) Length(dwarfContext interface{}) int64 {
327return 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.
333func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
334p := fn.Func.Text
335if p != nil {
336f, _ := linkgetlineFromPos(ctxt, p.Pos)
337fsym := ctxt.Lookup(f)
338return fsym
339}
340return 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.
346func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
347info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
348if info.Size != 0 {
349ctxt.Diag("makeFuncDebugEntry double process %v", s)
350}
351var scopes []dwarf.Scope
352var inlcalls dwarf.InlCalls
353if ctxt.DebugInfo != nil {
354scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
355}
356var err error
357dwctxt := dwCtxt{ctxt}
358filesym := ctxt.fileSymbol(s)
359fnstate := &dwarf.FnState{
360Name: s.Name,
361Importpath: myimportpath,
362Info: info,
363Filesym: filesym,
364Loc: loc,
365Ranges: ranges,
366Absfn: absfunc,
367StartPC: s,
368Size: s.Size,
369External: !s.Static(),
370Scopes: scopes,
371InlCalls: inlcalls,
372UseBASEntries: ctxt.UseBASEntries,
373}
374if absfunc != nil {
375err = dwarf.PutAbstractFunc(dwctxt, fnstate)
376if err != nil {
377ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
378}
379err = dwarf.PutConcreteFunc(dwctxt, fnstate)
380} else {
381err = dwarf.PutDefaultFunc(dwctxt, fnstate)
382}
383if err != nil {
384ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
385}
386// Fill in the debug lines symbol.
387ctxt.generateDebugLinesSymbol(s, lines)
388}
389
390// DwarfIntConst creates a link symbol for an integer constant with the
391// given name, type and value.
392func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
393if myimportpath == "" {
394return
395}
396s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
397s.Type = objabi.SDWARFCONST
398ctxt.Data = append(ctxt.Data, s)
399})
400dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
401}
402
403func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
404absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
405if absfn.Size != 0 {
406ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
407}
408if s.Func == nil {
409s.Func = new(FuncInfo)
410}
411scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
412dwctxt := dwCtxt{ctxt}
413filesym := ctxt.fileSymbol(s)
414fnstate := dwarf.FnState{
415Name: s.Name,
416Importpath: myimportpath,
417Info: absfn,
418Filesym: filesym,
419Absfn: absfn,
420External: !s.Static(),
421Scopes: scopes,
422UseBASEntries: ctxt.UseBASEntries,
423}
424if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
425ctxt.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).
463type DwarfFixupTable struct {
464ctxt *Link
465mu sync.Mutex
466symtab map[*LSym]int // maps abstract fn LSYM to index in svec
467svec []symFixups
468precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
469}
470
471type symFixups struct {
472fixups []relFixup
473doffsets []declOffset
474inlIndex int32
475defseen bool
476}
477
478type declOffset struct {
479// Index of variable within DCL list of pre-optimization function
480dclIdx int32
481// Offset of var's child DIE with respect to containing subprogram DIE
482offset int32
483}
484
485type relFixup struct {
486refsym *LSym
487relidx int32
488dclidx int32
489}
490
491type fnState struct {
492// precursor function (really *gc.Node)
493precursor interface{}
494// abstract function symbol
495absfn *LSym
496}
497
498func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
499return &DwarfFixupTable{
500ctxt: ctxt,
501symtab: make(map[*LSym]int),
502precursor: make(map[*LSym]fnState),
503}
504}
505
506func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
507if fnstate, found := ft.precursor[s]; found {
508return fnstate.precursor
509}
510return nil
511}
512
513func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
514if _, found := ft.precursor[s]; found {
515ft.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.
521absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
522absfn.Set(AttrDuplicateOK, true)
523absfn.Type = objabi.SDWARFABSFCN
524ft.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.
530if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
531s.Func.dwarfAbsFnSym = absfn
532}
533
534ft.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'.
539func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
540// Protect against concurrent access if multiple backend workers
541ft.mu.Lock()
542defer ft.mu.Unlock()
543
544// Create entry for symbol if not already present.
545idx, found := ft.symtab[tgt]
546if !found {
547ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
548idx = len(ft.svec) - 1
549ft.symtab[tgt] = idx
550}
551
552// Do we have child DIE offsets available? If so, then apply them,
553// otherwise create a fixup record.
554sf := &ft.svec[idx]
555if len(sf.doffsets) > 0 {
556found := false
557for _, do := range sf.doffsets {
558if do.dclIdx == int32(dclidx) {
559off := do.offset
560s.R[ridx].Add += int64(off)
561found = true
562break
563}
564}
565if !found {
566ft.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 {
569sf.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.
578func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
579// Length of these two slices should agree
580if len(vars) != len(coffsets) {
581ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
582return
583}
584
585// Generate the slice of declOffset's based in vars/coffsets
586doffsets := make([]declOffset, len(coffsets))
587for i := range coffsets {
588doffsets[i].dclIdx = vars[i].ChildIndex
589doffsets[i].offset = coffsets[i]
590}
591
592ft.mu.Lock()
593defer ft.mu.Unlock()
594
595// Store offsets for this symbol.
596idx, found := ft.symtab[s]
597if !found {
598sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
599ft.svec = append(ft.svec, sf)
600ft.symtab[s] = len(ft.svec) - 1
601} else {
602sf := &ft.svec[idx]
603sf.doffsets = doffsets
604sf.defseen = true
605}
606}
607
608func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
609sf := &ft.svec[slot]
610for _, f := range sf.fixups {
611dfound := false
612for _, doffset := range sf.doffsets {
613if doffset.dclIdx == f.dclidx {
614f.refsym.R[f.relidx].Add += int64(doffset.offset)
615dfound = true
616break
617}
618}
619if !dfound {
620ft.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.
627func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
628// Protect against concurrent access if multiple backend workers
629ft.mu.Lock()
630defer ft.mu.Unlock()
631
632if fnstate, found := ft.precursor[fnsym]; found {
633return fnstate.absfn
634}
635ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
636return 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.
645func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
646if trace {
647ft.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).
652fns := make([]*LSym, len(ft.precursor))
653idx := 0
654for fn := range ft.precursor {
655fns[idx] = fn
656idx++
657}
658sort.Sort(BySymName(fns))
659
660// Should not be called during parallel portion of compilation.
661if ft.ctxt.InParallel {
662ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
663}
664
665// Generate any missing abstract functions.
666for _, s := range fns {
667absfn := ft.AbsFuncDwarfSym(s)
668slot, found := ft.symtab[absfn]
669if !found || !ft.svec[slot].defseen {
670ft.ctxt.GenAbstractFunc(s)
671}
672}
673
674// Apply fixups.
675for _, s := range fns {
676absfn := ft.AbsFuncDwarfSym(s)
677slot, found := ft.symtab[absfn]
678if !found {
679ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
680} else {
681ft.processFixups(slot, s)
682}
683}
684}
685
686type BySymName []*LSym
687
688func (s BySymName) Len() int { return len(s) }
689func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
690func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
691