1// Copyright 2011 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package dwarfgen 6 7import ( 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 27func 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 // Back when there were two different *Funcs for a function, this code 41 // was not consistent about whether a particular *Node being processed 42 // was an ODCLFUNC or ONAME node. Partly this is because inlined function 43 // bodies have no ODCLFUNC node, which was it's own inconsistency. 44 // In any event, the handling of the two different nodes for DWARF purposes 45 // was subtly different, likely in unintended ways. CL 272253 merged the 46 // two nodes' Func fields, so that code sees the same *Func whether it is 47 // holding the ODCLFUNC or the ONAME. This resulted in changes in the 48 // DWARF output. To preserve the existing DWARF output and leave an 49 // intentional change for a future CL, this code does the following when 50 // fn.Op == ONAME: 51 // 52 // 1. Disallow use of createComplexVars in createDwarfVars. 53 // It was not possible to reach that code for an ONAME before, 54 // because the DebugInfo was set only on the ODCLFUNC Func. 55 // Calling into it in the ONAME case causes an index out of bounds panic. 56 // 57 // 2. Do not populate apdecls. fn.Func.Dcl was in the ODCLFUNC Func, 58 // not the ONAME Func. Populating apdecls for the ONAME case results 59 // in selected being populated after createSimpleVars is called in 60 // createDwarfVars, and then that causes the loop to skip all the entries 61 // in dcl, meaning that the RecordAutoType calls don't happen. 62 // 63 // These two adjustments keep toolstash -cmp working for now. 64 // Deciding the right answer is, as they say, future work. 65 // 66 // We can tell the difference between the old ODCLFUNC and ONAME 67 // cases by looking at the infosym.Name. If it's empty, DebugInfo is 68 // being called from (*obj.Link).populateDWARF, which used to use 69 // the ODCLFUNC. If it's non-empty (the name will end in $abstract), 70 // DebugInfo is being called from (*obj.Link).DwarfAbstractFunc, 71 // which used to use the ONAME form. 72 isODCLFUNC := infosym.Name == "" 73 74 var apdecls []*ir.Name 75 // Populate decls for fn. 76 if isODCLFUNC { 77 for _, n := range fn.Dcl { 78 if n.Op() != ir.ONAME { // might be OTYPE or OLITERAL 79 continue 80 } 81 switch n.Class { 82 case ir.PAUTO: 83 if !n.Used() { 84 // Text == nil -> generating abstract function 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 // Can happen for TypeInt128 types. This only happens for 100 // spill locations, so not a huge deal. 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 // For each type referenced by the functions auto vars but not 126 // already referenced by a dwarf var, attach an R_USETYPE relocation to 127 // the function symbol to insure that the type included in DWARF 128 // processing during linking. 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 154func declPos(decl *ir.Name) src.XPos { 155 return decl.Canonical().Pos() 156} 157 158// createDwarfVars process fn, returning a list of DWARF variables and the 159// Nodes they represent. 160func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var) { 161 // Collect a raw list of DWARF vars. 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 // Recover zero sized variables eliminated by the stackframe pass 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 // The backend's stackframe pass prunes away entries from the 194 // fn's Dcl list, including PARAMOUT nodes that correspond to 195 // output params passed in registers. Add back in these 196 // entries here so that we can process them properly during 197 // DWARF-gen. See issue 48573 for more details. 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 // If optimization is enabled, the list above will typically be 211 // missing some of the original pre-optimization variables in the 212 // function (they may have been promoted to registers, folded into 213 // constants, dead-coded away, etc). Input arguments not eligible 214 // for SSA optimization are also missing. Here we add back in entries 215 // for selected missing vars. Note that the recipe below creates a 216 // conservative location. The idea here is that we want to 217 // communicate to the user that "yes, there is a variable named X 218 // in this function, but no, I don't have enough information to 219 // reliably report its contents." 220 // For non-SSA-able arguments, however, the correct information 221 // is known -- they have a single home on the stack. 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 // SSA-able args get location lists, and may move in and 232 // out of registers, so those are handled elsewhere. 233 // Autos and named output params seem to get handled 234 // with VARDEF, which creates location lists. 235 // Args not of SSA-able type are treated here; they 236 // are homed on the stack in a single place for the 237 // entire call. 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 // The variable in question has been promoted to the heap. 251 // Its address is in n.Heapaddr. 252 // TODO(thanm): generate a better location expression 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 // Record go type of to insure that it gets emitted by the linker. 280 fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type())) 281 } 282 283 // Sort decls and vars. 284 sortDeclsAndVars(fn, decls, vars) 285 286 return decls, vars 287} 288 289// sortDeclsAndVars sorts the decl and dwarf var lists according to 290// parameter declaration order, so as to insure that when a subprogram 291// DIE is emitted, its parameter children appear in declaration order. 292// Prior to the advent of the register ABI, sorting by frame offset 293// would achieve this; with the register we now need to go back to the 294// original function signature. 295func 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 307type varsAndDecls struct { 308 decls []*ir.Name 309 vars []*dwarf.Var 310 paramOrder map[*ir.Name]int 311} 312 313func (v varsAndDecls) Len() int { 314 return len(v.decls) 315} 316 317func (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 333func (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// Given a function that was inlined at some point during the 339// compilation, return a sorted list of nodes corresponding to the 340// autos/locals in that function prior to inlining. If this is a 341// function that is not local to the package being compiled, then the 342// names of the variables may have been "versioned" to avoid conflicts 343// with local vars; disregard this versioning when sorting. 344func 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 // Avoid reporting "_" parameters, since if there are more than 350 // one, it can result in a collision later on, as in #23179. 351 if n.Sym().Name == "_" || c == '.' || n.Type().IsUntyped() { 352 continue 353 } 354 rdcl = append(rdcl, n) 355 } 356 return rdcl 357} 358 359// createSimpleVars creates a DWARF entry for every variable declared in the 360// function, claiming that they are permanently on the stack. 361func 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 377func 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// createABIVars creates DWARF variables for functions in which the 438// register ABI is enabled but optimization is turned off. It uses a 439// hybrid approach in which register-resident input params are 440// captured with location lists, and all other vars use the "simple" 441// strategy. 442func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) { 443 444 // Invoke createComplexVars to generate dwarf vars for input parameters 445 // that are register-allocated according to the ABI rules. 446 decls, vars, selected := createComplexVars(fnsym, fn, closureVars) 447 448 // Now fill in the remainder of the variables: input parameters 449 // that are not register-resident, output parameters, and local 450 // variables. 451 for _, n := range apDecls { 452 if ir.IsAutoTmp(n) { 453 continue 454 } 455 if _, ok := selected[n]; ok { 456 // already handled 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// createComplexVars creates recomposed DWARF vars with location lists, 469// suitable for describing optimized code. 470func 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 // Produce a DWARF variable entry for each user variable. 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// createComplexVar builds a single DWARF variable entry and location list. 495func 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 // The stack offset is used as a sorting key, so for decomposed 530 // variables just give it the first one. It's not used otherwise. 531 // This won't work well if the first slot hasn't been assigned a stack 532 // location, but it's not obvious how to do better. 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// RecordFlags records the specified command-line flags to be placed 552// in the DWARF info. 553func 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 // Flag has default value, so omit it. 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 // Adds flag to producer string signaling whether regabi is turned on or 593 // off. 594 // Once regabi is turned on across the board and the relative GOEXPERIMENT 595 // knobs no longer exist this code should be removed. 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 // Sometimes (for example when building tests) we can link 606 // together two package main archives. So allow dups. 607 s.Set(obj.AttrDuplicateOK, true) 608 base.Ctxt.Data = append(base.Ctxt.Data, s) 609 s.P = cmd.Bytes()[1:] 610} 611 612// RecordPackageName records the name of the package being 613// compiled, so that the linker can save it in the compile unit's DIE. 614func RecordPackageName() { 615 s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + base.Ctxt.Pkgpath) 616 s.Type = objabi.SDWARFCUINFO 617 // Sometimes (for example when building tests) we can link 618 // together two package main archives. So allow dups. 619 s.Set(obj.AttrDuplicateOK, true) 620 base.Ctxt.Data = append(base.Ctxt.Data, s) 621 s.P = []byte(types.LocalPkg.Name) 622} 623 624func closureOffset(n *ir.Name, closureVars map[*ir.Name]int64) int64 { 625 return closureVars[n] 626} 627