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