gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

dwarf.go (22513B)


      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] }