1 // Copyright 2022 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 coverage
6 7 // Types and constants related to the output files written
8 // by code coverage tooling. When a coverage-instrumented binary
9 // is run, it emits two output files: a meta-data output file, and
10 // a counter data output file.
11 12 //.....................................................................
13 //
14 // Meta-data definitions:
15 //
16 // The meta-data file is composed of a file header, a series of
17 // meta-data blobs/sections (one per instrumented package), and an offsets
18 // area storing the offsets of each section. Format of the meta-data
19 // file looks like:
20 //
21 // --header----------
22 // | magic: [4]byte magic string
23 // | version
24 // | total length of meta-data file in bytes
25 // | numPkgs: number of package entries in file
26 // | hash: [16]byte hash of entire meta-data payload
27 // | offset to string table section
28 // | length of string table
29 // | number of entries in string table
30 // | counter mode
31 // | counter granularity
32 // --package offsets table------
33 // <offset to pkg 0>
34 // <offset to pkg 1>
35 // ...
36 // --package lengths table------
37 // <length of pkg 0>
38 // <length of pkg 1>
39 // ...
40 // --string table------
41 // <uleb128 len> 8
42 // <data> "somestring"
43 // ...
44 // --package payloads------
45 // <meta-symbol for pkg 0>
46 // <meta-symbol for pkg 1>
47 // ...
48 //
49 // Each package payload is a stand-alone blob emitted by the compiler,
50 // and does not depend on anything else in the meta-data file. In
51 // particular, each blob has it's own string table. Note that the
52 // file-level string table is expected to be very short (most strings
53 // will be in the meta-data blobs themselves).
54 55 // CovMetaMagic holds the magic string for a meta-data file.
56 var CovMetaMagic = [4]byte{'\x00', '\x63', '\x76', '\x6d'}
57 58 // MetaFilePref is a prefix used when emitting meta-data files; these
59 // files are of the form "covmeta.<hash>", where hash is a hash
60 // computed from the hashes of all the package meta-data symbols in
61 // the program.
62 const MetaFilePref = "covmeta"
63 64 // MetaFileVersion contains the current (most recent) meta-data file version.
65 const MetaFileVersion = 1
66 67 // MetaFileHeader stores file header information for a meta-data file.
68 type MetaFileHeader struct {
69 Magic [4]byte
70 Version uint32
71 TotalLength uint64
72 Entries uint64
73 MetaFileHash [16]byte
74 StrTabOffset uint32
75 StrTabLength uint32
76 CMode CounterMode
77 CGranularity CounterGranularity
78 _ [6]byte // padding
79 }
80 81 // MetaSymbolHeader stores header information for a single
82 // meta-data blob, e.g. the coverage meta-data payload
83 // computed for a given Go package.
84 type MetaSymbolHeader struct {
85 Length uint32 // size of meta-symbol payload in bytes
86 PkgName uint32 // string table index
87 PkgPath uint32 // string table index
88 ModulePath uint32 // string table index
89 MetaHash [16]byte
90 _ byte // currently unused
91 _ [3]byte // padding
92 NumFiles uint32
93 NumFuncs uint32
94 }
95 96 const CovMetaHeaderSize = 16 + 4 + 4 + 4 + 4 + 4 + 4 + 4 // keep in sync with above
97 98 // As an example, consider the following Go package:
99 //
100 // 01: package p
101 // 02:
102 // 03: var v, w, z int
103 // 04:
104 // 05: func small(x, y int) int {
105 // 06: v++
106 // 07: // comment
107 // 08: if y == 0 {
108 // 09: return x
109 // 10: }
110 // 11: return (x << 1) ^ (9 / y)
111 // 12: }
112 // 13:
113 // 14: func Medium(q, r int) int {
114 // 15: s1 := small(q, r)
115 // 16: z += s1
116 // 17: s2 := small(r, q)
117 // 18: w -= s2
118 // 19: return w + z
119 // 20: }
120 //
121 // The meta-data blob for the single package above might look like the
122 // following:
123 //
124 // -- MetaSymbolHeader header----------
125 // | size: size of this blob in bytes
126 // | packagepath: <path to p>
127 // | modulepath: <modpath for p>
128 // | nfiles: 1
129 // | nfunctions: 2
130 // --func offsets table------
131 // <offset to func 0>
132 // <offset to func 1>
133 // --string table (contains all files and functions)------
134 // | <uleb128 len> 4
135 // | <data> "p.go"
136 // | <uleb128 len> 5
137 // | <data> "small"
138 // | <uleb128 len> 6
139 // | <data> "Medium"
140 // --func 0------
141 // | <uleb128> num units: 3
142 // | <uleb128> func name: S1 (index into string table)
143 // | <uleb128> file: S0 (index into string table)
144 // | <unit 0>: S0 L6 L8 2
145 // | <unit 1>: S0 L9 L9 1
146 // | <unit 2>: S0 L11 L11 1
147 // --func 1------
148 // | <uleb128> num units: 1
149 // | <uleb128> func name: S2 (index into string table)
150 // | <uleb128> file: S0 (index into string table)
151 // | <unit 0>: S0 L15 L19 5
152 // ---end-----------
153 154 // The following types and constants used by the meta-data encoder/decoder.
155 156 // FuncDesc encapsulates the meta-data definitions for a single Go function.
157 // This version assumes that we're looking at a function before inlining;
158 // if we want to capture a post-inlining view of the world, the
159 // representations of source positions would need to be a good deal more
160 // complicated.
161 type FuncDesc struct {
162 Funcname []byte
163 Srcfile []byte
164 Units []CoverableUnit
165 Lit bool // true if this is a function literal
166 }
167 168 // CoverableUnit describes the source characteristics of a single
169 // program unit for which we want to gather coverage info. Coverable
170 // units are either "simple" or "intraline"; a "simple" coverable unit
171 // corresponds to a basic block (region of straight-line code with no
172 // jumps or control transfers). An "intraline" unit corresponds to a
173 // logical clause nested within some other simple unit. A simple unit
174 // will have a zero Parent value; for an intraline unit NxStmts will
175 // be zero and Parent will be set to 1 plus the index of the
176 // containing simple statement. Example:
177 //
178 // L7: q := 1
179 // L8: x := (y == 101 || launch() == false)
180 // L9: r := x * 2
181 //
182 // For the code above we would have three simple units (one for each
183 // line), then an intraline unit describing the "launch() == false"
184 // clause in line 8, with Parent pointing to the index of the line 8
185 // unit in the units array.
186 //
187 // Note: in the initial version of the coverage revamp, only simple
188 // units will be in use.
189 type CoverableUnit struct {
190 StLine, StCol uint32
191 EnLine, EnCol uint32
192 NxStmts uint32
193 Parent uint32
194 }
195 196 // CounterMode tracks the "flavor" of the coverage counters being
197 // used in a given coverage-instrumented program.
198 type CounterMode uint8
199 200 const (
201 CtrModeInvalid CounterMode = iota
202 CtrModeSet // "set" mode
203 CtrModeCount // "count" mode
204 CtrModeAtomic // "atomic" mode
205 CtrModeRegOnly // registration-only pseudo-mode
206 CtrModeTestMain // testmain pseudo-mode
207 )
208 209 func (cm CounterMode) String() string {
210 switch cm {
211 case CtrModeSet:
212 return "set"
213 case CtrModeCount:
214 return "count"
215 case CtrModeAtomic:
216 return "atomic"
217 case CtrModeRegOnly:
218 return "regonly"
219 case CtrModeTestMain:
220 return "testmain"
221 }
222 return "<invalid>"
223 }
224 225 func ParseCounterMode(mode []byte) CounterMode {
226 var cm CounterMode
227 switch mode {
228 case "set":
229 cm = CtrModeSet
230 case "count":
231 cm = CtrModeCount
232 case "atomic":
233 cm = CtrModeAtomic
234 case "regonly":
235 cm = CtrModeRegOnly
236 case "testmain":
237 cm = CtrModeTestMain
238 default:
239 cm = CtrModeInvalid
240 }
241 return cm
242 }
243 244 // CounterGranularity tracks the granularity of the coverage counters being
245 // used in a given coverage-instrumented program.
246 type CounterGranularity uint8
247 248 const (
249 CtrGranularityInvalid CounterGranularity = iota
250 CtrGranularityPerBlock
251 CtrGranularityPerFunc
252 )
253 254 func (cm CounterGranularity) String() string {
255 switch cm {
256 case CtrGranularityPerBlock:
257 return "perblock"
258 case CtrGranularityPerFunc:
259 return "perfunc"
260 }
261 return "<invalid>"
262 }
263 264 // Name of file within the "go test -cover" temp coverdir directory
265 // containing a list of meta-data files for packages being tested
266 // in a "go test -coverpkg=... ..." run. This constant is shared
267 // by the Go command and by the coverage runtime.
268 const MetaFilesFileName = "metafiles.txt"
269 270 // MetaFileCollection contains information generated by the Go command and
271 // the read in by coverage test support functions within an executing
272 // "go test -cover" binary.
273 type MetaFileCollection struct {
274 ImportPaths [][]byte
275 MetaFileFragments [][]byte
276 }
277 278 //.....................................................................
279 //
280 // Counter data definitions:
281 //
282 283 // A counter data file is composed of a file header followed by one or
284 // more "segments" (each segment representing a given run or partial
285 // run of a give binary) followed by a footer.
286 287 // CovCounterMagic holds the magic string for a coverage counter-data file.
288 var CovCounterMagic = [4]byte{'\x00', '\x63', '\x77', '\x6d'}
289 290 // CounterFileVersion stores the most recent counter data file version.
291 const CounterFileVersion = 1
292 293 // CounterFileHeader stores files header information for a counter-data file.
294 type CounterFileHeader struct {
295 Magic [4]byte
296 Version uint32
297 MetaHash [16]byte
298 CFlavor CounterFlavor
299 BigEndian bool
300 _ [6]byte // padding
301 }
302 303 // CounterSegmentHeader encapsulates information about a specific
304 // segment in a counter data file, which at the moment contains
305 // counters data from a single execution of a coverage-instrumented
306 // program. Following the segment header will be the string table and
307 // args table, and then (possibly) padding bytes to bring the byte
308 // size of the preamble up to a multiple of 4. Immediately following
309 // that will be the counter payloads.
310 //
311 // The "args" section of a segment is used to store annotations
312 // describing where the counter data came from; this section is
313 // basically a series of key-value pairs (can be thought of as an
314 // encoded 'map[string]string'). At the moment we only write os.Args()
315 // data to this section, using pairs of the form "argc=<integer>",
316 // "argv0=<os.Args[0]>", "argv1=<os.Args[1]>", and so on. In the
317 // future the args table may also include things like GOOS/GOARCH
318 // values, and/or tags indicating which tests were run to generate the
319 // counter data.
320 type CounterSegmentHeader struct {
321 FcnEntries uint64
322 StrTabLen uint32
323 ArgsLen uint32
324 }
325 326 // CounterFileFooter appears at the tail end of a counter data file,
327 // and stores the number of segments it contains.
328 type CounterFileFooter struct {
329 Magic [4]byte
330 _ [4]byte // padding
331 NumSegments uint32
332 _ [4]byte // padding
333 }
334 335 // CounterFilePref is the file prefix used when emitting coverage data
336 // output files. CounterFileTemplate describes the format of the file
337 // name: prefix followed by meta-file hash followed by process ID
338 // followed by emit UnixNanoTime.
339 const CounterFilePref = "covcounters"
340 const CounterFileTempl = "%s.%x.%d.%d"
341 const CounterFileRegexp = `^%s\.(\S+)\.(\d+)\.(\d+)+$`
342 343 // CounterFlavor describes how function and counters are
344 // stored/represented in the counter section of the file.
345 type CounterFlavor uint8
346 347 const (
348 // "Raw" representation: all values (pkg ID, func ID, num counters,
349 // and counters themselves) are stored as uint32's.
350 CtrRaw CounterFlavor = iota + 1
351 352 // "ULeb" representation: all values (pkg ID, func ID, num counters,
353 // and counters themselves) are stored with ULEB128 encoding.
354 CtrULeb128
355 )
356 357 func Round4(x int) int {
358 return (x + 3) &^ 3
359 }
360 361 //.....................................................................
362 //
363 // Runtime counter data definitions.
364 //
365 366 // At runtime within a coverage-instrumented program, the "counters"
367 // object we associated with instrumented function can be thought of
368 // as a struct of the following form:
369 //
370 // struct {
371 // numCtrs uint32
372 // pkgid uint32
373 // funcid uint32
374 // counterArray [numBlocks]uint32
375 // }
376 //
377 // where "numCtrs" is the number of blocks / coverable units within the
378 // function, "pkgid" is the unique index assigned to this package by
379 // the runtime, "funcid" is the index of this function within its containing
380 // package, and "counterArray" stores the actual counters.
381 //
382 // The counter variable itself is created not as a struct but as a flat
383 // array of uint32's; we then use the offsets below to index into it.
384 385 const NumCtrsOffset = 0
386 const PkgIdOffset = 1
387 const FuncIdOffset = 2
388 const FirstCtrOffset = 3
389