Source file src/cmd/compile/internal/dwarfgen/dwarf.go

     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  
     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  	// Back when there were two different *Funcs for a function, this code
    43  	// was not consistent about whether a particular *Node being processed
    44  	// was an ODCLFUNC or ONAME node. Partly this is because inlined function
    45  	// bodies have no ODCLFUNC node, which was it's own inconsistency.
    46  	// In any event, the handling of the two different nodes for DWARF purposes
    47  	// was subtly different, likely in unintended ways. CL 272253 merged the
    48  	// two nodes' Func fields, so that code sees the same *Func whether it is
    49  	// holding the ODCLFUNC or the ONAME. This resulted in changes in the
    50  	// DWARF output. To preserve the existing DWARF output and leave an
    51  	// intentional change for a future CL, this code does the following when
    52  	// fn.Op == ONAME:
    53  	//
    54  	// 1. Disallow use of createComplexVars in createDwarfVars.
    55  	//    It was not possible to reach that code for an ONAME before,
    56  	//    because the DebugInfo was set only on the ODCLFUNC Func.
    57  	//    Calling into it in the ONAME case causes an index out of bounds panic.
    58  	//
    59  	// 2. Do not populate apdecls. fn.Func.Dcl was in the ODCLFUNC Func,
    60  	//    not the ONAME Func. Populating apdecls for the ONAME case results
    61  	//    in selected being populated after createSimpleVars is called in
    62  	//    createDwarfVars, and then that causes the loop to skip all the entries
    63  	//    in dcl, meaning that the RecordAutoType calls don't happen.
    64  	//
    65  	// These two adjustments keep toolstash -cmp working for now.
    66  	// Deciding the right answer is, as they say, future work.
    67  	//
    68  	// We can tell the difference between the old ODCLFUNC and ONAME
    69  	// cases by looking at the infosym.Name. If it's empty, DebugInfo is
    70  	// being called from (*obj.Link).populateDWARF, which used to use
    71  	// the ODCLFUNC. If it's non-empty (the name will end in $abstract),
    72  	// DebugInfo is being called from (*obj.Link).DwarfAbstractFunc,
    73  	// which used to use the ONAME form.
    74  	isODCLFUNC := infosym.Name == ""
    75  
    76  	var apdecls []*ir.Name
    77  	// Populate decls for fn.
    78  	if isODCLFUNC {
    79  		for _, n := range fn.Dcl {
    80  			if n.Op() != ir.ONAME { // might be OTYPE or OLITERAL
    81  				continue
    82  			}
    83  			switch n.Class {
    84  			case ir.PAUTO:
    85  				if !n.Used() {
    86  					// Text == nil -> generating abstract function
    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  				// Can happen for TypeInt128 types. This only happens for
   102  				// spill locations, so not a huge deal.
   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  	// For each type referenced by the functions auto vars but not
   128  	// already referenced by a dwarf var, attach an R_USETYPE relocation to
   129  	// the function symbol to insure that the type included in DWARF
   130  	// processing during linking.
   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  // createDwarfVars process fn, returning a list of DWARF variables and the
   161  // Nodes they represent.
   162  func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var) {
   163  	// Collect a raw list of DWARF vars.
   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  		// Recover zero sized variables eliminated by the stackframe pass
   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  		// The backend's stackframe pass prunes away entries from the
   196  		// fn's Dcl list, including PARAMOUT nodes that correspond to
   197  		// output params passed in registers. Add back in these
   198  		// entries here so that we can process them properly during
   199  		// DWARF-gen. See issue 48573 for more details.
   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  				base.Fatalf("invalid ir.Name on debugInfo.RegOutputParams list")
   207  			}
   208  			dcl = append(dcl, n)
   209  		}
   210  	}
   211  
   212  	// If optimization is enabled, the list above will typically be
   213  	// missing some of the original pre-optimization variables in the
   214  	// function (they may have been promoted to registers, folded into
   215  	// constants, dead-coded away, etc).  Input arguments not eligible
   216  	// for SSA optimization are also missing.  Here we add back in entries
   217  	// for selected missing vars. Note that the recipe below creates a
   218  	// conservative location. The idea here is that we want to
   219  	// communicate to the user that "yes, there is a variable named X
   220  	// in this function, but no, I don't have enough information to
   221  	// reliably report its contents."
   222  	// For non-SSA-able arguments, however, the correct information
   223  	// is known -- they have a single home on the stack.
   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  			// SSA-able args get location lists, and may move in and
   234  			// out of registers, so those are handled elsewhere.
   235  			// Autos and named output params seem to get handled
   236  			// with VARDEF, which creates location lists.
   237  			// Args not of SSA-able type are treated here; they
   238  			// are homed on the stack in a single place for the
   239  			// entire call.
   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  		inlIndex := 0
   252  		if base.Flag.GenDwarfInl > 1 {
   253  			if n.InlFormal() || n.InlLocal() {
   254  				inlIndex = posInlIndex(n.Pos()) + 1
   255  				if n.InlFormal() {
   256  					tag = dwarf.DW_TAG_formal_parameter
   257  				}
   258  			}
   259  		}
   260  		declpos := base.Ctxt.InnermostPos(n.Pos())
   261  		dvar := &dwarf.Var{
   262  			Name:          n.Sym().Name,
   263  			IsReturnValue: isReturnValue,
   264  			Tag:           tag,
   265  			WithLoclist:   true,
   266  			StackOffset:   int32(n.FrameOffset()),
   267  			Type:          base.Ctxt.Lookup(typename),
   268  			DeclFile:      declpos.RelFilename(),
   269  			DeclLine:      declpos.RelLine(),
   270  			DeclCol:       declpos.RelCol(),
   271  			InlIndex:      int32(inlIndex),
   272  			ChildIndex:    -1,
   273  			DictIndex:     n.DictIndex,
   274  			ClosureOffset: closureOffset(n, closureVars),
   275  		}
   276  		if n.Esc() == ir.EscHeap {
   277  			if n.Heapaddr == nil {
   278  				base.Fatalf("invalid heap allocated var without Heapaddr")
   279  			}
   280  			debug := fn.DebugInfo.(*ssa.FuncDebug)
   281  			list := createHeapDerefLocationList(n, debug.EntryID)
   282  			dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
   283  				debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
   284  			}
   285  		}
   286  		vars = append(vars, dvar)
   287  		// Record go type to ensure that it gets emitted by the linker.
   288  		fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
   289  	}
   290  
   291  	// Sort decls and vars.
   292  	sortDeclsAndVars(fn, decls, vars)
   293  
   294  	return decls, vars
   295  }
   296  
   297  // sortDeclsAndVars sorts the decl and dwarf var lists according to
   298  // parameter declaration order, so as to insure that when a subprogram
   299  // DIE is emitted, its parameter children appear in declaration order.
   300  // Prior to the advent of the register ABI, sorting by frame offset
   301  // would achieve this; with the register we now need to go back to the
   302  // original function signature.
   303  func sortDeclsAndVars(fn *ir.Func, decls []*ir.Name, vars []*dwarf.Var) {
   304  	paramOrder := make(map[*ir.Name]int)
   305  	idx := 1
   306  	for _, f := range fn.Type().RecvParamsResults() {
   307  		if n, ok := f.Nname.(*ir.Name); ok {
   308  			paramOrder[n] = idx
   309  			idx++
   310  		}
   311  	}
   312  	sort.Stable(varsAndDecls{decls, vars, paramOrder})
   313  }
   314  
   315  type varsAndDecls struct {
   316  	decls      []*ir.Name
   317  	vars       []*dwarf.Var
   318  	paramOrder map[*ir.Name]int
   319  }
   320  
   321  func (v varsAndDecls) Len() int {
   322  	return len(v.decls)
   323  }
   324  
   325  func (v varsAndDecls) Less(i, j int) bool {
   326  	nameLT := func(ni, nj *ir.Name) bool {
   327  		oi, foundi := v.paramOrder[ni]
   328  		oj, foundj := v.paramOrder[nj]
   329  		if foundi {
   330  			if foundj {
   331  				return oi < oj
   332  			} else {
   333  				return true
   334  			}
   335  		}
   336  		return false
   337  	}
   338  	return nameLT(v.decls[i], v.decls[j])
   339  }
   340  
   341  func (v varsAndDecls) Swap(i, j int) {
   342  	v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
   343  	v.decls[i], v.decls[j] = v.decls[j], v.decls[i]
   344  }
   345  
   346  // Given a function that was inlined at some point during the
   347  // compilation, return a sorted list of nodes corresponding to the
   348  // autos/locals in that function prior to inlining. If this is a
   349  // function that is not local to the package being compiled, then the
   350  // names of the variables may have been "versioned" to avoid conflicts
   351  // with local vars; disregard this versioning when sorting.
   352  func preInliningDcls(fnsym *obj.LSym) []*ir.Name {
   353  	fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*ir.Func)
   354  	var rdcl []*ir.Name
   355  	for _, n := range fn.Inl.Dcl {
   356  		c := n.Sym().Name[0]
   357  		// Avoid reporting "_" parameters, since if there are more than
   358  		// one, it can result in a collision later on, as in #23179.
   359  		if n.Sym().Name == "_" || c == '.' || n.Type().IsUntyped() {
   360  			continue
   361  		}
   362  		rdcl = append(rdcl, n)
   363  	}
   364  	return rdcl
   365  }
   366  
   367  // createSimpleVars creates a DWARF entry for every variable declared in the
   368  // function, claiming that they are permanently on the stack.
   369  func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
   370  	var vars []*dwarf.Var
   371  	var decls []*ir.Name
   372  	var selected ir.NameSet
   373  	for _, n := range apDecls {
   374  		if ir.IsAutoTmp(n) {
   375  			continue
   376  		}
   377  
   378  		decls = append(decls, n)
   379  		vars = append(vars, createSimpleVar(fnsym, n, closureVars))
   380  		selected.Add(n)
   381  	}
   382  	return decls, vars, selected
   383  }
   384  
   385  func createSimpleVar(fnsym *obj.LSym, n *ir.Name, closureVars map[*ir.Name]int64) *dwarf.Var {
   386  	var tag int
   387  	var offs int64
   388  
   389  	localAutoOffset := func() int64 {
   390  		offs = n.FrameOffset()
   391  		if base.Ctxt.Arch.FixedFrameSize == 0 {
   392  			offs -= int64(types.PtrSize)
   393  		}
   394  		if buildcfg.FramePointerEnabled {
   395  			offs -= int64(types.PtrSize)
   396  		}
   397  		return offs
   398  	}
   399  
   400  	switch n.Class {
   401  	case ir.PAUTO:
   402  		offs = localAutoOffset()
   403  		tag = dwarf.DW_TAG_variable
   404  	case ir.PPARAM, ir.PPARAMOUT:
   405  		tag = dwarf.DW_TAG_formal_parameter
   406  		if n.IsOutputParamInRegisters() {
   407  			offs = localAutoOffset()
   408  		} else {
   409  			offs = n.FrameOffset() + base.Ctxt.Arch.FixedFrameSize
   410  		}
   411  
   412  	default:
   413  		base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class, n)
   414  	}
   415  
   416  	typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
   417  	delete(fnsym.Func().Autot, reflectdata.TypeLinksym(n.Type()))
   418  	inlIndex := 0
   419  	if base.Flag.GenDwarfInl > 1 {
   420  		if n.InlFormal() || n.InlLocal() {
   421  			inlIndex = posInlIndex(n.Pos()) + 1
   422  			if n.InlFormal() {
   423  				tag = dwarf.DW_TAG_formal_parameter
   424  			}
   425  		}
   426  	}
   427  	declpos := base.Ctxt.InnermostPos(declPos(n))
   428  	return &dwarf.Var{
   429  		Name:          n.Sym().Name,
   430  		IsReturnValue: n.Class == ir.PPARAMOUT,
   431  		IsInlFormal:   n.InlFormal(),
   432  		Tag:           tag,
   433  		StackOffset:   int32(offs),
   434  		Type:          base.Ctxt.Lookup(typename),
   435  		DeclFile:      declpos.RelFilename(),
   436  		DeclLine:      declpos.RelLine(),
   437  		DeclCol:       declpos.RelCol(),
   438  		InlIndex:      int32(inlIndex),
   439  		ChildIndex:    -1,
   440  		DictIndex:     n.DictIndex,
   441  		ClosureOffset: closureOffset(n, closureVars),
   442  	}
   443  }
   444  
   445  // createABIVars creates DWARF variables for functions in which the
   446  // register ABI is enabled but optimization is turned off. It uses a
   447  // hybrid approach in which register-resident input params are
   448  // captured with location lists, and all other vars use the "simple"
   449  // strategy.
   450  func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
   451  
   452  	// Invoke createComplexVars to generate dwarf vars for input parameters
   453  	// that are register-allocated according to the ABI rules.
   454  	decls, vars, selected := createComplexVars(fnsym, fn, closureVars)
   455  
   456  	// Now fill in the remainder of the variables: input parameters
   457  	// that are not register-resident, output parameters, and local
   458  	// variables.
   459  	for _, n := range apDecls {
   460  		if ir.IsAutoTmp(n) {
   461  			continue
   462  		}
   463  		if _, ok := selected[n]; ok {
   464  			// already handled
   465  			continue
   466  		}
   467  
   468  		decls = append(decls, n)
   469  		vars = append(vars, createSimpleVar(fnsym, n, closureVars))
   470  		selected.Add(n)
   471  	}
   472  
   473  	return decls, vars, selected
   474  }
   475  
   476  // createComplexVars creates recomposed DWARF vars with location lists,
   477  // suitable for describing optimized code.
   478  func createComplexVars(fnsym *obj.LSym, fn *ir.Func, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
   479  	debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
   480  
   481  	// Produce a DWARF variable entry for each user variable.
   482  	var decls []*ir.Name
   483  	var vars []*dwarf.Var
   484  	var ssaVars ir.NameSet
   485  
   486  	for varID, dvar := range debugInfo.Vars {
   487  		n := dvar
   488  		ssaVars.Add(n)
   489  		for _, slot := range debugInfo.VarSlots[varID] {
   490  			ssaVars.Add(debugInfo.Slots[slot].N)
   491  		}
   492  
   493  		if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID), closureVars); dvar != nil {
   494  			decls = append(decls, n)
   495  			vars = append(vars, dvar)
   496  		}
   497  	}
   498  
   499  	return decls, vars, ssaVars
   500  }
   501  
   502  // createComplexVar builds a single DWARF variable entry and location list.
   503  func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID, closureVars map[*ir.Name]int64) *dwarf.Var {
   504  	debug := fn.DebugInfo.(*ssa.FuncDebug)
   505  	n := debug.Vars[varID]
   506  
   507  	var tag int
   508  	switch n.Class {
   509  	case ir.PAUTO:
   510  		tag = dwarf.DW_TAG_variable
   511  	case ir.PPARAM, ir.PPARAMOUT:
   512  		tag = dwarf.DW_TAG_formal_parameter
   513  	default:
   514  		return nil
   515  	}
   516  
   517  	gotype := reflectdata.TypeLinksym(n.Type())
   518  	delete(fnsym.Func().Autot, gotype)
   519  	typename := dwarf.InfoPrefix + gotype.Name[len("type:"):]
   520  	inlIndex := 0
   521  	if base.Flag.GenDwarfInl > 1 {
   522  		if n.InlFormal() || n.InlLocal() {
   523  			inlIndex = posInlIndex(n.Pos()) + 1
   524  			if n.InlFormal() {
   525  				tag = dwarf.DW_TAG_formal_parameter
   526  			}
   527  		}
   528  	}
   529  	declpos := base.Ctxt.InnermostPos(n.Pos())
   530  	dvar := &dwarf.Var{
   531  		Name:          n.Sym().Name,
   532  		IsReturnValue: n.Class == ir.PPARAMOUT,
   533  		IsInlFormal:   n.InlFormal(),
   534  		Tag:           tag,
   535  		WithLoclist:   true,
   536  		Type:          base.Ctxt.Lookup(typename),
   537  		// The stack offset is used as a sorting key, so for decomposed
   538  		// variables just give it the first one. It's not used otherwise.
   539  		// This won't work well if the first slot hasn't been assigned a stack
   540  		// location, but it's not obvious how to do better.
   541  		StackOffset:   ssagen.StackOffset(debug.Slots[debug.VarSlots[varID][0]]),
   542  		DeclFile:      declpos.RelFilename(),
   543  		DeclLine:      declpos.RelLine(),
   544  		DeclCol:       declpos.RelCol(),
   545  		InlIndex:      int32(inlIndex),
   546  		ChildIndex:    -1,
   547  		DictIndex:     n.DictIndex,
   548  		ClosureOffset: closureOffset(n, closureVars),
   549  	}
   550  	list := debug.LocationLists[varID]
   551  	if len(list) != 0 {
   552  		dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
   553  			debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
   554  		}
   555  	}
   556  	return dvar
   557  }
   558  
   559  // createHeapDerefLocationList creates a location list for a heap-escaped variable
   560  // that describes "dereference pointer at stack offset"
   561  func createHeapDerefLocationList(n *ir.Name, entryID ssa.ID) []byte {
   562  	// Get the stack offset where the heap pointer is stored
   563  	heapPtrOffset := n.Heapaddr.FrameOffset()
   564  	if base.Ctxt.Arch.FixedFrameSize == 0 {
   565  		heapPtrOffset -= int64(types.PtrSize)
   566  	}
   567  	if buildcfg.FramePointerEnabled {
   568  		heapPtrOffset -= int64(types.PtrSize)
   569  	}
   570  
   571  	// Create a location expression: DW_OP_fbreg <offset> DW_OP_deref
   572  	var locExpr []byte
   573  	var sizeIdx int
   574  	locExpr, sizeIdx = ssa.SetupLocList(base.Ctxt, entryID, locExpr, ssa.BlockStart.ID, ssa.FuncEnd.ID)
   575  	locExpr = append(locExpr, dwarf.DW_OP_fbreg)
   576  	locExpr = dwarf.AppendSleb128(locExpr, heapPtrOffset)
   577  	locExpr = append(locExpr, dwarf.DW_OP_deref)
   578  	base.Ctxt.Arch.ByteOrder.PutUint16(locExpr[sizeIdx:], uint16(len(locExpr)-sizeIdx-2))
   579  	return locExpr
   580  }
   581  
   582  // RecordFlags records the specified command-line flags to be placed
   583  // in the DWARF info.
   584  func RecordFlags(flags ...string) {
   585  	if base.Ctxt.Pkgpath == "" {
   586  		base.Fatalf("missing pkgpath")
   587  	}
   588  
   589  	type BoolFlag interface {
   590  		IsBoolFlag() bool
   591  	}
   592  	type CountFlag interface {
   593  		IsCountFlag() bool
   594  	}
   595  	var cmd bytes.Buffer
   596  	for _, name := range flags {
   597  		f := flag.Lookup(name)
   598  		if f == nil {
   599  			continue
   600  		}
   601  		getter := f.Value.(flag.Getter)
   602  		if getter.String() == f.DefValue {
   603  			// Flag has default value, so omit it.
   604  			continue
   605  		}
   606  		if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
   607  			val, ok := getter.Get().(bool)
   608  			if ok && val {
   609  				fmt.Fprintf(&cmd, " -%s", f.Name)
   610  				continue
   611  			}
   612  		}
   613  		if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
   614  			val, ok := getter.Get().(int)
   615  			if ok && val == 1 {
   616  				fmt.Fprintf(&cmd, " -%s", f.Name)
   617  				continue
   618  			}
   619  		}
   620  		fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
   621  	}
   622  
   623  	// Adds flag to producer string signaling whether regabi is turned on or
   624  	// off.
   625  	// Once regabi is turned on across the board and the relative GOEXPERIMENT
   626  	// knobs no longer exist this code should be removed.
   627  	if buildcfg.Experiment.RegabiArgs {
   628  		cmd.Write([]byte(" regabi"))
   629  	}
   630  
   631  	if cmd.Len() == 0 {
   632  		return
   633  	}
   634  	s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + base.Ctxt.Pkgpath)
   635  	s.Type = objabi.SDWARFCUINFO
   636  	// Sometimes (for example when building tests) we can link
   637  	// together two package main archives. So allow dups.
   638  	s.Set(obj.AttrDuplicateOK, true)
   639  	base.Ctxt.Data = append(base.Ctxt.Data, s)
   640  	s.P = cmd.Bytes()[1:]
   641  }
   642  
   643  // RecordPackageName records the name of the package being
   644  // compiled, so that the linker can save it in the compile unit's DIE.
   645  func RecordPackageName() {
   646  	s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + base.Ctxt.Pkgpath)
   647  	s.Type = objabi.SDWARFCUINFO
   648  	// Sometimes (for example when building tests) we can link
   649  	// together two package main archives. So allow dups.
   650  	s.Set(obj.AttrDuplicateOK, true)
   651  	base.Ctxt.Data = append(base.Ctxt.Data, s)
   652  	s.P = []byte(types.LocalPkg.Name)
   653  }
   654  
   655  func closureOffset(n *ir.Name, closureVars map[*ir.Name]int64) int64 {
   656  	return closureVars[n]
   657  }
   658  

View as plain text