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 7package obj 8 9import ( 10 "cmd/internal/dwarf" 11 "cmd/internal/objabi" 12 "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 20const ( 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. 35func (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 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 114func 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 205type dwCtxt struct{ *Link } 206 207func (c dwCtxt) PtrSize() int { 208 return c.Arch.PtrSize 209} 210func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) { 211 ls := s.(*LSym) 212 ls.WriteInt(c.Link, ls.Size, size, i) 213} 214func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) { 215 c.AddInt(s, 2, int64(i)) 216} 217func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) { 218 b := []byte{byte(i)} 219 c.AddBytes(s, b) 220} 221func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) { 222 ls := s.(*LSym) 223 ls.WriteBytes(c.Link, ls.Size, b) 224} 225func (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} 230func (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} 240func (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} 245func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { 246 panic("should be used only in the linker") 247} 248func (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 261func (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 271func (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. 281func (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 288func (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 293func (c dwCtxt) Logf(format string, args ...interface{}) { 294 c.Link.Logf(format, args...) 295} 296 297func isDwarf64(ctxt *Link) bool { 298 return ctxt.Headtype == objabi.Haix 299} 300 301func (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 328func (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. 335func (ctxt *Link) fileSymbol(fn *LSym) *LSym { 336 p := fn.Func().Text 337 if p != nil { 338 f, _ := linkgetlineFromPos(ctxt, 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. 348func (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. 394func (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. 407func (ctxt *Link) DwarfGlobal(myimportpath, typename string, varSym *LSym) { 408 if myimportpath == "" || varSym.Local() { 409 return 410 } 411 var varname string 412 if varSym.Pkg == "_" { 413 // The frontend uses package "_" to mark symbols that should not 414 // be referenced by index, e.g. linkname'd symbols. 415 varname = varSym.Name 416 } else { 417 // Convert "".<name> into a fully qualified package.sym name. 418 varname = objabi.PathToPrefix(myimportpath) + varSym.Name[len(`""`):] 419 } 420 dieSymName := dwarf.InfoPrefix + varname 421 dieSym := ctxt.LookupInit(dieSymName, func(s *LSym) { 422 s.Type = objabi.SDWARFVAR 423 s.Set(AttrDuplicateOK, true) // needed for shared linkage 424 ctxt.Data = append(ctxt.Data, s) 425 }) 426 typeSym := ctxt.Lookup(dwarf.InfoPrefix + typename) 427 dwarf.PutGlobal(dwCtxt{ctxt}, dieSym, typeSym, varSym, varname) 428} 429 430func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) { 431 absfn := ctxt.DwFixups.AbsFuncDwarfSym(s) 432 if absfn.Size != 0 { 433 ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s) 434 } 435 if s.Func() == nil { 436 s.NewFuncInfo() 437 } 438 scopes, _ := ctxt.DebugInfo(s, absfn, curfn) 439 dwctxt := dwCtxt{ctxt} 440 filesym := ctxt.fileSymbol(s) 441 fnstate := dwarf.FnState{ 442 Name: s.Name, 443 Importpath: myimportpath, 444 Info: absfn, 445 Filesym: filesym, 446 Absfn: absfn, 447 External: !s.Static(), 448 Scopes: scopes, 449 UseBASEntries: ctxt.UseBASEntries, 450 } 451 if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil { 452 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 453 } 454} 455 456// This table is designed to aid in the creation of references between 457// DWARF subprogram DIEs. 458// 459// In most cases when one DWARF DIE has to refer to another DWARF DIE, 460// the target of the reference has an LSym, which makes it easy to use 461// the existing relocation mechanism. For DWARF inlined routine DIEs, 462// however, the subprogram DIE has to refer to a child 463// parameter/variable DIE of the abstract subprogram. This child DIE 464// doesn't have an LSym, and also of interest is the fact that when 465// DWARF generation is happening for inlined function F within caller 466// G, it's possible that DWARF generation hasn't happened yet for F, 467// so there is no way to know the offset of a child DIE within F's 468// abstract function. Making matters more complex, each inlined 469// instance of F may refer to a subset of the original F's variables 470// (depending on what happens with optimization, some vars may be 471// eliminated). 472// 473// The fixup table below helps overcome this hurdle. At the point 474// where a parameter/variable reference is made (via a call to 475// "ReferenceChildDIE"), a fixup record is generate that records 476// the relocation that is targeting that child variable. At a later 477// point when the abstract function DIE is emitted, there will be 478// a call to "RegisterChildDIEOffsets", at which point the offsets 479// needed to apply fixups are captured. Finally, once the parallel 480// portion of the compilation is done, fixups can actually be applied 481// during the "Finalize" method (this can't be done during the 482// parallel portion of the compile due to the possibility of data 483// races). 484// 485// This table is also used to record the "precursor" function node for 486// each function that is the target of an inline -- child DIE references 487// have to be made with respect to the original pre-optimization 488// version of the function (to allow for the fact that each inlined 489// body may be optimized differently). 490type DwarfFixupTable struct { 491 ctxt *Link 492 mu sync.Mutex 493 symtab map[*LSym]int // maps abstract fn LSYM to index in svec 494 svec []symFixups 495 precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym 496} 497 498type symFixups struct { 499 fixups []relFixup 500 doffsets []declOffset 501 inlIndex int32 502 defseen bool 503} 504 505type declOffset struct { 506 // Index of variable within DCL list of pre-optimization function 507 dclIdx int32 508 // Offset of var's child DIE with respect to containing subprogram DIE 509 offset int32 510} 511 512type relFixup struct { 513 refsym *LSym 514 relidx int32 515 dclidx int32 516} 517 518type fnState struct { 519 // precursor function (really *gc.Node) 520 precursor interface{} 521 // abstract function symbol 522 absfn *LSym 523} 524 525func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable { 526 return &DwarfFixupTable{ 527 ctxt: ctxt, 528 symtab: make(map[*LSym]int), 529 precursor: make(map[*LSym]fnState), 530 } 531} 532 533func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} { 534 if fnstate, found := ft.precursor[s]; found { 535 return fnstate.precursor 536 } 537 return nil 538} 539 540func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) { 541 if _, found := ft.precursor[s]; found { 542 ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s) 543 } 544 545 // initialize abstract function symbol now. This is done here so 546 // as to avoid data races later on during the parallel portion of 547 // the back end. 548 absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix) 549 absfn.Set(AttrDuplicateOK, true) 550 absfn.Type = objabi.SDWARFABSFCN 551 ft.ctxt.Data = append(ft.ctxt.Data, absfn) 552 553 // In the case of "late" inlining (inlines that happen during 554 // wrapper generation as opposed to the main inlining phase) it's 555 // possible that we didn't cache the abstract function sym for the 556 // text symbol -- do so now if needed. See issue 38068. 557 if fn := s.Func(); fn != nil && fn.dwarfAbsFnSym == nil { 558 fn.dwarfAbsFnSym = absfn 559 } 560 561 ft.precursor[s] = fnState{precursor: fn, absfn: absfn} 562} 563 564// Make a note of a child DIE reference: relocation 'ridx' within symbol 's' 565// is targeting child 'c' of DIE with symbol 'tgt'. 566func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) { 567 // Protect against concurrent access if multiple backend workers 568 ft.mu.Lock() 569 defer ft.mu.Unlock() 570 571 // Create entry for symbol if not already present. 572 idx, found := ft.symtab[tgt] 573 if !found { 574 ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)}) 575 idx = len(ft.svec) - 1 576 ft.symtab[tgt] = idx 577 } 578 579 // Do we have child DIE offsets available? If so, then apply them, 580 // otherwise create a fixup record. 581 sf := &ft.svec[idx] 582 if len(sf.doffsets) > 0 { 583 found := false 584 for _, do := range sf.doffsets { 585 if do.dclIdx == int32(dclidx) { 586 off := do.offset 587 s.R[ridx].Add += int64(off) 588 found = true 589 break 590 } 591 } 592 if !found { 593 ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt) 594 } 595 } else { 596 sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)}) 597 } 598} 599 600// Called once DWARF generation is complete for a given abstract function, 601// whose children might have been referenced via a call above. Stores 602// the offsets for any child DIEs (vars, params) so that they can be 603// consumed later in on DwarfFixupTable.Finalize, which applies any 604// outstanding fixups. 605func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) { 606 // Length of these two slices should agree 607 if len(vars) != len(coffsets) { 608 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch") 609 return 610 } 611 612 // Generate the slice of declOffset's based in vars/coffsets 613 doffsets := make([]declOffset, len(coffsets)) 614 for i := range coffsets { 615 doffsets[i].dclIdx = vars[i].ChildIndex 616 doffsets[i].offset = coffsets[i] 617 } 618 619 ft.mu.Lock() 620 defer ft.mu.Unlock() 621 622 // Store offsets for this symbol. 623 idx, found := ft.symtab[s] 624 if !found { 625 sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets} 626 ft.svec = append(ft.svec, sf) 627 ft.symtab[s] = len(ft.svec) - 1 628 } else { 629 sf := &ft.svec[idx] 630 sf.doffsets = doffsets 631 sf.defseen = true 632 } 633} 634 635func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) { 636 sf := &ft.svec[slot] 637 for _, f := range sf.fixups { 638 dfound := false 639 for _, doffset := range sf.doffsets { 640 if doffset.dclIdx == f.dclidx { 641 f.refsym.R[f.relidx].Add += int64(doffset.offset) 642 dfound = true 643 break 644 } 645 } 646 if !dfound { 647 ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx) 648 } 649 } 650} 651 652// return the LSym corresponding to the 'abstract subprogram' DWARF 653// info entry for a function. 654func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym { 655 // Protect against concurrent access if multiple backend workers 656 ft.mu.Lock() 657 defer ft.mu.Unlock() 658 659 if fnstate, found := ft.precursor[fnsym]; found { 660 return fnstate.absfn 661 } 662 ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym) 663 return nil 664} 665 666// Called after all functions have been compiled; the main job of this 667// function is to identify cases where there are outstanding fixups. 668// This scenario crops up when we have references to variables of an 669// inlined routine, but that routine is defined in some other package. 670// This helper walks through and locate these fixups, then invokes a 671// helper to create an abstract subprogram DIE for each one. 672func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) { 673 if trace { 674 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath) 675 } 676 677 // Collect up the keys from the precursor map, then sort the 678 // resulting list (don't want to rely on map ordering here). 679 fns := make([]*LSym, len(ft.precursor)) 680 idx := 0 681 for fn := range ft.precursor { 682 fns[idx] = fn 683 idx++ 684 } 685 sort.Sort(BySymName(fns)) 686 687 // Should not be called during parallel portion of compilation. 688 if ft.ctxt.InParallel { 689 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend") 690 } 691 692 // Generate any missing abstract functions. 693 for _, s := range fns { 694 absfn := ft.AbsFuncDwarfSym(s) 695 slot, found := ft.symtab[absfn] 696 if !found || !ft.svec[slot].defseen { 697 ft.ctxt.GenAbstractFunc(s) 698 } 699 } 700 701 // Apply fixups. 702 for _, s := range fns { 703 absfn := ft.AbsFuncDwarfSym(s) 704 slot, found := ft.symtab[absfn] 705 if !found { 706 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s) 707 } else { 708 ft.processFixups(slot, s) 709 } 710 } 711} 712 713type BySymName []*LSym 714 715func (s BySymName) Len() int { return len(s) } 716func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name } 717func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 718