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 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 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) Size(s dwarf.Sym) int64 { 211 return s.(*LSym).Size 212} 213func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) { 214 ls := s.(*LSym) 215 ls.WriteInt(c.Link, ls.Size, size, i) 216} 217func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) { 218 c.AddInt(s, 2, int64(i)) 219} 220func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) { 221 b := []byte{byte(i)} 222 c.AddBytes(s, b) 223} 224func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) { 225 ls := s.(*LSym) 226 ls.WriteBytes(c.Link, ls.Size, b) 227} 228func (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} 233func (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} 243func (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} 248func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) { 249 panic("should be used only in the linker") 250} 251func (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 264func (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. 274func (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 281func (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 286func (c dwCtxt) Logf(format string, args ...interface{}) { 287 c.Link.Logf(format, args...) 288} 289 290func isDwarf64(ctxt *Link) bool { 291 return ctxt.Headtype == objabi.Haix 292} 293 294func (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. 323func 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. 333func (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. 386func (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. 400func (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 415func (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). 473type 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 481type symFixups struct { 482 fixups []relFixup 483 doffsets []declOffset 484 inlIndex int32 485 defseen bool 486} 487 488type 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 495type relFixup struct { 496 refsym *LSym 497 relidx int32 498 dclidx int32 499} 500 501type fnState struct { 502 // precursor function 503 precursor Func 504 // abstract function symbol 505 absfn *LSym 506} 507 508func 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 516func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) Func { 517 if fnstate, found := ft.precursor[s]; found { 518 return fnstate.precursor 519 } 520 return nil 521} 522 523func (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'. 549func (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. 588func (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 618func (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. 637func (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. 655func (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 696type BySymName []*LSym 697 698func (s BySymName) Len() int { return len(s) } 699func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name } 700func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 701