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