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.SetCoverageAuxVar(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