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