1
2
3
4
5
6
7 package obj
8
9 import (
10 "cmd/internal/dwarf"
11 "cmd/internal/objabi"
12 "cmd/internal/src"
13 "fmt"
14 "slices"
15 "strings"
16 "sync"
17 )
18
19
20
21 const (
22 LINE_BASE = -4
23 LINE_RANGE = 10
24 PC_RANGE = (255 - OPCODE_BASE) / LINE_RANGE
25 OPCODE_BASE = 11
26 )
27
28
29
30
31
32
33
34
35
36 func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
37 dctxt := dwCtxt{ctxt}
38
39
40
41 dctxt.AddUint8(lines, 0)
42 dwarf.Uleb128put(dctxt, lines, 1+int64(ctxt.Arch.PtrSize))
43 dctxt.AddUint8(lines, dwarf.DW_LNE_set_address)
44 dctxt.AddAddress(lines, s, 0)
45
46
47
48 stmt := true
49 line := int64(1)
50 pc := s.Func().Text.Pc
51 var lastpc int64
52 fileIndex := 1
53 prologue, wrotePrologue := false, false
54
55 for p := s.Func().Text; p != nil; p = p.Link {
56 prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
57
58 if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) {
59 continue
60 }
61 newStmt := p.Pos.IsStmt() != src.PosNotStmt
62 newFileIndex, newLine := ctxt.getFileIndexAndLine(p.Pos)
63 newFileIndex++
64
65
66 wrote := false
67 if newFileIndex != fileIndex {
68 dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
69 dwarf.Uleb128put(dctxt, lines, int64(newFileIndex))
70 fileIndex = newFileIndex
71 wrote = true
72 }
73 if prologue && !wrotePrologue {
74 dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end))
75 wrotePrologue = true
76 wrote = true
77 }
78 if stmt != newStmt {
79 dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt))
80 stmt = newStmt
81 wrote = true
82 }
83
84 if line != int64(newLine) || wrote {
85 pcdelta := p.Pc - pc
86 lastpc = p.Pc
87 putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line)
88 line, pc = int64(newLine), p.Pc
89 }
90 }
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 lastlen := uint64(s.Size - (lastpc - s.Func().Text.Pc))
108 dctxt.AddUint8(lines, dwarf.DW_LNS_advance_pc)
109 dwarf.Uleb128put(dctxt, lines, int64(lastlen))
110 dctxt.AddUint8(lines, 0)
111 dwarf.Uleb128put(dctxt, lines, 1)
112 dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence)
113 }
114
115 func putpclcdelta(linkctxt *Link, dctxt dwCtxt, s *LSym, deltaPC uint64, deltaLC int64) {
116
117
118 var opcode int64
119 if deltaLC < LINE_BASE {
120 if deltaPC >= PC_RANGE {
121 opcode = OPCODE_BASE + (LINE_RANGE * PC_RANGE)
122 } else {
123 opcode = OPCODE_BASE + (LINE_RANGE * int64(deltaPC))
124 }
125 } else if deltaLC < LINE_BASE+LINE_RANGE {
126 if deltaPC >= PC_RANGE {
127 opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * PC_RANGE)
128 if opcode > 255 {
129 opcode -= LINE_RANGE
130 }
131 } else {
132 opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * int64(deltaPC))
133 }
134 } else {
135 if deltaPC <= PC_RANGE {
136 opcode = OPCODE_BASE + (LINE_RANGE - 1) + (LINE_RANGE * int64(deltaPC))
137 if opcode > 255 {
138 opcode = 255
139 }
140 } else {
141
142
143
144
145
146
147
148
149
150
151 switch deltaPC - PC_RANGE {
152
153
154
155
156
157
158
159
160 case PC_RANGE, (1 << 7) - 1, (1 << 16) - 1, (1 << 21) - 1, (1 << 28) - 1,
161 (1 << 35) - 1, (1 << 42) - 1, (1 << 49) - 1, (1 << 56) - 1, (1 << 63) - 1:
162 opcode = 255
163 default:
164 opcode = OPCODE_BASE + LINE_RANGE*PC_RANGE - 1
165 }
166 }
167 }
168 if opcode < OPCODE_BASE || opcode > 255 {
169 panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
170 }
171
172
173 deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE)
174 deltaLC -= (opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE
175
176
177 if deltaPC != 0 {
178 if deltaPC <= PC_RANGE {
179
180
181 opcode -= LINE_RANGE * int64(PC_RANGE-deltaPC)
182 if opcode < OPCODE_BASE {
183 panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
184 }
185 dctxt.AddUint8(s, dwarf.DW_LNS_const_add_pc)
186 } else if (1<<14) <= deltaPC && deltaPC < (1<<16) {
187 dctxt.AddUint8(s, dwarf.DW_LNS_fixed_advance_pc)
188 dctxt.AddUint16(s, uint16(deltaPC))
189 } else {
190 dctxt.AddUint8(s, dwarf.DW_LNS_advance_pc)
191 dwarf.Uleb128put(dctxt, s, int64(deltaPC))
192 }
193 }
194
195
196 if deltaLC != 0 {
197 dctxt.AddUint8(s, dwarf.DW_LNS_advance_line)
198 dwarf.Sleb128put(dctxt, s, deltaLC)
199 }
200
201
202 dctxt.AddUint8(s, uint8(opcode))
203 }
204
205
206 type dwCtxt struct{ *Link }
207
208 func (c dwCtxt) PtrSize() int {
209 return c.Arch.PtrSize
210 }
211 func (c dwCtxt) Size(s dwarf.Sym) int64 {
212 return s.(*LSym).Size
213 }
214 func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
215 ls := s.(*LSym)
216 ls.WriteInt(c.Link, ls.Size, size, i)
217 }
218 func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
219 c.AddInt(s, 2, int64(i))
220 }
221 func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
222 b := []byte{byte(i)}
223 c.AddBytes(s, b)
224 }
225 func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
226 ls := s.(*LSym)
227 ls.WriteBytes(c.Link, ls.Size, b)
228 }
229 func (c dwCtxt) AddString(s dwarf.Sym, v string) {
230 ls := s.(*LSym)
231 ls.WriteString(c.Link, ls.Size, len(v), v)
232 ls.WriteInt(c.Link, ls.Size, 1, 0)
233 }
234 func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
235 ls := s.(*LSym)
236 size := c.PtrSize()
237 if data != nil {
238 rsym := data.(*LSym)
239 ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
240 } else {
241 ls.WriteInt(c.Link, ls.Size, size, value)
242 }
243 }
244 func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
245 ls := s.(*LSym)
246 rsym := data.(*LSym)
247 ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
248 }
249 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
250 panic("should be used only in the linker")
251 }
252 func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
253 size := 4
254 if isDwarf64(c.Link) {
255 size = 8
256 }
257
258 ls := s.(*LSym)
259 rsym := t.(*LSym)
260 ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
261 r := &ls.R[len(ls.R)-1]
262 r.Type = objabi.R_DWARFSECREF
263 }
264
265 func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
266 ls := s.(*LSym)
267 return ls.Size
268 }
269
270
271
272
273
274
275 func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
276 ls := from.(*LSym)
277 tls := to.(*LSym)
278 ridx := len(ls.R) - 1
279 c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
280 }
281
282 func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
283 ls := s.(*LSym)
284 c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
285 }
286
287 func (c dwCtxt) Logf(format string, args ...interface{}) {
288 c.Link.Logf(format, args...)
289 }
290
291 func (c dwCtxt) AddIndirectTextRef(s dwarf.Sym, t interface{}) {
292 ls := s.(*LSym)
293 tsym := t.(*LSym)
294
295
296
297
298 ls.WriteDwTxtAddrx(c.Link, ls.Size, tsym, c.DwTextCount*2)
299 }
300
301 func isDwarf64(ctxt *Link) bool {
302 return ctxt.Headtype == objabi.Haix
303 }
304
305 func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
306 if !s.Type.IsText() {
307 ctxt.Diag("dwarfSym of non-TEXT %v", s)
308 }
309 fn := s.Func()
310 if fn.dwarfInfoSym == nil {
311 fn.dwarfInfoSym = &LSym{
312 Type: objabi.SDWARFFCN,
313 }
314 if ctxt.Flag_locationlists {
315 fn.dwarfLocSym = &LSym{
316 Type: objabi.SDWARFLOC,
317 }
318 }
319 fn.dwarfRangesSym = &LSym{
320 Type: objabi.SDWARFRANGE,
321 }
322 fn.dwarfDebugLinesSym = &LSym{
323 Type: objabi.SDWARFLINES,
324 }
325 if s.WasInlined() {
326 fn.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
327 }
328 }
329 return fn.dwarfInfoSym, fn.dwarfLocSym, fn.dwarfRangesSym, fn.dwarfAbsFnSym, fn.dwarfDebugLinesSym
330 }
331
332
333
334 func textPos(fn *LSym) src.XPos {
335 if p := fn.Func().Text; p != nil {
336 return p.Pos
337 }
338 return src.NoXPos
339 }
340
341
342
343
344 func (ctxt *Link) populateDWARF(curfn Func, s *LSym) {
345 myimportpath := ctxt.Pkgpath
346 if myimportpath == "" {
347 return
348 }
349
350 info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
351 if info.Size != 0 {
352 ctxt.Diag("makeFuncDebugEntry double process %v", s)
353 }
354 var scopes []dwarf.Scope
355 var inlcalls dwarf.InlCalls
356 if ctxt.DebugInfo != nil {
357 scopes, inlcalls = ctxt.DebugInfo(ctxt, s, info, curfn)
358 }
359 var err error
360 dwctxt := dwCtxt{ctxt}
361 startPos := ctxt.InnermostPos(textPos(s))
362 if !startPos.IsKnown() || startPos.RelLine() != uint(s.Func().StartLine) {
363 panic("bad startPos")
364 }
365 fnstate := &dwarf.FnState{
366 Name: s.Name,
367 Info: info,
368 Loc: loc,
369 Ranges: ranges,
370 Absfn: absfunc,
371 StartPC: s,
372 Size: s.Size,
373 StartPos: startPos,
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 ctxt.DwTextCount)
386 } else {
387 err = dwarf.PutDefaultFunc(dwctxt, fnstate, s.Wrapper())
388 }
389 if err != nil {
390 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
391 }
392
393 ctxt.generateDebugLinesSymbol(s, lines)
394 }
395
396
397
398 func (ctxt *Link) DwarfIntConst(name, typename string, val int64) {
399 myimportpath := ctxt.Pkgpath
400 if myimportpath == "" {
401 return
402 }
403 s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
404 s.Type = objabi.SDWARFCONST
405 ctxt.Data = append(ctxt.Data, s)
406 })
407 dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
408 }
409
410
411
412 func (ctxt *Link) DwarfGlobal(typename string, varSym *LSym) {
413 myimportpath := ctxt.Pkgpath
414 if myimportpath == "" || varSym.Local() {
415 return
416 }
417 varname := varSym.Name
418 dieSym := &LSym{
419 Type: objabi.SDWARFVAR,
420 }
421 varSym.NewVarInfo().dwarfInfoSym = dieSym
422 ctxt.Data = append(ctxt.Data, dieSym)
423 typeSym := ctxt.Lookup(dwarf.InfoPrefix + typename)
424 dwarf.PutGlobal(dwCtxt{ctxt}, dieSym, typeSym, varSym, varname)
425 }
426
427 func (ctxt *Link) DwarfAbstractFunc(curfn Func, s *LSym) {
428 absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
429 if absfn.Size != 0 {
430 ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
431 }
432 if s.Func() == nil {
433 s.NewFuncInfo()
434 }
435 scopes, _ := ctxt.DebugInfo(ctxt, s, absfn, curfn)
436 dwctxt := dwCtxt{ctxt}
437 fnstate := dwarf.FnState{
438 Name: s.Name,
439 Info: absfn,
440 Absfn: absfn,
441 StartPos: ctxt.InnermostPos(curfn.Pos()),
442 External: !s.Static(),
443 Scopes: scopes,
444 UseBASEntries: ctxt.UseBASEntries,
445 }
446 if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
447 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
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
485 type DwarfFixupTable struct {
486 ctxt *Link
487 mu sync.Mutex
488 symtab map[*LSym]int
489 svec []symFixups
490 precursor map[*LSym]fnState
491 }
492
493 type symFixups struct {
494 fixups []relFixup
495 doffsets []declOffset
496 inlIndex int32
497 defseen bool
498 }
499
500 type declOffset struct {
501
502 dclIdx int32
503
504 offset int32
505 }
506
507 type relFixup struct {
508 refsym *LSym
509 relidx int32
510 dclidx int32
511 }
512
513 type fnState struct {
514
515 precursor Func
516
517 absfn *LSym
518 }
519
520 func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
521 return &DwarfFixupTable{
522 ctxt: ctxt,
523 symtab: make(map[*LSym]int),
524 precursor: make(map[*LSym]fnState),
525 }
526 }
527
528 func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) Func {
529 if fnstate, found := ft.precursor[s]; found {
530 return fnstate.precursor
531 }
532 return nil
533 }
534
535 func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn Func) {
536 if _, found := ft.precursor[s]; found {
537 ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
538 }
539
540
541
542
543 absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
544 absfn.Set(AttrDuplicateOK, true)
545 absfn.Type = objabi.SDWARFABSFCN
546 ft.ctxt.Data = append(ft.ctxt.Data, absfn)
547
548
549
550
551
552 if fn := s.Func(); fn != nil && fn.dwarfAbsFnSym == nil {
553 fn.dwarfAbsFnSym = absfn
554 }
555
556 ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
557 }
558
559
560
561 func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
562
563 ft.mu.Lock()
564 defer ft.mu.Unlock()
565
566
567 idx, found := ft.symtab[tgt]
568 if !found {
569 ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
570 idx = len(ft.svec) - 1
571 ft.symtab[tgt] = idx
572 }
573
574
575
576 sf := &ft.svec[idx]
577 if len(sf.doffsets) > 0 {
578 found := false
579 for _, do := range sf.doffsets {
580 if do.dclIdx == int32(dclidx) {
581 off := do.offset
582 s.R[ridx].Add += int64(off)
583 found = true
584 break
585 }
586 }
587 if !found {
588 ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
589 }
590 } else {
591 sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
592 }
593 }
594
595
596
597
598
599
600 func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
601
602 if len(vars) != len(coffsets) {
603 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
604 return
605 }
606
607
608 doffsets := make([]declOffset, len(coffsets))
609 for i := range coffsets {
610 doffsets[i].dclIdx = vars[i].ChildIndex
611 doffsets[i].offset = coffsets[i]
612 }
613
614 ft.mu.Lock()
615 defer ft.mu.Unlock()
616
617
618 idx, found := ft.symtab[s]
619 if !found {
620 sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
621 ft.svec = append(ft.svec, sf)
622 ft.symtab[s] = len(ft.svec) - 1
623 } else {
624 sf := &ft.svec[idx]
625 sf.doffsets = doffsets
626 sf.defseen = true
627 }
628 }
629
630 func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
631 sf := &ft.svec[slot]
632 for _, f := range sf.fixups {
633 dfound := false
634 for _, doffset := range sf.doffsets {
635 if doffset.dclIdx == f.dclidx {
636 f.refsym.R[f.relidx].Add += int64(doffset.offset)
637 dfound = true
638 break
639 }
640 }
641 if !dfound {
642 ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
643 }
644 }
645 }
646
647
648
649 func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
650
651 ft.mu.Lock()
652 defer ft.mu.Unlock()
653
654 if fnstate, found := ft.precursor[fnsym]; found {
655 return fnstate.absfn
656 }
657 ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
658 return nil
659 }
660
661
662
663
664
665
666
667 func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
668 if trace {
669 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
670 }
671
672
673
674 fns := make([]*LSym, len(ft.precursor))
675 idx := 0
676 for fn := range ft.precursor {
677 fns[idx] = fn
678 idx++
679 }
680 slices.SortFunc(fns, func(a, b *LSym) int {
681 return strings.Compare(a.Name, b.Name)
682 })
683
684
685 if ft.ctxt.InParallel {
686 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
687 }
688
689
690 for _, s := range fns {
691 absfn := ft.AbsFuncDwarfSym(s)
692 slot, found := ft.symtab[absfn]
693 if !found || !ft.svec[slot].defseen {
694 ft.ctxt.GenAbstractFunc(s)
695 }
696 }
697
698
699 for _, s := range fns {
700 absfn := ft.AbsFuncDwarfSym(s)
701 slot, found := ft.symtab[absfn]
702 if !found {
703 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
704 } else {
705 ft.processFixups(slot, s)
706 }
707 }
708 }
709
View as plain text