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