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 {
292 if n.Heapaddr == nil {
293 base.Fatalf("invalid heap allocated var without Heapaddr")
294 }
295 debug := fn.DebugInfo.(*ssa.FuncDebug)
296 list := createHeapDerefLocationList(n, debug.EntryID)
297 dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
298 debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
299 }
300 }
301 vars = append(vars, dvar)
302
303 fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
304 }
305
306
307 sortDeclsAndVars(fn, decls, vars)
308
309 return decls, vars
310 }
311
312
313
314
315
316
317
318 func sortDeclsAndVars(fn *ir.Func, decls []*ir.Name, vars []*dwarf.Var) {
319 paramOrder := make(map[*ir.Name]int)
320 idx := 1
321 for _, f := range fn.Type().RecvParamsResults() {
322 if n, ok := f.Nname.(*ir.Name); ok {
323 paramOrder[n] = idx
324 idx++
325 }
326 }
327 sort.Stable(varsAndDecls{decls, vars, paramOrder})
328 }
329
330 type varsAndDecls struct {
331 decls []*ir.Name
332 vars []*dwarf.Var
333 paramOrder map[*ir.Name]int
334 }
335
336 func (v varsAndDecls) Len() int {
337 return len(v.decls)
338 }
339
340 func (v varsAndDecls) Less(i, j int) bool {
341 nameLT := func(ni, nj *ir.Name) bool {
342 oi, foundi := v.paramOrder[ni]
343 oj, foundj := v.paramOrder[nj]
344 if foundi {
345 if foundj {
346 return oi < oj
347 } else {
348 return true
349 }
350 }
351 return false
352 }
353 return nameLT(v.decls[i], v.decls[j])
354 }
355
356 func (v varsAndDecls) Swap(i, j int) {
357 v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
358 v.decls[i], v.decls[j] = v.decls[j], v.decls[i]
359 }
360
361
362
363
364
365
366
367 func preInliningDcls(fnsym *obj.LSym) []*ir.Name {
368 fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*ir.Func)
369 var rdcl []*ir.Name
370 for _, n := range fn.Inl.Dcl {
371 c := n.Sym().Name[0]
372
373
374 if n.Sym().Name == "_" || c == '.' || n.Type().IsUntyped() {
375 continue
376 }
377 rdcl = append(rdcl, n)
378 }
379 return rdcl
380 }
381
382
383
384 func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
385 var vars []*dwarf.Var
386 var decls []*ir.Name
387 var selected ir.NameSet
388 for _, n := range apDecls {
389 if ir.IsAutoTmp(n) {
390 continue
391 }
392
393 decls = append(decls, n)
394 vars = append(vars, createSimpleVar(fnsym, n, closureVars))
395 selected.Add(n)
396 }
397 return decls, vars, selected
398 }
399
400 func createSimpleVar(fnsym *obj.LSym, n *ir.Name, closureVars map[*ir.Name]int64) *dwarf.Var {
401 var tag int
402 var offs int64
403
404 localAutoOffset := func() int64 {
405 offs = n.FrameOffset()
406 if base.Ctxt.Arch.FixedFrameSize == 0 {
407 offs -= int64(types.PtrSize)
408 }
409 if buildcfg.FramePointerEnabled {
410 offs -= int64(types.PtrSize)
411 }
412 return offs
413 }
414
415 switch n.Class {
416 case ir.PAUTO:
417 offs = localAutoOffset()
418 tag = dwarf.DW_TAG_variable
419 case ir.PPARAM, ir.PPARAMOUT:
420 tag = dwarf.DW_TAG_formal_parameter
421 if n.IsOutputParamInRegisters() {
422 offs = localAutoOffset()
423 } else {
424 offs = n.FrameOffset() + base.Ctxt.Arch.FixedFrameSize
425 }
426
427 default:
428 base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class, n)
429 }
430
431 typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
432 delete(fnsym.Func().Autot, reflectdata.TypeLinksym(n.Type()))
433 inlIndex := 0
434 if base.Flag.GenDwarfInl > 1 {
435 if n.InlFormal() || n.InlLocal() {
436 inlIndex = posInlIndex(n.Pos()) + 1
437 if n.InlFormal() {
438 tag = dwarf.DW_TAG_formal_parameter
439 }
440 }
441 }
442 declpos := base.Ctxt.InnermostPos(declPos(n))
443 return &dwarf.Var{
444 Name: n.Sym().Name,
445 IsReturnValue: n.Class == ir.PPARAMOUT,
446 IsInlFormal: n.InlFormal(),
447 Tag: tag,
448 StackOffset: int32(offs),
449 Type: base.Ctxt.Lookup(typename),
450 DeclFile: declpos.RelFilename(),
451 DeclLine: declpos.RelLine(),
452 DeclCol: declpos.RelCol(),
453 InlIndex: int32(inlIndex),
454 ChildIndex: -1,
455 DictIndex: n.DictIndex,
456 ClosureOffset: closureOffset(n, closureVars),
457 }
458 }
459
460
461
462
463
464
465 func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
466
467
468
469 decls, vars, selected := createComplexVars(fnsym, fn, closureVars)
470
471
472
473
474 for _, n := range apDecls {
475 if ir.IsAutoTmp(n) {
476 continue
477 }
478 if _, ok := selected[n]; ok {
479
480 continue
481 }
482
483 decls = append(decls, n)
484 vars = append(vars, createSimpleVar(fnsym, n, closureVars))
485 selected.Add(n)
486 }
487
488 return decls, vars, selected
489 }
490
491
492
493 func createComplexVars(fnsym *obj.LSym, fn *ir.Func, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
494 debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
495
496
497 var decls []*ir.Name
498 var vars []*dwarf.Var
499 var ssaVars ir.NameSet
500
501 for varID, dvar := range debugInfo.Vars {
502 n := dvar
503 ssaVars.Add(n)
504 for _, slot := range debugInfo.VarSlots[varID] {
505 ssaVars.Add(debugInfo.Slots[slot].N)
506 }
507
508 if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID), closureVars); dvar != nil {
509 decls = append(decls, n)
510 vars = append(vars, dvar)
511 }
512 }
513
514 return decls, vars, ssaVars
515 }
516
517
518 func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID, closureVars map[*ir.Name]int64) *dwarf.Var {
519 debug := fn.DebugInfo.(*ssa.FuncDebug)
520 n := debug.Vars[varID]
521
522 var tag int
523 switch n.Class {
524 case ir.PAUTO:
525 tag = dwarf.DW_TAG_variable
526 case ir.PPARAM, ir.PPARAMOUT:
527 tag = dwarf.DW_TAG_formal_parameter
528 default:
529 return nil
530 }
531
532 gotype := reflectdata.TypeLinksym(n.Type())
533 delete(fnsym.Func().Autot, gotype)
534 typename := dwarf.InfoPrefix + gotype.Name[len("type:"):]
535 inlIndex := 0
536 if base.Flag.GenDwarfInl > 1 {
537 if n.InlFormal() || n.InlLocal() {
538 inlIndex = posInlIndex(n.Pos()) + 1
539 if n.InlFormal() {
540 tag = dwarf.DW_TAG_formal_parameter
541 }
542 }
543 }
544 declpos := base.Ctxt.InnermostPos(n.Pos())
545 dvar := &dwarf.Var{
546 Name: n.Sym().Name,
547 IsReturnValue: n.Class == ir.PPARAMOUT,
548 IsInlFormal: n.InlFormal(),
549 Tag: tag,
550 WithLoclist: true,
551 Type: base.Ctxt.Lookup(typename),
552
553
554
555
556 StackOffset: ssagen.StackOffset(debug.Slots[debug.VarSlots[varID][0]]),
557 DeclFile: declpos.RelFilename(),
558 DeclLine: declpos.RelLine(),
559 DeclCol: declpos.RelCol(),
560 InlIndex: int32(inlIndex),
561 ChildIndex: -1,
562 DictIndex: n.DictIndex,
563 ClosureOffset: closureOffset(n, closureVars),
564 }
565 list := debug.LocationLists[varID]
566 if len(list) != 0 {
567 dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
568 debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
569 }
570 }
571 return dvar
572 }
573
574
575
576 func createHeapDerefLocationList(n *ir.Name, entryID ssa.ID) []byte {
577
578 heapPtrOffset := n.Heapaddr.FrameOffset()
579 if base.Ctxt.Arch.FixedFrameSize == 0 {
580 heapPtrOffset -= int64(types.PtrSize)
581 }
582 if buildcfg.FramePointerEnabled {
583 heapPtrOffset -= int64(types.PtrSize)
584 }
585
586
587 var locExpr []byte
588 var sizeIdx int
589 locExpr, sizeIdx = ssa.SetupLocList(base.Ctxt, entryID, locExpr, ssa.BlockStart.ID, ssa.FuncEnd.ID)
590 locExpr = append(locExpr, dwarf.DW_OP_fbreg)
591 locExpr = dwarf.AppendSleb128(locExpr, heapPtrOffset)
592 locExpr = append(locExpr, dwarf.DW_OP_deref)
593 base.Ctxt.Arch.ByteOrder.PutUint16(locExpr[sizeIdx:], uint16(len(locExpr)-sizeIdx-2))
594 return locExpr
595 }
596
597
598
599 func RecordFlags(flags ...string) {
600 if base.Ctxt.Pkgpath == "" {
601 base.Fatalf("missing pkgpath")
602 }
603
604 type BoolFlag interface {
605 IsBoolFlag() bool
606 }
607 type CountFlag interface {
608 IsCountFlag() bool
609 }
610 var cmd bytes.Buffer
611 for _, name := range flags {
612 f := flag.Lookup(name)
613 if f == nil {
614 continue
615 }
616 getter := f.Value.(flag.Getter)
617 if getter.String() == f.DefValue {
618
619 continue
620 }
621 if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
622 val, ok := getter.Get().(bool)
623 if ok && val {
624 fmt.Fprintf(&cmd, " -%s", f.Name)
625 continue
626 }
627 }
628 if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
629 val, ok := getter.Get().(int)
630 if ok && val == 1 {
631 fmt.Fprintf(&cmd, " -%s", f.Name)
632 continue
633 }
634 }
635 fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
636 }
637
638
639
640
641
642 if buildcfg.Experiment.RegabiArgs {
643 cmd.Write([]byte(" regabi"))
644 }
645
646 if cmd.Len() == 0 {
647 return
648 }
649 s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + base.Ctxt.Pkgpath)
650 s.Type = objabi.SDWARFCUINFO
651
652
653 s.Set(obj.AttrDuplicateOK, true)
654 base.Ctxt.Data = append(base.Ctxt.Data, s)
655 s.P = cmd.Bytes()[1:]
656 }
657
658
659
660 func RecordPackageName() {
661 s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + base.Ctxt.Pkgpath)
662 s.Type = objabi.SDWARFCUINFO
663
664
665 s.Set(obj.AttrDuplicateOK, true)
666 base.Ctxt.Data = append(base.Ctxt.Data, s)
667 s.P = []byte(types.LocalPkg.Name)
668 }
669
670 func closureOffset(n *ir.Name, closureVars map[*ir.Name]int64) int64 {
671 return closureVars[n]
672 }
673
View as plain text