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