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