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