github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/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.assembler file. 4 5 // Writes dwarf information to object files. 6 7 package obj 8 9 import ( 10 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/dwarf" 11 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/objabi" 12 "github.com/Rookout/GoSDK/pkg/services/assembler/internal/src" 13 "fmt" 14 "sort" 15 "sync" 16 ) 17 18 19 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 28 29 30 31 32 33 34 35 func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) { 36 dctxt := dwCtxt{ctxt} 37 38 39 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 46 47 stmt := true 48 line := int64(1) 49 pc := s.Func().Text.Pc 50 var lastpc int64 51 name := "" 52 prologue, wrotePrologue := false, false 53 54 for p := s.Func().Text; p != nil; p = p.Link { 55 prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd) 56 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 64 wrote := false 65 if name != newName { 66 newFile := ctxt.PosTable.FileIndex(newName) + 1 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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 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) 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 116 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 141 142 143 144 145 146 147 148 149 150 switch deltaPC - PC_RANGE { 151 152 153 154 155 156 157 158 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 164 } 165 } 166 } 167 if opcode < OPCODE_BASE || opcode > 255 { 168 panic(fmt.Sprintf("produced invalid special opcode %d", opcode)) 169 } 170 171 172 deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE) 173 deltaLC -= (opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE 174 175 176 if deltaPC != 0 { 177 if deltaPC <= PC_RANGE { 178 179 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 195 if deltaLC != 0 { 196 dctxt.AddUint8(s, dwarf.DW_LNS_advance_line) 197 dwarf.Sleb128put(dctxt, s, deltaLC) 198 } 199 200 201 dctxt.AddUint8(s, uint8(opcode)) 202 } 203 204 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 266 267 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 277 278 279 280 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 333 334 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 346 347 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 357 358 scopes, inlcalls, _ = ctxt.DebugInfo(s, info, curfn) 359 } 360 var err error 361 dwctxt := dwCtxt{ctxt} 362 filesym := ctxt.fileSymbol(s) 363 fnstate := &dwarf.FnState{ 364 Name: s.Name, 365 Importpath: myimportpath, 366 Info: info, 367 Filesym: filesym, 368 Loc: loc, 369 Ranges: ranges, 370 Absfn: absfunc, 371 StartPC: s, 372 Size: s.Size, 373 StartLine: s.Func().StartLine, 374 External: !s.Static(), 375 Scopes: scopes, 376 InlCalls: inlcalls, 377 UseBASEntries: ctxt.UseBASEntries, 378 } 379 if absfunc != nil { 380 err = dwarf.PutAbstractFunc(dwctxt, fnstate) 381 if err != nil { 382 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 383 } 384 err = dwarf.PutConcreteFunc(dwctxt, fnstate, s.Wrapper()) 385 } else { 386 err = dwarf.PutDefaultFunc(dwctxt, fnstate, s.Wrapper()) 387 } 388 if err != nil { 389 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 390 } 391 392 ctxt.generateDebugLinesSymbol(s, lines) 393 } 394 395 396 397 func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) { 398 if myimportpath == "" { 399 return 400 } 401 s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) { 402 s.Type = objabi.SDWARFCONST 403 ctxt.Data = append(ctxt.Data, s) 404 }) 405 dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val) 406 } 407 408 409 410 func (ctxt *Link) DwarfGlobal(myimportpath, typename string, varSym *LSym) { 411 if myimportpath == "" || varSym.Local() { 412 return 413 } 414 varname := varSym.Name 415 dieSym := &LSym{ 416 Type: objabi.SDWARFVAR, 417 } 418 varSym.NewVarInfo().dwarfInfoSym = dieSym 419 ctxt.Data = append(ctxt.Data, dieSym) 420 typeSym := ctxt.Lookup(dwarf.InfoPrefix + typename) 421 dwarf.PutGlobal(dwCtxt{ctxt}, dieSym, typeSym, varSym, varname) 422 } 423 424 func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) { 425 absfn := ctxt.DwFixups.AbsFuncDwarfSym(s) 426 if absfn.Size != 0 { 427 ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s) 428 } 429 if s.Func() == nil { 430 s.NewFuncInfo() 431 } 432 scopes, _, startPos := ctxt.DebugInfo(s, absfn, curfn) 433 _, startLine := ctxt.getFileSymbolAndLine(startPos) 434 dwctxt := dwCtxt{ctxt} 435 fnstate := dwarf.FnState{ 436 Name: s.Name, 437 Importpath: myimportpath, 438 Info: absfn, 439 Absfn: absfn, 440 StartLine: startLine, 441 External: !s.Static(), 442 Scopes: scopes, 443 UseBASEntries: ctxt.UseBASEntries, 444 } 445 if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil { 446 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err) 447 } 448 } 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 type DwarfFixupTable struct { 485 ctxt *Link 486 mu sync.Mutex 487 symtab map[*LSym]int 488 svec []symFixups 489 precursor map[*LSym]fnState 490 } 491 492 type symFixups struct { 493 fixups []relFixup 494 doffsets []declOffset 495 inlIndex int32 496 defseen bool 497 } 498 499 type declOffset struct { 500 501 dclIdx int32 502 503 offset int32 504 } 505 506 type relFixup struct { 507 refsym *LSym 508 relidx int32 509 dclidx int32 510 } 511 512 type fnState struct { 513 514 precursor interface{} 515 516 absfn *LSym 517 } 518 519 func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable { 520 return &DwarfFixupTable{ 521 ctxt: ctxt, 522 symtab: make(map[*LSym]int), 523 precursor: make(map[*LSym]fnState), 524 } 525 } 526 527 func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} { 528 if fnstate, found := ft.precursor[s]; found { 529 return fnstate.precursor 530 } 531 return nil 532 } 533 534 func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) { 535 if _, found := ft.precursor[s]; found { 536 ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s) 537 } 538 539 540 541 542 absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix) 543 absfn.Set(AttrDuplicateOK, true) 544 absfn.Type = objabi.SDWARFABSFCN 545 ft.ctxt.Data = append(ft.ctxt.Data, absfn) 546 547 548 549 550 551 if fn := s.Func(); fn != nil && fn.dwarfAbsFnSym == nil { 552 fn.dwarfAbsFnSym = absfn 553 } 554 555 ft.precursor[s] = fnState{precursor: fn, absfn: absfn} 556 } 557 558 559 560 func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) { 561 562 ft.mu.Lock() 563 defer ft.mu.Unlock() 564 565 566 idx, found := ft.symtab[tgt] 567 if !found { 568 ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)}) 569 idx = len(ft.svec) - 1 570 ft.symtab[tgt] = idx 571 } 572 573 574 575 sf := &ft.svec[idx] 576 if len(sf.doffsets) > 0 { 577 found := false 578 for _, do := range sf.doffsets { 579 if do.dclIdx == int32(dclidx) { 580 off := do.offset 581 s.R[ridx].Add += int64(off) 582 found = true 583 break 584 } 585 } 586 if !found { 587 ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt) 588 } 589 } else { 590 sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)}) 591 } 592 } 593 594 595 596 597 598 599 func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) { 600 601 if len(vars) != len(coffsets) { 602 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch") 603 return 604 } 605 606 607 doffsets := make([]declOffset, len(coffsets)) 608 for i := range coffsets { 609 doffsets[i].dclIdx = vars[i].ChildIndex 610 doffsets[i].offset = coffsets[i] 611 } 612 613 ft.mu.Lock() 614 defer ft.mu.Unlock() 615 616 617 idx, found := ft.symtab[s] 618 if !found { 619 sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets} 620 ft.svec = append(ft.svec, sf) 621 ft.symtab[s] = len(ft.svec) - 1 622 } else { 623 sf := &ft.svec[idx] 624 sf.doffsets = doffsets 625 sf.defseen = true 626 } 627 } 628 629 func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) { 630 sf := &ft.svec[slot] 631 for _, f := range sf.fixups { 632 dfound := false 633 for _, doffset := range sf.doffsets { 634 if doffset.dclIdx == f.dclidx { 635 f.refsym.R[f.relidx].Add += int64(doffset.offset) 636 dfound = true 637 break 638 } 639 } 640 if !dfound { 641 ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx) 642 } 643 } 644 } 645 646 647 648 func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym { 649 650 ft.mu.Lock() 651 defer ft.mu.Unlock() 652 653 if fnstate, found := ft.precursor[fnsym]; found { 654 return fnstate.absfn 655 } 656 ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym) 657 return nil 658 } 659 660 661 662 663 664 665 666 func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) { 667 if trace { 668 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath) 669 } 670 671 672 673 fns := make([]*LSym, len(ft.precursor)) 674 idx := 0 675 for fn := range ft.precursor { 676 fns[idx] = fn 677 idx++ 678 } 679 sort.Sort(BySymName(fns)) 680 681 682 if ft.ctxt.InParallel { 683 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend") 684 } 685 686 687 for _, s := range fns { 688 absfn := ft.AbsFuncDwarfSym(s) 689 slot, found := ft.symtab[absfn] 690 if !found || !ft.svec[slot].defseen { 691 ft.ctxt.GenAbstractFunc(s) 692 } 693 } 694 695 696 for _, s := range fns { 697 absfn := ft.AbsFuncDwarfSym(s) 698 slot, found := ft.symtab[absfn] 699 if !found { 700 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s) 701 } else { 702 ft.processFixups(slot, s) 703 } 704 } 705 } 706 707 type BySymName []*LSym 708 709 func (s BySymName) Len() int { return len(s) } 710 func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name } 711 func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }