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  	"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  	// 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  
   154  func 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.
   160  func 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.
   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  // 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.
   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  		// 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.
   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  // 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.
   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  	// 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.
   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  	// 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.
   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  		// 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.
   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  			// 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.
   614  func 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  
   624  func closureOffset(n *ir.Name, closureVars map[*ir.Name]int64) int64 {
   625  	return closureVars[n]
   626  }
   627  

View as plain text