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 isDwarf64(ctxt *Link) bool {
292 return ctxt.Headtype == objabi.Haix
293 }
294
295 func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
296 if !s.Type.IsText() {
297 ctxt.Diag("dwarfSym of non-TEXT %v", s)
298 }
299 fn := s.Func()
300 if fn.dwarfInfoSym == nil {
301 fn.dwarfInfoSym = &LSym{
302 Type: objabi.SDWARFFCN,
303 }
304 if ctxt.Flag_locationlists {
305 fn.dwarfLocSym = &LSym{
306 Type: objabi.SDWARFLOC,
307 }
308 }
309 fn.dwarfRangesSym = &LSym{
310 Type: objabi.SDWARFRANGE,
311 }
312 fn.dwarfDebugLinesSym = &LSym{
313 Type: objabi.SDWARFLINES,
314 }
315 if s.WasInlined() {
316 fn.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
317 }
318 }
319 return fn.dwarfInfoSym, fn.dwarfLocSym, fn.dwarfRangesSym, fn.dwarfAbsFnSym, fn.dwarfDebugLinesSym
320 }
321
322
323
324 func textPos(fn *LSym) src.XPos {
325 if p := fn.Func().Text; p != nil {
326 return p.Pos
327 }
328 return src.NoXPos
329 }
330
331
332
333
334 func (ctxt *Link) populateDWARF(curfn Func, s *LSym) {
335 myimportpath := ctxt.Pkgpath
336 if myimportpath == "" {
337 return
338 }
339
340 info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
341 if info.Size != 0 {
342 ctxt.Diag("makeFuncDebugEntry double process %v", s)
343 }
344 var scopes []dwarf.Scope
345 var inlcalls dwarf.InlCalls
346 if ctxt.DebugInfo != nil {
347 scopes, inlcalls = ctxt.DebugInfo(ctxt, s, info, curfn)
348 }
349 var err error
350 dwctxt := dwCtxt{ctxt}
351 startPos := ctxt.InnermostPos(textPos(s))
352 if !startPos.IsKnown() || startPos.RelLine() != uint(s.Func().StartLine) {
353 panic("bad startPos")
354 }
355 fnstate := &dwarf.FnState{
356 Name: s.Name,
357 Info: info,
358 Loc: loc,
359 Ranges: ranges,
360 Absfn: absfunc,
361 StartPC: s,
362 Size: s.Size,
363 StartPos: startPos,
364 External: !s.Static(),
365 Scopes: scopes,
366 InlCalls: inlcalls,
367 UseBASEntries: ctxt.UseBASEntries,
368 }
369 if absfunc != nil {
370 err = dwarf.PutAbstractFunc(dwctxt, fnstate)
371 if err != nil {
372 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
373 }
374 err = dwarf.PutConcreteFunc(dwctxt, fnstate, s.Wrapper())
375 } else {
376 err = dwarf.PutDefaultFunc(dwctxt, fnstate, s.Wrapper())
377 }
378 if err != nil {
379 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
380 }
381
382 ctxt.generateDebugLinesSymbol(s, lines)
383 }
384
385
386
387 func (ctxt *Link) DwarfIntConst(name, typename string, val int64) {
388 myimportpath := ctxt.Pkgpath
389 if myimportpath == "" {
390 return
391 }
392 s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
393 s.Type = objabi.SDWARFCONST
394 ctxt.Data = append(ctxt.Data, s)
395 })
396 dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
397 }
398
399
400
401 func (ctxt *Link) DwarfGlobal(typename string, varSym *LSym) {
402 myimportpath := ctxt.Pkgpath
403 if myimportpath == "" || varSym.Local() {
404 return
405 }
406 varname := varSym.Name
407 dieSym := &LSym{
408 Type: objabi.SDWARFVAR,
409 }
410 varSym.NewVarInfo().dwarfInfoSym = dieSym
411 ctxt.Data = append(ctxt.Data, dieSym)
412 typeSym := ctxt.Lookup(dwarf.InfoPrefix + typename)
413 dwarf.PutGlobal(dwCtxt{ctxt}, dieSym, typeSym, varSym, varname)
414 }
415
416 func (ctxt *Link) DwarfAbstractFunc(curfn Func, s *LSym) {
417 absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
418 if absfn.Size != 0 {
419 ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
420 }
421 if s.Func() == nil {
422 s.NewFuncInfo()
423 }
424 scopes, _ := ctxt.DebugInfo(ctxt, s, absfn, curfn)
425 dwctxt := dwCtxt{ctxt}
426 fnstate := dwarf.FnState{
427 Name: s.Name,
428 Info: absfn,
429 Absfn: absfn,
430 StartPos: ctxt.InnermostPos(curfn.Pos()),
431 External: !s.Static(),
432 Scopes: scopes,
433 UseBASEntries: ctxt.UseBASEntries,
434 }
435 if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
436 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
437 }
438 }
439
440
441
442
443
444
445
446
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 type DwarfFixupTable struct {
475 ctxt *Link
476 mu sync.Mutex
477 symtab map[*LSym]int
478 svec []symFixups
479 precursor map[*LSym]fnState
480 }
481
482 type symFixups struct {
483 fixups []relFixup
484 doffsets []declOffset
485 inlIndex int32
486 defseen bool
487 }
488
489 type declOffset struct {
490
491 dclIdx int32
492
493 offset int32
494 }
495
496 type relFixup struct {
497 refsym *LSym
498 relidx int32
499 dclidx int32
500 }
501
502 type fnState struct {
503
504 precursor Func
505
506 absfn *LSym
507 }
508
509 func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
510 return &DwarfFixupTable{
511 ctxt: ctxt,
512 symtab: make(map[*LSym]int),
513 precursor: make(map[*LSym]fnState),
514 }
515 }
516
517 func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) Func {
518 if fnstate, found := ft.precursor[s]; found {
519 return fnstate.precursor
520 }
521 return nil
522 }
523
524 func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn Func) {
525 if _, found := ft.precursor[s]; found {
526 ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
527 }
528
529
530
531
532 absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
533 absfn.Set(AttrDuplicateOK, true)
534 absfn.Type = objabi.SDWARFABSFCN
535 ft.ctxt.Data = append(ft.ctxt.Data, absfn)
536
537
538
539
540
541 if fn := s.Func(); fn != nil && fn.dwarfAbsFnSym == nil {
542 fn.dwarfAbsFnSym = absfn
543 }
544
545 ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
546 }
547
548
549
550 func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
551
552 ft.mu.Lock()
553 defer ft.mu.Unlock()
554
555
556 idx, found := ft.symtab[tgt]
557 if !found {
558 ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
559 idx = len(ft.svec) - 1
560 ft.symtab[tgt] = idx
561 }
562
563
564
565 sf := &ft.svec[idx]
566 if len(sf.doffsets) > 0 {
567 found := false
568 for _, do := range sf.doffsets {
569 if do.dclIdx == int32(dclidx) {
570 off := do.offset
571 s.R[ridx].Add += int64(off)
572 found = true
573 break
574 }
575 }
576 if !found {
577 ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
578 }
579 } else {
580 sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
581 }
582 }
583
584
585
586
587
588
589 func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
590
591 if len(vars) != len(coffsets) {
592 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
593 return
594 }
595
596
597 doffsets := make([]declOffset, len(coffsets))
598 for i := range coffsets {
599 doffsets[i].dclIdx = vars[i].ChildIndex
600 doffsets[i].offset = coffsets[i]
601 }
602
603 ft.mu.Lock()
604 defer ft.mu.Unlock()
605
606
607 idx, found := ft.symtab[s]
608 if !found {
609 sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
610 ft.svec = append(ft.svec, sf)
611 ft.symtab[s] = len(ft.svec) - 1
612 } else {
613 sf := &ft.svec[idx]
614 sf.doffsets = doffsets
615 sf.defseen = true
616 }
617 }
618
619 func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
620 sf := &ft.svec[slot]
621 for _, f := range sf.fixups {
622 dfound := false
623 for _, doffset := range sf.doffsets {
624 if doffset.dclIdx == f.dclidx {
625 f.refsym.R[f.relidx].Add += int64(doffset.offset)
626 dfound = true
627 break
628 }
629 }
630 if !dfound {
631 ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
632 }
633 }
634 }
635
636
637
638 func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
639
640 ft.mu.Lock()
641 defer ft.mu.Unlock()
642
643 if fnstate, found := ft.precursor[fnsym]; found {
644 return fnstate.absfn
645 }
646 ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
647 return nil
648 }
649
650
651
652
653
654
655
656 func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
657 if trace {
658 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
659 }
660
661
662
663 fns := make([]*LSym, len(ft.precursor))
664 idx := 0
665 for fn := range ft.precursor {
666 fns[idx] = fn
667 idx++
668 }
669 slices.SortFunc(fns, func(a, b *LSym) int {
670 return strings.Compare(a.Name, b.Name)
671 })
672
673
674 if ft.ctxt.InParallel {
675 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
676 }
677
678
679 for _, s := range fns {
680 absfn := ft.AbsFuncDwarfSym(s)
681 slot, found := ft.symtab[absfn]
682 if !found || !ft.svec[slot].defseen {
683 ft.ctxt.GenAbstractFunc(s)
684 }
685 }
686
687
688 for _, s := range fns {
689 absfn := ft.AbsFuncDwarfSym(s)
690 slot, found := ft.symtab[absfn]
691 if !found {
692 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
693 } else {
694 ft.processFixups(slot, s)
695 }
696 }
697 }
698
View as plain text