1  
     2  
     3  
     4  
     5  package coverage
     6  
     7  
     8  
     9  
    10  
    11  
    12  
    13  
    14  import (
    15  	"cmd/compile/internal/base"
    16  	"cmd/compile/internal/ir"
    17  	"cmd/compile/internal/typecheck"
    18  	"cmd/compile/internal/types"
    19  	"cmd/internal/objabi"
    20  	"internal/coverage"
    21  	"strconv"
    22  	"strings"
    23  )
    24  
    25  
    26  
    27  type names struct {
    28  	MetaVar     *ir.Name
    29  	PkgIdVar    *ir.Name
    30  	InitFn      *ir.Func
    31  	CounterMode coverage.CounterMode
    32  	CounterGran coverage.CounterGranularity
    33  }
    34  
    35  
    36  
    37  
    38  
    39  
    40  
    41  func Fixup() {
    42  	if base.Flag.Cfg.CoverageInfo == nil {
    43  		return 
    44  	}
    45  
    46  	metaVarName := base.Flag.Cfg.CoverageInfo.MetaVar
    47  	pkgIdVarName := base.Flag.Cfg.CoverageInfo.PkgIdVar
    48  	counterMode := base.Flag.Cfg.CoverageInfo.CounterMode
    49  	counterGran := base.Flag.Cfg.CoverageInfo.CounterGranularity
    50  	counterPrefix := base.Flag.Cfg.CoverageInfo.CounterPrefix
    51  	var metavar *ir.Name
    52  	var pkgidvar *ir.Name
    53  
    54  	ckTypSanity := func(nm *ir.Name, tag string) {
    55  		if nm.Type() == nil || nm.Type().HasPointers() {
    56  			base.Fatalf("unsuitable %s %q mentioned in coveragecfg, improper type '%v'", tag, nm.Sym().Name, nm.Type())
    57  		}
    58  	}
    59  
    60  	for _, nm := range typecheck.Target.Externs {
    61  		s := nm.Sym()
    62  		switch s.Name {
    63  		case metaVarName:
    64  			metavar = nm
    65  			ckTypSanity(nm, "metavar")
    66  			nm.MarkReadonly()
    67  			continue
    68  		case pkgIdVarName:
    69  			pkgidvar = nm
    70  			ckTypSanity(nm, "pkgidvar")
    71  			nm.SetCoverageAuxVar(true)
    72  			s := nm.Linksym()
    73  			s.Type = objabi.SCOVERAGE_AUXVAR
    74  			continue
    75  		}
    76  		if strings.HasPrefix(s.Name, counterPrefix) {
    77  			ckTypSanity(nm, "countervar")
    78  			nm.SetCoverageCounter(true)
    79  			s := nm.Linksym()
    80  			s.Type = objabi.SCOVERAGE_COUNTER
    81  		}
    82  	}
    83  	cm := coverage.ParseCounterMode(counterMode)
    84  	if cm == coverage.CtrModeInvalid {
    85  		base.Fatalf("bad setting %q for covermode in coveragecfg:",
    86  			counterMode)
    87  	}
    88  	var cg coverage.CounterGranularity
    89  	switch counterGran {
    90  	case "perblock":
    91  		cg = coverage.CtrGranularityPerBlock
    92  	case "perfunc":
    93  		cg = coverage.CtrGranularityPerFunc
    94  	default:
    95  		base.Fatalf("bad setting %q for covergranularity in coveragecfg:",
    96  			counterGran)
    97  	}
    98  
    99  	cnames := names{
   100  		MetaVar:     metavar,
   101  		PkgIdVar:    pkgidvar,
   102  		CounterMode: cm,
   103  		CounterGran: cg,
   104  	}
   105  
   106  	for _, fn := range typecheck.Target.Funcs {
   107  		if ir.FuncName(fn) == "init" {
   108  			cnames.InitFn = fn
   109  			break
   110  		}
   111  	}
   112  	if cnames.InitFn == nil {
   113  		panic("unexpected (no init func for -cover build)")
   114  	}
   115  
   116  	hashv, len := metaHashAndLen()
   117  	if cnames.CounterMode != coverage.CtrModeTestMain {
   118  		registerMeta(cnames, hashv, len)
   119  	}
   120  	if base.Ctxt.Pkgpath == "main" {
   121  		addInitHookCall(cnames.InitFn, cnames.CounterMode)
   122  	}
   123  }
   124  
   125  func metaHashAndLen() ([16]byte, int) {
   126  
   127  	
   128  	mhash := base.Flag.Cfg.CoverageInfo.MetaHash
   129  	if len(mhash) != 32 {
   130  		base.Fatalf("unexpected: got metahash length %d want 32", len(mhash))
   131  	}
   132  	var hv [16]byte
   133  	for i := 0; i < 16; i++ {
   134  		nib := string(mhash[i*2 : i*2+2])
   135  		x, err := strconv.ParseInt(nib, 16, 32)
   136  		if err != nil {
   137  			base.Fatalf("metahash bad byte %q", nib)
   138  		}
   139  		hv[i] = byte(x)
   140  	}
   141  
   142  	
   143  	return hv, base.Flag.Cfg.CoverageInfo.MetaLen
   144  }
   145  
   146  func registerMeta(cnames names, hashv [16]byte, mdlen int) {
   147  	
   148  	pos := cnames.InitFn.Pos()
   149  	elist := make([]ir.Node, 0, 16)
   150  	for i := 0; i < 16; i++ {
   151  		elem := ir.NewInt(base.Pos, int64(hashv[i]))
   152  		elist = append(elist, elem)
   153  	}
   154  	ht := types.NewArray(types.Types[types.TUINT8], 16)
   155  	hashx := ir.NewCompLitExpr(pos, ir.OCOMPLIT, ht, elist)
   156  
   157  	
   158  	mdax := typecheck.NodAddr(cnames.MetaVar)
   159  	mdauspx := typecheck.ConvNop(mdax, types.Types[types.TUNSAFEPTR])
   160  
   161  	
   162  	lenx := ir.NewInt(base.Pos, int64(mdlen)) 
   163  
   164  	
   165  	
   166  	
   167  	
   168  	fn := typecheck.LookupRuntime("addCovMeta")
   169  	pkid := coverage.HardCodedPkgID(base.Ctxt.Pkgpath)
   170  	pkIdNode := ir.NewInt(base.Pos, int64(pkid))
   171  	cmodeNode := ir.NewInt(base.Pos, int64(cnames.CounterMode))
   172  	cgranNode := ir.NewInt(base.Pos, int64(cnames.CounterGran))
   173  	pkPathNode := ir.NewString(base.Pos, base.Ctxt.Pkgpath)
   174  	callx := typecheck.Call(pos, fn, []ir.Node{mdauspx, lenx, hashx,
   175  		pkPathNode, pkIdNode, cmodeNode, cgranNode}, false)
   176  	assign := callx
   177  	if pkid == coverage.NotHardCoded {
   178  		assign = typecheck.Stmt(ir.NewAssignStmt(pos, cnames.PkgIdVar, callx))
   179  	}
   180  
   181  	
   182  	
   183  	
   184  	cnames.InitFn.Body.Prepend(assign)
   185  }
   186  
   187  
   188  
   189  
   190  
   191  func addInitHookCall(initfn *ir.Func, cmode coverage.CounterMode) {
   192  	typecheck.InitCoverage()
   193  	pos := initfn.Pos()
   194  	istest := cmode == coverage.CtrModeTestMain
   195  	initf := typecheck.LookupCoverage("initHook")
   196  	istestNode := ir.NewBool(base.Pos, istest)
   197  	args := []ir.Node{istestNode}
   198  	callx := typecheck.Call(pos, initf, args, false)
   199  	initfn.Body.Append(callx)
   200  }
   201  
View as plain text