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/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 interface{}) ([]dwarf.Scope, 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  	// Back when there were two different *Funcs for a function, this code
    40  	// was not consistent about whether a particular *Node being processed
    41  	// was an ODCLFUNC or ONAME node. Partly this is because inlined function
    42  	// bodies have no ODCLFUNC node, which was it's own inconsistency.
    43  	// In any event, the handling of the two different nodes for DWARF purposes
    44  	// was subtly different, likely in unintended ways. CL 272253 merged the
    45  	// two nodes' Func fields, so that code sees the same *Func whether it is
    46  	// holding the ODCLFUNC or the ONAME. This resulted in changes in the
    47  	// DWARF output. To preserve the existing DWARF output and leave an
    48  	// intentional change for a future CL, this code does the following when
    49  	// fn.Op == ONAME:
    50  	//
    51  	// 1. Disallow use of createComplexVars in createDwarfVars.
    52  	//    It was not possible to reach that code for an ONAME before,
    53  	//    because the DebugInfo was set only on the ODCLFUNC Func.
    54  	//    Calling into it in the ONAME case causes an index out of bounds panic.
    55  	//
    56  	// 2. Do not populate apdecls. fn.Func.Dcl was in the ODCLFUNC Func,
    57  	//    not the ONAME Func. Populating apdecls for the ONAME case results
    58  	//    in selected being populated after createSimpleVars is called in
    59  	//    createDwarfVars, and then that causes the loop to skip all the entries
    60  	//    in dcl, meaning that the RecordAutoType calls don't happen.
    61  	//
    62  	// These two adjustments keep toolstash -cmp working for now.
    63  	// Deciding the right answer is, as they say, future work.
    64  	//
    65  	// We can tell the difference between the old ODCLFUNC and ONAME
    66  	// cases by looking at the infosym.Name. If it's empty, DebugInfo is
    67  	// being called from (*obj.Link).populateDWARF, which used to use
    68  	// the ODCLFUNC. If it's non-empty (the name will end in $abstract),
    69  	// DebugInfo is being called from (*obj.Link).DwarfAbstractFunc,
    70  	// which used to use the ONAME form.
    71  	isODCLFUNC := infosym.Name == ""
    72  
    73  	var apdecls []*ir.Name
    74  	// Populate decls for fn.
    75  	if isODCLFUNC {
    76  		for _, n := range fn.Dcl {
    77  			if n.Op() != ir.ONAME { // might be OTYPE or OLITERAL
    78  				continue
    79  			}
    80  			switch n.Class {
    81  			case ir.PAUTO:
    82  				if !n.Used() {
    83  					// Text == nil -> generating abstract function
    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  			fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
    95  		}
    96  	}
    97  
    98  	decls, dwarfVars := createDwarfVars(fnsym, isODCLFUNC, fn, apdecls)
    99  
   100  	// For each type referenced by the functions auto vars but not
   101  	// already referenced by a dwarf var, attach an R_USETYPE relocation to
   102  	// the function symbol to insure that the type included in DWARF
   103  	// processing during linking.
   104  	typesyms := []*obj.LSym{}
   105  	for t, _ := range fnsym.Func().Autot {
   106  		typesyms = append(typesyms, t)
   107  	}
   108  	sort.Sort(obj.BySymName(typesyms))
   109  	for _, sym := range typesyms {
   110  		r := obj.Addrel(infosym)
   111  		r.Sym = sym
   112  		r.Type = objabi.R_USETYPE
   113  	}
   114  	fnsym.Func().Autot = nil
   115  
   116  	var varScopes []ir.ScopeID
   117  	for _, decl := range decls {
   118  		pos := declPos(decl)
   119  		varScopes = append(varScopes, findScope(fn.Marks, pos))
   120  	}
   121  
   122  	scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes)
   123  	var inlcalls dwarf.InlCalls
   124  	if base.Flag.GenDwarfInl > 0 {
   125  		inlcalls = assembleInlines(fnsym, dwarfVars)
   126  	}
   127  	return scopes, inlcalls
   128  }
   129  
   130  func declPos(decl *ir.Name) src.XPos {
   131  	return decl.Canonical().Pos()
   132  }
   133  
   134  // createDwarfVars process fn, returning a list of DWARF variables and the
   135  // Nodes they represent.
   136  func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir.Name) ([]*ir.Name, []*dwarf.Var) {
   137  	// Collect a raw list of DWARF vars.
   138  	var vars []*dwarf.Var
   139  	var decls []*ir.Name
   140  	var selected ir.NameSet
   141  
   142  	if base.Ctxt.Flag_locationlists && base.Ctxt.Flag_optimize && fn.DebugInfo != nil && complexOK {
   143  		decls, vars, selected = createComplexVars(fnsym, fn)
   144  	} else if fn.ABI == obj.ABIInternal && base.Flag.N != 0 && complexOK {
   145  		decls, vars, selected = createABIVars(fnsym, fn, apDecls)
   146  	} else {
   147  		decls, vars, selected = createSimpleVars(fnsym, apDecls)
   148  	}
   149  
   150  	dcl := apDecls
   151  	if fnsym.WasInlined() {
   152  		dcl = preInliningDcls(fnsym)
   153  	} else {
   154  		// The backend's stackframe pass prunes away entries from the
   155  		// fn's Dcl list, including PARAMOUT nodes that correspond to
   156  		// output params passed in registers. Add back in these
   157  		// entries here so that we can process them properly during
   158  		// DWARF-gen. See issue 48573 for more details.
   159  		debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
   160  		for _, n := range debugInfo.RegOutputParams {
   161  			if n.Class != ir.PPARAMOUT || !n.IsOutputParamInRegisters() {
   162  				panic("invalid ir.Name on debugInfo.RegOutputParams list")
   163  			}
   164  			dcl = append(dcl, n)
   165  		}
   166  	}
   167  
   168  	// If optimization is enabled, the list above will typically be
   169  	// missing some of the original pre-optimization variables in the
   170  	// function (they may have been promoted to registers, folded into
   171  	// constants, dead-coded away, etc).  Input arguments not eligible
   172  	// for SSA optimization are also missing.  Here we add back in entries
   173  	// for selected missing vars. Note that the recipe below creates a
   174  	// conservative location. The idea here is that we want to
   175  	// communicate to the user that "yes, there is a variable named X
   176  	// in this function, but no, I don't have enough information to
   177  	// reliably report its contents."
   178  	// For non-SSA-able arguments, however, the correct information
   179  	// is known -- they have a single home on the stack.
   180  	for _, n := range dcl {
   181  		if selected.Has(n) {
   182  			continue
   183  		}
   184  		c := n.Sym().Name[0]
   185  		if c == '.' || n.Type().IsUntyped() {
   186  			continue
   187  		}
   188  		if n.Class == ir.PPARAM && !ssagen.TypeOK(n.Type()) {
   189  			// SSA-able args get location lists, and may move in and
   190  			// out of registers, so those are handled elsewhere.
   191  			// Autos and named output params seem to get handled
   192  			// with VARDEF, which creates location lists.
   193  			// Args not of SSA-able type are treated here; they
   194  			// are homed on the stack in a single place for the
   195  			// entire call.
   196  			vars = append(vars, createSimpleVar(fnsym, n))
   197  			decls = append(decls, n)
   198  			continue
   199  		}
   200  		typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
   201  		decls = append(decls, n)
   202  		abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
   203  		isReturnValue := (n.Class == ir.PPARAMOUT)
   204  		if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
   205  			abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   206  		}
   207  		if n.Esc() == ir.EscHeap {
   208  			// The variable in question has been promoted to the heap.
   209  			// Its address is in n.Heapaddr.
   210  			// TODO(thanm): generate a better location expression
   211  		}
   212  		inlIndex := 0
   213  		if base.Flag.GenDwarfInl > 1 {
   214  			if n.InlFormal() || n.InlLocal() {
   215  				inlIndex = posInlIndex(n.Pos()) + 1
   216  				if n.InlFormal() {
   217  					abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   218  				}
   219  			}
   220  		}
   221  		declpos := base.Ctxt.InnermostPos(n.Pos())
   222  		vars = append(vars, &dwarf.Var{
   223  			Name:          n.Sym().Name,
   224  			IsReturnValue: isReturnValue,
   225  			Abbrev:        abbrev,
   226  			StackOffset:   int32(n.FrameOffset()),
   227  			Type:          base.Ctxt.Lookup(typename),
   228  			DeclFile:      declpos.RelFilename(),
   229  			DeclLine:      declpos.RelLine(),
   230  			DeclCol:       declpos.RelCol(),
   231  			InlIndex:      int32(inlIndex),
   232  			ChildIndex:    -1,
   233  			DictIndex:     n.DictIndex,
   234  		})
   235  		// Record go type of to insure that it gets emitted by the linker.
   236  		fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
   237  	}
   238  
   239  	// Sort decls and vars.
   240  	sortDeclsAndVars(fn, decls, vars)
   241  
   242  	return decls, vars
   243  }
   244  
   245  // sortDeclsAndVars sorts the decl and dwarf var lists according to
   246  // parameter declaration order, so as to insure that when a subprogram
   247  // DIE is emitted, its parameter children appear in declaration order.
   248  // Prior to the advent of the register ABI, sorting by frame offset
   249  // would achieve this; with the register we now need to go back to the
   250  // original function signature.
   251  func sortDeclsAndVars(fn *ir.Func, decls []*ir.Name, vars []*dwarf.Var) {
   252  	paramOrder := make(map[*ir.Name]int)
   253  	idx := 1
   254  	for _, selfn := range types.RecvsParamsResults {
   255  		fsl := selfn(fn.Type()).FieldSlice()
   256  		for _, f := range fsl {
   257  			if n, ok := f.Nname.(*ir.Name); ok {
   258  				paramOrder[n] = idx
   259  				idx++
   260  			}
   261  		}
   262  	}
   263  	sort.Stable(varsAndDecls{decls, vars, paramOrder})
   264  }
   265  
   266  type varsAndDecls struct {
   267  	decls      []*ir.Name
   268  	vars       []*dwarf.Var
   269  	paramOrder map[*ir.Name]int
   270  }
   271  
   272  func (v varsAndDecls) Len() int {
   273  	return len(v.decls)
   274  }
   275  
   276  func (v varsAndDecls) Less(i, j int) bool {
   277  	nameLT := func(ni, nj *ir.Name) bool {
   278  		oi, foundi := v.paramOrder[ni]
   279  		oj, foundj := v.paramOrder[nj]
   280  		if foundi {
   281  			if foundj {
   282  				return oi < oj
   283  			} else {
   284  				return true
   285  			}
   286  		}
   287  		return false
   288  	}
   289  	return nameLT(v.decls[i], v.decls[j])
   290  }
   291  
   292  func (v varsAndDecls) Swap(i, j int) {
   293  	v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
   294  	v.decls[i], v.decls[j] = v.decls[j], v.decls[i]
   295  }
   296  
   297  // Given a function that was inlined at some point during the
   298  // compilation, return a sorted list of nodes corresponding to the
   299  // autos/locals in that function prior to inlining. If this is a
   300  // function that is not local to the package being compiled, then the
   301  // names of the variables may have been "versioned" to avoid conflicts
   302  // with local vars; disregard this versioning when sorting.
   303  func preInliningDcls(fnsym *obj.LSym) []*ir.Name {
   304  	fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*ir.Func)
   305  	var rdcl []*ir.Name
   306  	for _, n := range fn.Inl.Dcl {
   307  		c := n.Sym().Name[0]
   308  		// Avoid reporting "_" parameters, since if there are more than
   309  		// one, it can result in a collision later on, as in #23179.
   310  		if unversion(n.Sym().Name) == "_" || c == '.' || n.Type().IsUntyped() {
   311  			continue
   312  		}
   313  		rdcl = append(rdcl, n)
   314  	}
   315  	return rdcl
   316  }
   317  
   318  // createSimpleVars creates a DWARF entry for every variable declared in the
   319  // function, claiming that they are permanently on the stack.
   320  func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Name) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
   321  	var vars []*dwarf.Var
   322  	var decls []*ir.Name
   323  	var selected ir.NameSet
   324  	for _, n := range apDecls {
   325  		if ir.IsAutoTmp(n) {
   326  			continue
   327  		}
   328  
   329  		decls = append(decls, n)
   330  		vars = append(vars, createSimpleVar(fnsym, n))
   331  		selected.Add(n)
   332  	}
   333  	return decls, vars, selected
   334  }
   335  
   336  func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
   337  	var abbrev int
   338  	var offs int64
   339  
   340  	localAutoOffset := func() int64 {
   341  		offs = n.FrameOffset()
   342  		if base.Ctxt.FixedFrameSize() == 0 {
   343  			offs -= int64(types.PtrSize)
   344  		}
   345  		if buildcfg.FramePointerEnabled {
   346  			offs -= int64(types.PtrSize)
   347  		}
   348  		return offs
   349  	}
   350  
   351  	switch n.Class {
   352  	case ir.PAUTO:
   353  		offs = localAutoOffset()
   354  		abbrev = dwarf.DW_ABRV_AUTO
   355  	case ir.PPARAM, ir.PPARAMOUT:
   356  		abbrev = dwarf.DW_ABRV_PARAM
   357  		if n.IsOutputParamInRegisters() {
   358  			offs = localAutoOffset()
   359  		} else {
   360  			offs = n.FrameOffset() + base.Ctxt.FixedFrameSize()
   361  		}
   362  
   363  	default:
   364  		base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class, n)
   365  	}
   366  
   367  	typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
   368  	delete(fnsym.Func().Autot, reflectdata.TypeLinksym(n.Type()))
   369  	inlIndex := 0
   370  	if base.Flag.GenDwarfInl > 1 {
   371  		if n.InlFormal() || n.InlLocal() {
   372  			inlIndex = posInlIndex(n.Pos()) + 1
   373  			if n.InlFormal() {
   374  				abbrev = dwarf.DW_ABRV_PARAM
   375  			}
   376  		}
   377  	}
   378  	declpos := base.Ctxt.InnermostPos(declPos(n))
   379  	return &dwarf.Var{
   380  		Name:          n.Sym().Name,
   381  		IsReturnValue: n.Class == ir.PPARAMOUT,
   382  		IsInlFormal:   n.InlFormal(),
   383  		Abbrev:        abbrev,
   384  		StackOffset:   int32(offs),
   385  		Type:          base.Ctxt.Lookup(typename),
   386  		DeclFile:      declpos.RelFilename(),
   387  		DeclLine:      declpos.RelLine(),
   388  		DeclCol:       declpos.RelCol(),
   389  		InlIndex:      int32(inlIndex),
   390  		ChildIndex:    -1,
   391  		DictIndex:     n.DictIndex,
   392  	}
   393  }
   394  
   395  // createABIVars creates DWARF variables for functions in which the
   396  // register ABI is enabled but optimization is turned off. It uses a
   397  // hybrid approach in which register-resident input params are
   398  // captured with location lists, and all other vars use the "simple"
   399  // strategy.
   400  func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
   401  
   402  	// Invoke createComplexVars to generate dwarf vars for input parameters
   403  	// that are register-allocated according to the ABI rules.
   404  	decls, vars, selected := createComplexVars(fnsym, fn)
   405  
   406  	// Now fill in the remainder of the variables: input parameters
   407  	// that are not register-resident, output parameters, and local
   408  	// variables.
   409  	for _, n := range apDecls {
   410  		if ir.IsAutoTmp(n) {
   411  			continue
   412  		}
   413  		if _, ok := selected[n]; ok {
   414  			// already handled
   415  			continue
   416  		}
   417  
   418  		decls = append(decls, n)
   419  		vars = append(vars, createSimpleVar(fnsym, n))
   420  		selected.Add(n)
   421  	}
   422  
   423  	return decls, vars, selected
   424  }
   425  
   426  // createComplexVars creates recomposed DWARF vars with location lists,
   427  // suitable for describing optimized code.
   428  func createComplexVars(fnsym *obj.LSym, fn *ir.Func) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
   429  	debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
   430  
   431  	// Produce a DWARF variable entry for each user variable.
   432  	var decls []*ir.Name
   433  	var vars []*dwarf.Var
   434  	var ssaVars ir.NameSet
   435  
   436  	for varID, dvar := range debugInfo.Vars {
   437  		n := dvar
   438  		ssaVars.Add(n)
   439  		for _, slot := range debugInfo.VarSlots[varID] {
   440  			ssaVars.Add(debugInfo.Slots[slot].N)
   441  		}
   442  
   443  		if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID)); dvar != nil {
   444  			decls = append(decls, n)
   445  			vars = append(vars, dvar)
   446  		}
   447  	}
   448  
   449  	return decls, vars, ssaVars
   450  }
   451  
   452  // createComplexVar builds a single DWARF variable entry and location list.
   453  func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var {
   454  	debug := fn.DebugInfo.(*ssa.FuncDebug)
   455  	n := debug.Vars[varID]
   456  
   457  	var abbrev int
   458  	switch n.Class {
   459  	case ir.PAUTO:
   460  		abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
   461  	case ir.PPARAM, ir.PPARAMOUT:
   462  		abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   463  	default:
   464  		return nil
   465  	}
   466  
   467  	gotype := reflectdata.TypeLinksym(n.Type())
   468  	delete(fnsym.Func().Autot, gotype)
   469  	typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
   470  	inlIndex := 0
   471  	if base.Flag.GenDwarfInl > 1 {
   472  		if n.InlFormal() || n.InlLocal() {
   473  			inlIndex = posInlIndex(n.Pos()) + 1
   474  			if n.InlFormal() {
   475  				abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   476  			}
   477  		}
   478  	}
   479  	declpos := base.Ctxt.InnermostPos(n.Pos())
   480  	dvar := &dwarf.Var{
   481  		Name:          n.Sym().Name,
   482  		IsReturnValue: n.Class == ir.PPARAMOUT,
   483  		IsInlFormal:   n.InlFormal(),
   484  		Abbrev:        abbrev,
   485  		Type:          base.Ctxt.Lookup(typename),
   486  		// The stack offset is used as a sorting key, so for decomposed
   487  		// variables just give it the first one. It's not used otherwise.
   488  		// This won't work well if the first slot hasn't been assigned a stack
   489  		// location, but it's not obvious how to do better.
   490  		StackOffset: ssagen.StackOffset(debug.Slots[debug.VarSlots[varID][0]]),
   491  		DeclFile:    declpos.RelFilename(),
   492  		DeclLine:    declpos.RelLine(),
   493  		DeclCol:     declpos.RelCol(),
   494  		InlIndex:    int32(inlIndex),
   495  		ChildIndex:  -1,
   496  		DictIndex:   n.DictIndex,
   497  	}
   498  	list := debug.LocationLists[varID]
   499  	if len(list) != 0 {
   500  		dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
   501  			debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
   502  		}
   503  	}
   504  	return dvar
   505  }
   506  
   507  // RecordFlags records the specified command-line flags to be placed
   508  // in the DWARF info.
   509  func RecordFlags(flags ...string) {
   510  	if base.Ctxt.Pkgpath == "" {
   511  		// We can't record the flags if we don't know what the
   512  		// package name is.
   513  		return
   514  	}
   515  
   516  	type BoolFlag interface {
   517  		IsBoolFlag() bool
   518  	}
   519  	type CountFlag interface {
   520  		IsCountFlag() bool
   521  	}
   522  	var cmd bytes.Buffer
   523  	for _, name := range flags {
   524  		f := flag.Lookup(name)
   525  		if f == nil {
   526  			continue
   527  		}
   528  		getter := f.Value.(flag.Getter)
   529  		if getter.String() == f.DefValue {
   530  			// Flag has default value, so omit it.
   531  			continue
   532  		}
   533  		if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
   534  			val, ok := getter.Get().(bool)
   535  			if ok && val {
   536  				fmt.Fprintf(&cmd, " -%s", f.Name)
   537  				continue
   538  			}
   539  		}
   540  		if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
   541  			val, ok := getter.Get().(int)
   542  			if ok && val == 1 {
   543  				fmt.Fprintf(&cmd, " -%s", f.Name)
   544  				continue
   545  			}
   546  		}
   547  		fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
   548  	}
   549  
   550  	// Adds flag to producer string singalling whether regabi is turned on or
   551  	// off.
   552  	// Once regabi is turned on across the board and the relative GOEXPERIMENT
   553  	// knobs no longer exist this code should be removed.
   554  	if buildcfg.Experiment.RegabiArgs {
   555  		cmd.Write([]byte(" regabi"))
   556  	}
   557  
   558  	if cmd.Len() == 0 {
   559  		return
   560  	}
   561  	s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + base.Ctxt.Pkgpath)
   562  	s.Type = objabi.SDWARFCUINFO
   563  	// Sometimes (for example when building tests) we can link
   564  	// together two package main archives. So allow dups.
   565  	s.Set(obj.AttrDuplicateOK, true)
   566  	base.Ctxt.Data = append(base.Ctxt.Data, s)
   567  	s.P = cmd.Bytes()[1:]
   568  }
   569  
   570  // RecordPackageName records the name of the package being
   571  // compiled, so that the linker can save it in the compile unit's DIE.
   572  func RecordPackageName() {
   573  	s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + base.Ctxt.Pkgpath)
   574  	s.Type = objabi.SDWARFCUINFO
   575  	// Sometimes (for example when building tests) we can link
   576  	// together two package main archives. So allow dups.
   577  	s.Set(obj.AttrDuplicateOK, true)
   578  	base.Ctxt.Data = append(base.Ctxt.Data, s)
   579  	s.P = []byte(types.LocalPkg.Name)
   580  }
   581  

View as plain text