1
2
3
4
5 package dwarfgen
6
7 import (
8 "bytes"
9 "flag"
10 "fmt"
11 "internal/buildcfg"
12 "slices"
13 "sort"
14 "strings"
15
16 "cmd/compile/internal/base"
17 "cmd/compile/internal/ir"
18 "cmd/compile/internal/reflectdata"
19 "cmd/compile/internal/ssa"
20 "cmd/compile/internal/ssagen"
21 "cmd/compile/internal/typecheck"
22 "cmd/compile/internal/types"
23 "cmd/internal/dwarf"
24 "cmd/internal/obj"
25 "cmd/internal/objabi"
26 "cmd/internal/src"
27 )
28
29 func Info(ctxt *obj.Link, fnsym *obj.LSym, infosym *obj.LSym, curfn obj.Func) (scopes []dwarf.Scope, inlcalls dwarf.InlCalls) {
30 fn := curfn.(*ir.Func)
31
32 if fn.Nname != nil {
33 expect := fn.Linksym()
34 if fnsym.ABI() == obj.ABI0 {
35 expect = fn.LinksymABI(obj.ABI0)
36 }
37 if fnsym != expect {
38 base.Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
39 }
40 }
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 isODCLFUNC := infosym.Name == ""
75
76 var apdecls []*ir.Name
77
78 if isODCLFUNC {
79 for _, n := range fn.Dcl {
80 if n.Op() != ir.ONAME {
81 continue
82 }
83 switch n.Class {
84 case ir.PAUTO:
85 if !n.Used() {
86
87 if fnsym.Func().Text != nil {
88 base.Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
89 }
90 continue
91 }
92 case ir.PPARAM, ir.PPARAMOUT:
93 default:
94 continue
95 }
96 if !ssa.IsVarWantedForDebug(n) {
97 continue
98 }
99 apdecls = append(apdecls, n)
100 if n.Type().Kind() == types.TSSA {
101
102
103 continue
104 }
105 fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
106 }
107 }
108
109 var closureVars map[*ir.Name]int64
110 if fn.Needctxt() {
111 closureVars = make(map[*ir.Name]int64)
112 csiter := typecheck.NewClosureStructIter(fn.ClosureVars)
113 for {
114 n, _, offset := csiter.Next()
115 if n == nil {
116 break
117 }
118 closureVars[n] = offset
119 if n.Heapaddr != nil {
120 closureVars[n.Heapaddr] = offset
121 }
122 }
123 }
124
125 decls, dwarfVars := createDwarfVars(fnsym, isODCLFUNC, fn, apdecls, closureVars)
126
127
128
129
130
131
132
133
134
135 typesyms := []*obj.LSym{}
136 for t := range fnsym.Func().Autot {
137 typesyms = append(typesyms, t)
138 }
139 for i := range fnsym.R {
140 if fnsym.R[i].Type == objabi.R_USEIFACE && !strings.HasPrefix(fnsym.R[i].Sym.Name, "go:itab.") {
141
142 typesyms = append(typesyms, fnsym.R[i].Sym)
143 }
144 }
145 slices.SortFunc(typesyms, func(a, b *obj.LSym) int {
146 return strings.Compare(a.Name, b.Name)
147 })
148 var lastsym *obj.LSym
149 for _, sym := range typesyms {
150 if sym == lastsym {
151 continue
152 }
153 lastsym = sym
154 infosym.AddRel(ctxt, obj.Reloc{Type: objabi.R_USETYPE, Sym: sym})
155 }
156 fnsym.Func().Autot = nil
157
158 var varScopes []ir.ScopeID
159 for _, decl := range decls {
160 pos := declPos(decl)
161 varScopes = append(varScopes, findScope(fn.Marks, pos))
162 }
163
164 scopes = assembleScopes(fnsym, fn, dwarfVars, varScopes)
165 if base.Flag.GenDwarfInl > 0 {
166 inlcalls = assembleInlines(fnsym, dwarfVars)
167 }
168 return scopes, inlcalls
169 }
170
171 func declPos(decl *ir.Name) src.XPos {
172 return decl.Canonical().Pos()
173 }
174
175
176
177 func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var) {
178
179 var vars []*dwarf.Var
180 var decls []*ir.Name
181 var selected ir.NameSet
182
183 if base.Ctxt.Flag_locationlists && base.Ctxt.Flag_optimize && fn.DebugInfo != nil && complexOK {
184 decls, vars, selected = createComplexVars(fnsym, fn, closureVars)
185 } else if fn.ABI == obj.ABIInternal && base.Flag.N != 0 && complexOK {
186 decls, vars, selected = createABIVars(fnsym, fn, apDecls, closureVars)
187 } else {
188 decls, vars, selected = createSimpleVars(fnsym, apDecls, closureVars)
189 }
190 if fn.DebugInfo != nil {
191
192 for _, n := range fn.DebugInfo.(*ssa.FuncDebug).OptDcl {
193 if n.Class != ir.PAUTO {
194 continue
195 }
196 types.CalcSize(n.Type())
197 if n.Type().Size() == 0 {
198 decls = append(decls, n)
199 vars = append(vars, createSimpleVar(fnsym, n, closureVars))
200 vars[len(vars)-1].StackOffset = 0
201 fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
202 }
203 }
204 }
205
206 dcl := apDecls
207 if fnsym.WasInlined() {
208 dcl = preInliningDcls(fnsym)
209 } else {
210
211
212
213
214
215 debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
216 for _, n := range debugInfo.RegOutputParams {
217 if !ssa.IsVarWantedForDebug(n) {
218 continue
219 }
220 if n.Class != ir.PPARAMOUT || !n.IsOutputParamInRegisters() {
221 base.Fatalf("invalid ir.Name on debugInfo.RegOutputParams list")
222 }
223 dcl = append(dcl, n)
224 }
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239 for _, n := range dcl {
240 if selected.Has(n) {
241 continue
242 }
243 c := n.Sym().Name[0]
244 if c == '.' || n.Type().IsUntyped() {
245 continue
246 }
247 if n.Class == ir.PPARAM && !ssa.CanSSA(n.Type()) {
248
249
250
251
252
253
254
255 vars = append(vars, createSimpleVar(fnsym, n, closureVars))
256 decls = append(decls, n)
257 continue
258 }
259 typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
260 decls = append(decls, n)
261 tag := dwarf.DW_TAG_variable
262 isReturnValue := (n.Class == ir.PPARAMOUT)
263 if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
264 tag = dwarf.DW_TAG_formal_parameter
265 }
266 inlIndex := 0
267 if base.Flag.GenDwarfInl > 1 {
268 if n.InlFormal() || n.InlLocal() {
269 inlIndex = posInlIndex(n.Pos()) + 1
270 if n.InlFormal() {
271 tag = dwarf.DW_TAG_formal_parameter
272 }
273 }
274 }
275 declpos := base.Ctxt.InnermostPos(n.Pos())
276 dvar := &dwarf.Var{
277 Name: n.Sym().Name,
278 IsReturnValue: isReturnValue,
279 Tag: tag,
280 WithLoclist: true,
281 StackOffset: int32(n.FrameOffset()),
282 Type: base.Ctxt.Lookup(typename),
283 DeclFile: declpos.RelFilename(),
284 DeclLine: declpos.RelLine(),
285 DeclCol: declpos.RelCol(),
286 InlIndex: int32(inlIndex),
287 ChildIndex: -1,
288 DictIndex: n.DictIndex,
289 ClosureOffset: closureOffset(n, closureVars),
290 }
291 if n.Esc() == ir.EscHeap && n.Heapaddr != nil {
292
293
294
295
296
297
298
299 debug := fn.DebugInfo.(*ssa.FuncDebug)
300 list := createHeapDerefLocationList(n, debug.EntryID)
301 dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
302 debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
303 }
304 }
305 vars = append(vars, dvar)
306
307 fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
308 }
309
310
311 sortDeclsAndVars(fn, decls, vars)
312
313 return decls, vars
314 }
315
316
317
318
319
320
321
322 func sortDeclsAndVars(fn *ir.Func, decls []*ir.Name, vars []*dwarf.Var) {
323 paramOrder := make(map[*ir.Name]int)
324 idx := 1
325 for _, f := range fn.Type().RecvParamsResults() {
326 if n, ok := f.Nname.(*ir.Name); ok {
327 paramOrder[n] = idx
328 idx++
329 }
330 }
331 sort.Stable(varsAndDecls{decls, vars, paramOrder})
332 }
333
334 type varsAndDecls struct {
335 decls []*ir.Name
336 vars []*dwarf.Var
337 paramOrder map[*ir.Name]int
338 }
339
340 func (v varsAndDecls) Len() int {
341 return len(v.decls)
342 }
343
344 func (v varsAndDecls) Less(i, j int) bool {
345 nameLT := func(ni, nj *ir.Name) bool {
346 oi, foundi := v.paramOrder[ni]
347 oj, foundj := v.paramOrder[nj]
348 if foundi {
349 if foundj {
350 return oi < oj
351 } else {
352 return true
353 }
354 }
355 return false
356 }
357 return nameLT(v.decls[i], v.decls[j])
358 }
359
360 func (v varsAndDecls) Swap(i, j int) {
361 v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
362 v.decls[i], v.decls[j] = v.decls[j], v.decls[i]
363 }
364
365
366
367
368
369
370
371 func preInliningDcls(fnsym *obj.LSym) []*ir.Name {
372 fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*ir.Func)
373 var rdcl []*ir.Name
374 for _, n := range fn.Inl.Dcl {
375 c := n.Sym().Name[0]
376
377
378 if n.Sym().Name == "_" || c == '.' || n.Type().IsUntyped() {
379 continue
380 }
381 rdcl = append(rdcl, n)
382 }
383 return rdcl
384 }
385
386
387
388 func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
389 var vars []*dwarf.Var
390 var decls []*ir.Name
391 var selected ir.NameSet
392 for _, n := range apDecls {
393 if ir.IsAutoTmp(n) {
394 continue
395 }
396
397 decls = append(decls, n)
398 vars = append(vars, createSimpleVar(fnsym, n, closureVars))
399 selected.Add(n)
400 }
401 return decls, vars, selected
402 }
403
404 func createSimpleVar(fnsym *obj.LSym, n *ir.Name, closureVars map[*ir.Name]int64) *dwarf.Var {
405 var tag int
406 var offs int64
407
408 localAutoOffset := func() int64 {
409 offs = n.FrameOffset()
410 if base.Ctxt.Arch.FixedFrameSize == 0 {
411 offs -= int64(types.PtrSize)
412 }
413 if buildcfg.FramePointerEnabled {
414 offs -= int64(types.PtrSize)
415 }
416 return offs
417 }
418
419 switch n.Class {
420 case ir.PAUTO:
421 offs = localAutoOffset()
422 tag = dwarf.DW_TAG_variable
423 case ir.PPARAM, ir.PPARAMOUT:
424 tag = dwarf.DW_TAG_formal_parameter
425 if n.IsOutputParamInRegisters() {
426 offs = localAutoOffset()
427 } else {
428 offs = n.FrameOffset() + base.Ctxt.Arch.FixedFrameSize
429 }
430
431 default:
432 base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class, n)
433 }
434
435 typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
436 delete(fnsym.Func().Autot, reflectdata.TypeLinksym(n.Type()))
437 inlIndex := 0
438 if base.Flag.GenDwarfInl > 1 {
439 if n.InlFormal() || n.InlLocal() {
440 inlIndex = posInlIndex(n.Pos()) + 1
441 if n.InlFormal() {
442 tag = dwarf.DW_TAG_formal_parameter
443 }
444 }
445 }
446 declpos := base.Ctxt.InnermostPos(declPos(n))
447 return &dwarf.Var{
448 Name: n.Sym().Name,
449 IsReturnValue: n.Class == ir.PPARAMOUT,
450 IsInlFormal: n.InlFormal(),
451 Tag: tag,
452 StackOffset: int32(offs),
453 Type: base.Ctxt.Lookup(typename),
454 DeclFile: declpos.RelFilename(),
455 DeclLine: declpos.RelLine(),
456 DeclCol: declpos.RelCol(),
457 InlIndex: int32(inlIndex),
458 ChildIndex: -1,
459 DictIndex: n.DictIndex,
460 ClosureOffset: closureOffset(n, closureVars),
461 }
462 }
463
464
465
466
467
468
469 func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
470
471
472
473 decls, vars, selected := createComplexVars(fnsym, fn, closureVars)
474
475
476
477
478 for _, n := range apDecls {
479 if ir.IsAutoTmp(n) {
480 continue
481 }
482 if _, ok := selected[n]; ok {
483
484 continue
485 }
486
487 decls = append(decls, n)
488 vars = append(vars, createSimpleVar(fnsym, n, closureVars))
489 selected.Add(n)
490 }
491
492 return decls, vars, selected
493 }
494
495
496
497 func createComplexVars(fnsym *obj.LSym, fn *ir.Func, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
498 debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
499
500
501 var decls []*ir.Name
502 var vars []*dwarf.Var
503 var ssaVars ir.NameSet
504
505 for varID, dvar := range debugInfo.Vars {
506 n := dvar
507 ssaVars.Add(n)
508 for _, slot := range debugInfo.VarSlots[varID] {
509 ssaVars.Add(debugInfo.Slots[slot].N)
510 }
511
512 if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID), closureVars); dvar != nil {
513 decls = append(decls, n)
514 vars = append(vars, dvar)
515 }
516 }
517
518 return decls, vars, ssaVars
519 }
520
521
522 func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID, closureVars map[*ir.Name]int64) *dwarf.Var {
523 debug := fn.DebugInfo.(*ssa.FuncDebug)
524 n := debug.Vars[varID]
525
526 var tag int
527 switch n.Class {
528 case ir.PAUTO:
529 tag = dwarf.DW_TAG_variable
530 case ir.PPARAM, ir.PPARAMOUT:
531 tag = dwarf.DW_TAG_formal_parameter
532 default:
533 return nil
534 }
535
536 gotype := reflectdata.TypeLinksym(n.Type())
537 delete(fnsym.Func().Autot, gotype)
538 typename := dwarf.InfoPrefix + gotype.Name[len("type:"):]
539 inlIndex := 0
540 if base.Flag.GenDwarfInl > 1 {
541 if n.InlFormal() || n.InlLocal() {
542 inlIndex = posInlIndex(n.Pos()) + 1
543 if n.InlFormal() {
544 tag = dwarf.DW_TAG_formal_parameter
545 }
546 }
547 }
548 declpos := base.Ctxt.InnermostPos(n.Pos())
549 dvar := &dwarf.Var{
550 Name: n.Sym().Name,
551 IsReturnValue: n.Class == ir.PPARAMOUT,
552 IsInlFormal: n.InlFormal(),
553 Tag: tag,
554 WithLoclist: true,
555 Type: base.Ctxt.Lookup(typename),
556
557
558
559
560 StackOffset: ssagen.StackOffset(debug.Slots[debug.VarSlots[varID][0]]),
561 DeclFile: declpos.RelFilename(),
562 DeclLine: declpos.RelLine(),
563 DeclCol: declpos.RelCol(),
564 InlIndex: int32(inlIndex),
565 ChildIndex: -1,
566 DictIndex: n.DictIndex,
567 ClosureOffset: closureOffset(n, closureVars),
568 }
569 list := debug.LocationLists[varID]
570 if len(list) != 0 {
571 dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
572 debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
573 }
574 }
575 return dvar
576 }
577
578
579
580 func createHeapDerefLocationList(n *ir.Name, entryID ssa.ID) []byte {
581
582 heapPtrOffset := n.Heapaddr.FrameOffset()
583 if base.Ctxt.Arch.FixedFrameSize == 0 {
584 heapPtrOffset -= int64(types.PtrSize)
585 }
586 if buildcfg.FramePointerEnabled {
587 heapPtrOffset -= int64(types.PtrSize)
588 }
589
590
591 var locExpr []byte
592 var sizeIdx int
593 locExpr, sizeIdx = ssa.SetupLocList(base.Ctxt, entryID, locExpr, ssa.BlockStart.ID, ssa.FuncEnd.ID)
594 locExpr = append(locExpr, dwarf.DW_OP_fbreg)
595 locExpr = dwarf.AppendSleb128(locExpr, heapPtrOffset)
596 locExpr = append(locExpr, dwarf.DW_OP_deref)
597 base.Ctxt.Arch.ByteOrder.PutUint16(locExpr[sizeIdx:], uint16(len(locExpr)-sizeIdx-2))
598 return locExpr
599 }
600
601
602
603 func RecordFlags(flags ...string) {
604 if base.Ctxt.Pkgpath == "" {
605 base.Fatalf("missing pkgpath")
606 }
607
608 type BoolFlag interface {
609 IsBoolFlag() bool
610 }
611 type CountFlag interface {
612 IsCountFlag() bool
613 }
614 var cmd bytes.Buffer
615 for _, name := range flags {
616 f := flag.Lookup(name)
617 if f == nil {
618 continue
619 }
620 getter := f.Value.(flag.Getter)
621 if getter.String() == f.DefValue {
622
623 continue
624 }
625 if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
626 val, ok := getter.Get().(bool)
627 if ok && val {
628 fmt.Fprintf(&cmd, " -%s", f.Name)
629 continue
630 }
631 }
632 if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
633 val, ok := getter.Get().(int)
634 if ok && val == 1 {
635 fmt.Fprintf(&cmd, " -%s", f.Name)
636 continue
637 }
638 }
639 fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
640 }
641
642
643
644
645
646 if buildcfg.Experiment.RegabiArgs {
647 cmd.Write([]byte(" regabi"))
648 }
649
650 if cmd.Len() == 0 {
651 return
652 }
653 s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + base.Ctxt.Pkgpath)
654 s.Type = objabi.SDWARFCUINFO
655
656
657 s.Set(obj.AttrDuplicateOK, true)
658 base.Ctxt.Data = append(base.Ctxt.Data, s)
659 s.P = cmd.Bytes()[1:]
660 }
661
662
663
664 func RecordPackageName() {
665 s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + base.Ctxt.Pkgpath)
666 s.Type = objabi.SDWARFCUINFO
667
668
669 s.Set(obj.AttrDuplicateOK, true)
670 base.Ctxt.Data = append(base.Ctxt.Data, s)
671 s.P = []byte(types.LocalPkg.Name)
672 }
673
674 func closureOffset(n *ir.Name, closureVars map[*ir.Name]int64) int64 {
675 return closureVars[n]
676 }
677
View as plain text