defs.mx raw

   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