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 "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 fileIndex := 1
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 newFileIndex, newLine := ctxt.getFileIndexAndLine(p.Pos)
62 newFileIndex++
63
64
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
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) Size(s dwarf.Sym) int64 {
211 return s.(*LSym).Size
212 }
213 func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
214 ls := s.(*LSym)
215 ls.WriteInt(c.Link, ls.Size, size, i)
216 }
217 func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
218 c.AddInt(s, 2, int64(i))
219 }
220 func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
221 b := []byte{byte(i)}
222 c.AddBytes(s, b)
223 }
224 func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
225 ls := s.(*LSym)
226 ls.WriteBytes(c.Link, ls.Size, b)
227 }
228 func (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 }
233 func (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 }
243 func (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 }
248 func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
249 panic("should be used only in the linker")
250 }
251 func (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
264 func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
265 ls := s.(*LSym)
266 return ls.Size
267 }
268
269
270
271
272
273
274 func (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
281 func (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
286 func (c dwCtxt) Logf(format string, args ...interface{}) {
287 c.Link.Logf(format, args...)
288 }
289
290 func isDwarf64(ctxt *Link) bool {
291 return ctxt.Headtype == objabi.Haix
292 }
293
294 func (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
322
323 func 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
331
332
333 func (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
381 ctxt.generateDebugLinesSymbol(s, lines)
382 }
383
384
385
386 func (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
399
400 func (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
415 func (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
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 type DwarfFixupTable struct {
474 ctxt *Link
475 mu sync.Mutex
476 symtab map[*LSym]int
477 svec []symFixups
478 precursor map[*LSym]fnState
479 }
480
481 type symFixups struct {
482 fixups []relFixup
483 doffsets []declOffset
484 inlIndex int32
485 defseen bool
486 }
487
488 type declOffset struct {
489
490 dclIdx int32
491
492 offset int32
493 }
494
495 type relFixup struct {
496 refsym *LSym
497 relidx int32
498 dclidx int32
499 }
500
501 type fnState struct {
502
503 precursor Func
504
505 absfn *LSym
506 }
507
508 func 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
516 func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) Func {
517 if fnstate, found := ft.precursor[s]; found {
518 return fnstate.precursor
519 }
520 return nil
521 }
522
523 func (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
529
530
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
537
538
539
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
548
549 func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
550
551 ft.mu.Lock()
552 defer ft.mu.Unlock()
553
554
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
563
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
584
585
586
587
588 func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
589
590 if len(vars) != len(coffsets) {
591 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
592 return
593 }
594
595
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
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
618 func (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
636
637 func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
638
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
650
651
652
653
654
655 func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
656 if trace {
657 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
658 }
659
660
661
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
671 if ft.ctxt.InParallel {
672 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
673 }
674
675
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
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
696 type BySymName []*LSym
697
698 func (s BySymName) Len() int { return len(s) }
699 func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
700 func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
701
View as plain text