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 string 163 Srcfile string 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 string) 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 []string 275 MetaFileFragments []string 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