github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/internal/coverage/defs.go (about) 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 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 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 //..................................................................... 265 // 266 // Counter data definitions: 267 // 268 269 // A counter data file is composed of a file header followed by one or 270 // more "segments" (each segment representing a given run or partial 271 // run of a give binary) followed by a footer. 272 273 // CovCounterMagic holds the magic string for a coverage counter-data file. 274 var CovCounterMagic = [4]byte{'\x00', '\x63', '\x77', '\x6d'} 275 276 // CounterFileVersion stores the most recent counter data file version. 277 const CounterFileVersion = 1 278 279 // CounterFileHeader stores files header information for a counter-data file. 280 type CounterFileHeader struct { 281 Magic [4]byte 282 Version uint32 283 MetaHash [16]byte 284 CFlavor CounterFlavor 285 BigEndian bool 286 _ [6]byte // padding 287 } 288 289 // CounterSegmentHeader encapsulates information about a specific 290 // segment in a counter data file, which at the moment contains 291 // counters data from a single execution of a coverage-instrumented 292 // program. Following the segment header will be the string table and 293 // args table, and then (possibly) padding bytes to bring the byte 294 // size of the preamble up to a multiple of 4. Immediately following 295 // that will be the counter payloads. 296 // 297 // The "args" section of a segment is used to store annotations 298 // describing where the counter data came from; this section is 299 // basically a series of key-value pairs (can be thought of as an 300 // encoded 'map[string]string'). At the moment we only write os.Args() 301 // data to this section, using pairs of the form "argc=<integer>", 302 // "argv0=<os.Args[0]>", "argv1=<os.Args[1]>", and so on. In the 303 // future the args table may also include things like GOOS/GOARCH 304 // values, and/or tags indicating which tests were run to generate the 305 // counter data. 306 type CounterSegmentHeader struct { 307 FcnEntries uint64 308 StrTabLen uint32 309 ArgsLen uint32 310 } 311 312 // CounterFileFooter appears at the tail end of a counter data file, 313 // and stores the number of segments it contains. 314 type CounterFileFooter struct { 315 Magic [4]byte 316 _ [4]byte // padding 317 NumSegments uint32 318 _ [4]byte // padding 319 } 320 321 // CounterFilePref is the file prefix used when emitting coverage data 322 // output files. CounterFileTemplate describes the format of the file 323 // name: prefix followed by meta-file hash followed by process ID 324 // followed by emit UnixNanoTime. 325 const CounterFilePref = "covcounters" 326 const CounterFileTempl = "%s.%x.%d.%d" 327 const CounterFileRegexp = `^%s\.(\S+)\.(\d+)\.(\d+)+$` 328 329 // CounterFlavor describes how function and counters are 330 // stored/represented in the counter section of the file. 331 type CounterFlavor uint8 332 333 const ( 334 // "Raw" representation: all values (pkg ID, func ID, num counters, 335 // and counters themselves) are stored as uint32's. 336 CtrRaw CounterFlavor = iota + 1 337 338 // "ULeb" representation: all values (pkg ID, func ID, num counters, 339 // and counters themselves) are stored with ULEB128 encoding. 340 CtrULeb128 341 ) 342 343 func Round4(x int) int { 344 return (x + 3) &^ 3 345 } 346 347 //..................................................................... 348 // 349 // Runtime counter data definitions. 350 // 351 352 // At runtime within a coverage-instrumented program, the "counters" 353 // object we associated with instrumented function can be thought of 354 // as a struct of the following form: 355 // 356 // struct { 357 // numCtrs uint32 358 // pkgid uint32 359 // funcid uint32 360 // counterArray [numBlocks]uint32 361 // } 362 // 363 // where "numCtrs" is the number of blocks / coverable units within the 364 // function, "pkgid" is the unique index assigned to this package by 365 // the runtime, "funcid" is the index of this function within its containing 366 // package, and "counterArray" stores the actual counters. 367 // 368 // The counter variable itself is created not as a struct but as a flat 369 // array of uint32's; we then use the offsets below to index into it. 370 371 const NumCtrsOffset = 0 372 const PkgIdOffset = 1 373 const FuncIdOffset = 2 374 const FirstCtrOffset = 3