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