github.com/bir3/gocompiler@v0.9.2202/src/cmd/internal/obj/dwarf.go (about) 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/bir3/gocompiler/src/cmd/internal/dwarf" 11 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 12 "github.com/bir3/gocompiler/src/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 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 fileIndex := 1 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 newFileIndex, newLine := ctxt.getFileIndexAndLine(p.Pos) 62 newFileIndex++ // 1 indexing for the table 63 64 // Output debug info. 65 wrote := false 66 if newFileIndex != fileIndex { 67 dctxt.AddUint8(lines, dwarf.DW_LNS_set_file) 68 dwarf.Uleb128put(dctxt, lines, int64(newFileIndex)) 69 fileIndex = newFileIndex 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 114 func 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 205 type dwCtxt struct{ *Link } 206 207 func (c dwCtxt) PtrSize() int { 208 return c.Arch.PtrSize 209 } 210 func (c dwCtxt) Size(s dwarf.Sym) int64 { 211 return s.(*LSym).Size 212 } 213 func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) { 214 ls := s.(*LSym) 215 ls.WriteInt(c.Link, ls.Size, size, i) 216 } 217 func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) { 218 c.AddInt(s, 2, int64(i)) 219 } 220 func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) { 221 b := []byte{byte(i)} 222 c.AddBytes(s, b) 223 } 224 func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) { 225 ls := s.(*LSym) 226 ls.WriteBytes(c.Link, ls.Size, b) 227 } 228 func (c dwCtxt) AddString(s dwarf.Sym, v string) { 229 ls := s.(*LSym) 230 ls.WriteString(c.Link, ls.Size, len(v), v) 231 ls.WriteInt(c.Link, ls.Size, 1, 0) 232 } 233 func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) { 234 ls := s.(*LSym) 235 size := c.PtrSize() 236 if data != nil { 237 rsym := data.(*LSym) 238 ls.WriteAddr(c.Link, ls.Size, size, rsym, value) 239 } else { 240 ls.WriteInt(c.Link, ls.Size, size, value) 241 } 242 } 243 func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) { 244 ls := s.(*LSym) 245 rsym := data.(*LSym) 246 ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value) 247 } 248 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { 249 panic("should be used only in the linker") 250 } 251 func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) { 252 size := 4 253 if isDwarf64(c.Link) { 254 size = 8 255 } 256 257 ls := s.(*LSym) 258 rsym := t.(*LSym) 259 ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs) 260 r := &ls.R[len(ls.R)-1] 261 r.Type = objabi.R_DWARFSECREF 262 } 263 264 func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 { 265 ls := s.(*LSym) 266 return ls.Size 267 } 268 269 // Here "from" is a symbol corresponding to an inlined or concrete 270 // function, "to" is the symbol for the corresponding abstract 271 // function, and "dclIdx" is the index of the symbol of interest with 272 // respect to the Dcl slice of the original pre-optimization version 273 // of the inlined function. 274 func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) { 275 ls := from.(*LSym) 276 tls := to.(*LSym) 277 ridx := len(ls.R) - 1 278 c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex) 279 } 280 281 func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) { 282 ls := s.(*LSym) 283 c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets) 284 } 285 286 func (c dwCtxt) Logf(format string, args ...interface{}) { 287 c.Link.Logf(format, args...) 288 } 289 290 func isDwarf64(ctxt *Link) bool { 291 return ctxt.Headtype == objabi.Haix 292 } 293 294 func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) { 295 if s.Type != objabi.STEXT { 296 ctxt.Diag("dwarfSym of non-TEXT %v", s) 297 } 298 fn := s.Func() 299 if fn.dwarfInfoSym == nil { 300 fn.dwarfInfoSym = &LSym{ 301 Type: objabi.SDWARFFCN, 302 } 303 if ctxt.Flag_locationlists { 304 fn.dwarfLocSym = &LSym{ 305 Type: objabi.SDWARFLOC, 306 } 307 } 308 fn.dwarfRangesSym = &LSym{ 309 Type: objabi.SDWARFRANGE, 310 } 311 fn.dwarfDebugLinesSym = &LSym{ 312 Type: objabi.SDWARFLINES, 313 } 314 if s.WasInlined() { 315 fn.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s) 316 } 317 } 318 return fn.dwarfInfoSym, fn.dwarfLocSym, fn.dwarfRangesSym, fn.dwarfAbsFnSym, fn.dwarfDebugLinesSym 319 } 320 321 // textPos returns the source position of the first instruction (prog) 322 // of the specified function. 323 func textPos(fn *LSym) src.XPos { 324 if p := fn.Func().Text; p != nil { 325 return p.Pos 326 } 327 return src.NoXPos 328 } 329 330 // populateDWARF fills in the DWARF Debugging Information Entries for 331 // TEXT symbol 's'. The various DWARF symbols must already have been 332 // initialized in InitTextSym. 333 func (ctxt *Link) populateDWARF(curfn Func, s *LSym) { 334 myimportpath := ctxt.Pkgpath 335 if myimportpath == "" { 336 return 337 } 338 339 info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s) 340 if info.Size != 0 { 341 ctxt.Diag("makeFuncDebugEntry double process %v", s) 342 } 343 var scopes []dwarf.Scope 344 var inlcalls dwarf.InlCalls 345 if ctxt.DebugInfo != nil { 346 scopes, inlcalls = ctxt.DebugInfo(s, info, curfn) 347 } 348 var err error 349 dwctxt := dwCtxt{ctxt} 350 startPos := ctxt.InnermostPos(textPos(s)) 351 if !startPos.IsKnown() || startPos.RelLine() != uint(s.Func().StartLine) { 352 panic("bad startPos") 353 } 354 fnstate := &dwarf.FnState{ 355 Name: s.Name, 356 Info: info, 357 Loc: loc, 358 Ranges: ranges, 359 Absfn: absfunc, 360 StartPC: s, 361 Size: s.Size, 362 StartPos: startPos, 363 External: !s.Static(), 364 Scopes: scopes, 365 InlCalls: inlcalls, 366 UseBASEntries: ctxt.UseBASEntries, 367 } 368 if absfunc != nil { 369 err = dwarf.PutAbstractFunc(dwctxt, fnstate) 370 if err != nil { 371 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 372 } 373 err = dwarf.PutConcreteFunc(dwctxt, fnstate, s.Wrapper()) 374 } else { 375 err = dwarf.PutDefaultFunc(dwctxt, fnstate, s.Wrapper()) 376 } 377 if err != nil { 378 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 379 } 380 // Fill in the debug lines symbol. 381 ctxt.generateDebugLinesSymbol(s, lines) 382 } 383 384 // DwarfIntConst creates a link symbol for an integer constant with the 385 // given name, type and value. 386 func (ctxt *Link) DwarfIntConst(name, typename string, val int64) { 387 myimportpath := ctxt.Pkgpath 388 if myimportpath == "" { 389 return 390 } 391 s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) { 392 s.Type = objabi.SDWARFCONST 393 ctxt.Data = append(ctxt.Data, s) 394 }) 395 dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val) 396 } 397 398 // DwarfGlobal creates a link symbol containing a DWARF entry for 399 // a global variable. 400 func (ctxt *Link) DwarfGlobal(typename string, varSym *LSym) { 401 myimportpath := ctxt.Pkgpath 402 if myimportpath == "" || varSym.Local() { 403 return 404 } 405 varname := varSym.Name 406 dieSym := &LSym{ 407 Type: objabi.SDWARFVAR, 408 } 409 varSym.NewVarInfo().dwarfInfoSym = dieSym 410 ctxt.Data = append(ctxt.Data, dieSym) 411 typeSym := ctxt.Lookup(dwarf.InfoPrefix + typename) 412 dwarf.PutGlobal(dwCtxt{ctxt}, dieSym, typeSym, varSym, varname) 413 } 414 415 func (ctxt *Link) DwarfAbstractFunc(curfn Func, s *LSym) { 416 absfn := ctxt.DwFixups.AbsFuncDwarfSym(s) 417 if absfn.Size != 0 { 418 ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s) 419 } 420 if s.Func() == nil { 421 s.NewFuncInfo() 422 } 423 scopes, _ := ctxt.DebugInfo(s, absfn, curfn) 424 dwctxt := dwCtxt{ctxt} 425 fnstate := dwarf.FnState{ 426 Name: s.Name, 427 Info: absfn, 428 Absfn: absfn, 429 StartPos: ctxt.InnermostPos(curfn.Pos()), 430 External: !s.Static(), 431 Scopes: scopes, 432 UseBASEntries: ctxt.UseBASEntries, 433 } 434 if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil { 435 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 436 } 437 } 438 439 // This table is designed to aid in the creation of references between 440 // DWARF subprogram DIEs. 441 // 442 // In most cases when one DWARF DIE has to refer to another DWARF DIE, 443 // the target of the reference has an LSym, which makes it easy to use 444 // the existing relocation mechanism. For DWARF inlined routine DIEs, 445 // however, the subprogram DIE has to refer to a child 446 // parameter/variable DIE of the abstract subprogram. This child DIE 447 // doesn't have an LSym, and also of interest is the fact that when 448 // DWARF generation is happening for inlined function F within caller 449 // G, it's possible that DWARF generation hasn't happened yet for F, 450 // so there is no way to know the offset of a child DIE within F's 451 // abstract function. Making matters more complex, each inlined 452 // instance of F may refer to a subset of the original F's variables 453 // (depending on what happens with optimization, some vars may be 454 // eliminated). 455 // 456 // The fixup table below helps overcome this hurdle. At the point 457 // where a parameter/variable reference is made (via a call to 458 // "ReferenceChildDIE"), a fixup record is generate that records 459 // the relocation that is targeting that child variable. At a later 460 // point when the abstract function DIE is emitted, there will be 461 // a call to "RegisterChildDIEOffsets", at which point the offsets 462 // needed to apply fixups are captured. Finally, once the parallel 463 // portion of the compilation is done, fixups can actually be applied 464 // during the "Finalize" method (this can't be done during the 465 // parallel portion of the compile due to the possibility of data 466 // races). 467 // 468 // This table is also used to record the "precursor" function node for 469 // each function that is the target of an inline -- child DIE references 470 // have to be made with respect to the original pre-optimization 471 // version of the function (to allow for the fact that each inlined 472 // body may be optimized differently). 473 type DwarfFixupTable struct { 474 ctxt *Link 475 mu sync.Mutex 476 symtab map[*LSym]int // maps abstract fn LSYM to index in svec 477 svec []symFixups 478 precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym 479 } 480 481 type symFixups struct { 482 fixups []relFixup 483 doffsets []declOffset 484 inlIndex int32 485 defseen bool 486 } 487 488 type declOffset struct { 489 // Index of variable within DCL list of pre-optimization function 490 dclIdx int32 491 // Offset of var's child DIE with respect to containing subprogram DIE 492 offset int32 493 } 494 495 type relFixup struct { 496 refsym *LSym 497 relidx int32 498 dclidx int32 499 } 500 501 type fnState struct { 502 // precursor function 503 precursor Func 504 // abstract function symbol 505 absfn *LSym 506 } 507 508 func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable { 509 return &DwarfFixupTable{ 510 ctxt: ctxt, 511 symtab: make(map[*LSym]int), 512 precursor: make(map[*LSym]fnState), 513 } 514 } 515 516 func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) Func { 517 if fnstate, found := ft.precursor[s]; found { 518 return fnstate.precursor 519 } 520 return nil 521 } 522 523 func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn Func) { 524 if _, found := ft.precursor[s]; found { 525 ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s) 526 } 527 528 // initialize abstract function symbol now. This is done here so 529 // as to avoid data races later on during the parallel portion of 530 // the back end. 531 absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix) 532 absfn.Set(AttrDuplicateOK, true) 533 absfn.Type = objabi.SDWARFABSFCN 534 ft.ctxt.Data = append(ft.ctxt.Data, absfn) 535 536 // In the case of "late" inlining (inlines that happen during 537 // wrapper generation as opposed to the main inlining phase) it's 538 // possible that we didn't cache the abstract function sym for the 539 // text symbol -- do so now if needed. See issue 38068. 540 if fn := s.Func(); fn != nil && fn.dwarfAbsFnSym == nil { 541 fn.dwarfAbsFnSym = absfn 542 } 543 544 ft.precursor[s] = fnState{precursor: fn, absfn: absfn} 545 } 546 547 // Make a note of a child DIE reference: relocation 'ridx' within symbol 's' 548 // is targeting child 'c' of DIE with symbol 'tgt'. 549 func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) { 550 // Protect against concurrent access if multiple backend workers 551 ft.mu.Lock() 552 defer ft.mu.Unlock() 553 554 // Create entry for symbol if not already present. 555 idx, found := ft.symtab[tgt] 556 if !found { 557 ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)}) 558 idx = len(ft.svec) - 1 559 ft.symtab[tgt] = idx 560 } 561 562 // Do we have child DIE offsets available? If so, then apply them, 563 // otherwise create a fixup record. 564 sf := &ft.svec[idx] 565 if len(sf.doffsets) > 0 { 566 found := false 567 for _, do := range sf.doffsets { 568 if do.dclIdx == int32(dclidx) { 569 off := do.offset 570 s.R[ridx].Add += int64(off) 571 found = true 572 break 573 } 574 } 575 if !found { 576 ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt) 577 } 578 } else { 579 sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)}) 580 } 581 } 582 583 // Called once DWARF generation is complete for a given abstract function, 584 // whose children might have been referenced via a call above. Stores 585 // the offsets for any child DIEs (vars, params) so that they can be 586 // consumed later in on DwarfFixupTable.Finalize, which applies any 587 // outstanding fixups. 588 func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) { 589 // Length of these two slices should agree 590 if len(vars) != len(coffsets) { 591 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch") 592 return 593 } 594 595 // Generate the slice of declOffset's based in vars/coffsets 596 doffsets := make([]declOffset, len(coffsets)) 597 for i := range coffsets { 598 doffsets[i].dclIdx = vars[i].ChildIndex 599 doffsets[i].offset = coffsets[i] 600 } 601 602 ft.mu.Lock() 603 defer ft.mu.Unlock() 604 605 // Store offsets for this symbol. 606 idx, found := ft.symtab[s] 607 if !found { 608 sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets} 609 ft.svec = append(ft.svec, sf) 610 ft.symtab[s] = len(ft.svec) - 1 611 } else { 612 sf := &ft.svec[idx] 613 sf.doffsets = doffsets 614 sf.defseen = true 615 } 616 } 617 618 func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) { 619 sf := &ft.svec[slot] 620 for _, f := range sf.fixups { 621 dfound := false 622 for _, doffset := range sf.doffsets { 623 if doffset.dclIdx == f.dclidx { 624 f.refsym.R[f.relidx].Add += int64(doffset.offset) 625 dfound = true 626 break 627 } 628 } 629 if !dfound { 630 ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx) 631 } 632 } 633 } 634 635 // return the LSym corresponding to the 'abstract subprogram' DWARF 636 // info entry for a function. 637 func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym { 638 // Protect against concurrent access if multiple backend workers 639 ft.mu.Lock() 640 defer ft.mu.Unlock() 641 642 if fnstate, found := ft.precursor[fnsym]; found { 643 return fnstate.absfn 644 } 645 ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym) 646 return nil 647 } 648 649 // Called after all functions have been compiled; the main job of this 650 // function is to identify cases where there are outstanding fixups. 651 // This scenario crops up when we have references to variables of an 652 // inlined routine, but that routine is defined in some other package. 653 // This helper walks through and locate these fixups, then invokes a 654 // helper to create an abstract subprogram DIE for each one. 655 func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) { 656 if trace { 657 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath) 658 } 659 660 // Collect up the keys from the precursor map, then sort the 661 // resulting list (don't want to rely on map ordering here). 662 fns := make([]*LSym, len(ft.precursor)) 663 idx := 0 664 for fn := range ft.precursor { 665 fns[idx] = fn 666 idx++ 667 } 668 sort.Sort(BySymName(fns)) 669 670 // Should not be called during parallel portion of compilation. 671 if ft.ctxt.InParallel { 672 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend") 673 } 674 675 // Generate any missing abstract functions. 676 for _, s := range fns { 677 absfn := ft.AbsFuncDwarfSym(s) 678 slot, found := ft.symtab[absfn] 679 if !found || !ft.svec[slot].defseen { 680 ft.ctxt.GenAbstractFunc(s) 681 } 682 } 683 684 // Apply fixups. 685 for _, s := range fns { 686 absfn := ft.AbsFuncDwarfSym(s) 687 slot, found := ft.symtab[absfn] 688 if !found { 689 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s) 690 } else { 691 ft.processFixups(slot, s) 692 } 693 } 694 } 695 696 type BySymName []*LSym 697 698 func (s BySymName) Len() int { return len(s) } 699 func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name } 700 func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }