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 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 := linkgetlineFromPos(ctxt, 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, _ := linkgetlineFromPos(ctxt, 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 scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
357 }
358 var err error
359 dwctxt := dwCtxt{ctxt}
360 filesym := ctxt.fileSymbol(s)
361 fnstate := &dwarf.FnState{
362 Name: s.Name,
363 Importpath: myimportpath,
364 Info: info,
365 Filesym: filesym,
366 Loc: loc,
367 Ranges: ranges,
368 Absfn: absfunc,
369 StartPC: s,
370 Size: s.Size,
371 External: !s.Static(),
372 Scopes: scopes,
373 InlCalls: inlcalls,
374 UseBASEntries: ctxt.UseBASEntries,
375 }
376 if absfunc != nil {
377 err = dwarf.PutAbstractFunc(dwctxt, fnstate)
378 if err != nil {
379 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
380 }
381 err = dwarf.PutConcreteFunc(dwctxt, fnstate, s.Wrapper())
382 } else {
383 err = dwarf.PutDefaultFunc(dwctxt, fnstate, s.Wrapper())
384 }
385 if err != nil {
386 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
387 }
388
389 ctxt.generateDebugLinesSymbol(s, lines)
390 }
391
392
393
394 func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
395 if myimportpath == "" {
396 return
397 }
398 s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
399 s.Type = objabi.SDWARFCONST
400 ctxt.Data = append(ctxt.Data, s)
401 })
402 dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
403 }
404
405
406
407 func (ctxt *Link) DwarfGlobal(myimportpath, typename string, varSym *LSym) {
408 if myimportpath == "" || varSym.Local() {
409 return
410 }
411 var varname string
412 if varSym.Pkg == "_" {
413
414
415 varname = varSym.Name
416 } else {
417
418 varname = objabi.PathToPrefix(myimportpath) + varSym.Name[len(`""`):]
419 }
420 dieSymName := dwarf.InfoPrefix + varname
421 dieSym := ctxt.LookupInit(dieSymName, func(s *LSym) {
422 s.Type = objabi.SDWARFVAR
423 s.Set(AttrDuplicateOK, true)
424 ctxt.Data = append(ctxt.Data, s)
425 })
426 typeSym := ctxt.Lookup(dwarf.InfoPrefix + typename)
427 dwarf.PutGlobal(dwCtxt{ctxt}, dieSym, typeSym, varSym, varname)
428 }
429
430 func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
431 absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
432 if absfn.Size != 0 {
433 ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
434 }
435 if s.Func() == nil {
436 s.NewFuncInfo()
437 }
438 scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
439 dwctxt := dwCtxt{ctxt}
440 filesym := ctxt.fileSymbol(s)
441 fnstate := dwarf.FnState{
442 Name: s.Name,
443 Importpath: myimportpath,
444 Info: absfn,
445 Filesym: filesym,
446 Absfn: absfn,
447 External: !s.Static(),
448 Scopes: scopes,
449 UseBASEntries: ctxt.UseBASEntries,
450 }
451 if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
452 ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
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
486
487
488
489
490 type DwarfFixupTable struct {
491 ctxt *Link
492 mu sync.Mutex
493 symtab map[*LSym]int
494 svec []symFixups
495 precursor map[*LSym]fnState
496 }
497
498 type symFixups struct {
499 fixups []relFixup
500 doffsets []declOffset
501 inlIndex int32
502 defseen bool
503 }
504
505 type declOffset struct {
506
507 dclIdx int32
508
509 offset int32
510 }
511
512 type relFixup struct {
513 refsym *LSym
514 relidx int32
515 dclidx int32
516 }
517
518 type fnState struct {
519
520 precursor interface{}
521
522 absfn *LSym
523 }
524
525 func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
526 return &DwarfFixupTable{
527 ctxt: ctxt,
528 symtab: make(map[*LSym]int),
529 precursor: make(map[*LSym]fnState),
530 }
531 }
532
533 func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
534 if fnstate, found := ft.precursor[s]; found {
535 return fnstate.precursor
536 }
537 return nil
538 }
539
540 func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
541 if _, found := ft.precursor[s]; found {
542 ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
543 }
544
545
546
547
548 absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
549 absfn.Set(AttrDuplicateOK, true)
550 absfn.Type = objabi.SDWARFABSFCN
551 ft.ctxt.Data = append(ft.ctxt.Data, absfn)
552
553
554
555
556
557 if fn := s.Func(); fn != nil && fn.dwarfAbsFnSym == nil {
558 fn.dwarfAbsFnSym = absfn
559 }
560
561 ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
562 }
563
564
565
566 func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
567
568 ft.mu.Lock()
569 defer ft.mu.Unlock()
570
571
572 idx, found := ft.symtab[tgt]
573 if !found {
574 ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
575 idx = len(ft.svec) - 1
576 ft.symtab[tgt] = idx
577 }
578
579
580
581 sf := &ft.svec[idx]
582 if len(sf.doffsets) > 0 {
583 found := false
584 for _, do := range sf.doffsets {
585 if do.dclIdx == int32(dclidx) {
586 off := do.offset
587 s.R[ridx].Add += int64(off)
588 found = true
589 break
590 }
591 }
592 if !found {
593 ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
594 }
595 } else {
596 sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
597 }
598 }
599
600
601
602
603
604
605 func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
606
607 if len(vars) != len(coffsets) {
608 ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
609 return
610 }
611
612
613 doffsets := make([]declOffset, len(coffsets))
614 for i := range coffsets {
615 doffsets[i].dclIdx = vars[i].ChildIndex
616 doffsets[i].offset = coffsets[i]
617 }
618
619 ft.mu.Lock()
620 defer ft.mu.Unlock()
621
622
623 idx, found := ft.symtab[s]
624 if !found {
625 sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
626 ft.svec = append(ft.svec, sf)
627 ft.symtab[s] = len(ft.svec) - 1
628 } else {
629 sf := &ft.svec[idx]
630 sf.doffsets = doffsets
631 sf.defseen = true
632 }
633 }
634
635 func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
636 sf := &ft.svec[slot]
637 for _, f := range sf.fixups {
638 dfound := false
639 for _, doffset := range sf.doffsets {
640 if doffset.dclIdx == f.dclidx {
641 f.refsym.R[f.relidx].Add += int64(doffset.offset)
642 dfound = true
643 break
644 }
645 }
646 if !dfound {
647 ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
648 }
649 }
650 }
651
652
653
654 func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
655
656 ft.mu.Lock()
657 defer ft.mu.Unlock()
658
659 if fnstate, found := ft.precursor[fnsym]; found {
660 return fnstate.absfn
661 }
662 ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
663 return nil
664 }
665
666
667
668
669
670
671
672 func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
673 if trace {
674 ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
675 }
676
677
678
679 fns := make([]*LSym, len(ft.precursor))
680 idx := 0
681 for fn := range ft.precursor {
682 fns[idx] = fn
683 idx++
684 }
685 sort.Sort(BySymName(fns))
686
687
688 if ft.ctxt.InParallel {
689 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
690 }
691
692
693 for _, s := range fns {
694 absfn := ft.AbsFuncDwarfSym(s)
695 slot, found := ft.symtab[absfn]
696 if !found || !ft.svec[slot].defseen {
697 ft.ctxt.GenAbstractFunc(s)
698 }
699 }
700
701
702 for _, s := range fns {
703 absfn := ft.AbsFuncDwarfSym(s)
704 slot, found := ft.symtab[absfn]
705 if !found {
706 ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
707 } else {
708 ft.processFixups(slot, s)
709 }
710 }
711 }
712
713 type BySymName []*LSym
714
715 func (s BySymName) Len() int { return len(s) }
716 func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
717 func (s BySymName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
718
View as plain text