Source file src/internal/coverage/defs.go

     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  // MetaFilePaths 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  

View as plain text