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 5package 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. 56var 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. 62const MetaFilePref = "covmeta" 63 64// MetaFileVersion contains the current (most recent) meta-data file version. 65const MetaFileVersion = 1 66 67// MetaFileHeader stores file header information for a meta-data file. 68type 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. 84type 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 96const 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. 161type 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. 189type 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. 198type CounterMode uint8 199 200const ( 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 209func (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 225func 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. 246type CounterGranularity uint8 247 248const ( 249 CtrGranularityInvalid CounterGranularity = iota 250 CtrGranularityPerBlock 251 CtrGranularityPerFunc 252) 253 254func (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. 268const 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. 273type 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. 288var CovCounterMagic = [4]byte{'\x00', '\x63', '\x77', '\x6d'} 289 290// CounterFileVersion stores the most recent counter data file version. 291const CounterFileVersion = 1 292 293// CounterFileHeader stores files header information for a counter-data file. 294type 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. 320type 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. 328type 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. 339const CounterFilePref = "covcounters" 340const CounterFileTempl = "%s.%x.%d.%d" 341const CounterFileRegexp = `^%s\.(\S+)\.(\d+)\.(\d+)+$` 342 343// CounterFlavor describes how function and counters are 344// stored/represented in the counter section of the file. 345type CounterFlavor uint8 346 347const ( 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 357func 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 385const NumCtrsOffset = 0 386const PkgIdOffset = 1 387const FuncIdOffset = 2 388const FirstCtrOffset = 3 389