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// Building the runtime package with coverage instrumentation enabled
8// is tricky.  For all other packages, you can be guaranteed that
9// the package init function is run before any functions are executed,
10// but this invariant is not maintained for packages such as "runtime",
11// "internal/cpu", etc. To handle this, hard-code the package ID for
12// the set of packages whose functions may be running before the
13// init function of the package is complete.
14//
15// Hardcoding is unfortunate because it means that the tool that does
16// coverage instrumentation has to keep a list of runtime packages,
17// meaning that if someone makes changes to the pkg "runtime"
18// dependencies, unexpected behavior will result for coverage builds.
19// The coverage runtime will detect and report the unexpected
20// behavior; look for an error of this form:
21//
22//    internal error in coverage meta-data tracking:
23//    list of hard-coded runtime package IDs needs revising.
24//    registered list:
25//    slot: 0 path='internal/cpu'  hard-coded id: 1
26//    slot: 1 path='internal/goarch'  hard-coded id: 2
27//    slot: 2 path='internal/runtime/atomic'  hard-coded id: 3
28//    slot: 3 path='internal/goos'
29//    slot: 4 path='runtime/internal/sys'  hard-coded id: 5
30//    slot: 5 path='internal/abi'  hard-coded id: 4
31//    slot: 6 path='runtime/internal/math'  hard-coded id: 6
32//    slot: 7 path='internal/bytealg'  hard-coded id: 7
33//    slot: 8 path='internal/goexperiment'
34//    slot: 9 path='internal/runtime/syscall'  hard-coded id: 8
35//    slot: 10 path='runtime'  hard-coded id: 9
36//    fatal error: runtime.addCovMeta
37//
38// For the error above, the hard-coded list is missing "internal/goos"
39// and "internal/goexperiment" ; the developer in question will need
40// to copy the list above into "rtPkgs" below.
41//
42// Note: this strategy assumes that the list of dependencies of
43// package runtime is fixed, and doesn't vary depending on OS/arch. If
44// this were to be the case, we would need a table of some sort below
45// as opposed to a fixed list.
46
47var rtPkgs = [...]string{
48	"internal/cpu",
49	"internal/goarch",
50	"internal/runtime/atomic",
51	"internal/goos",
52	"internal/chacha8rand",
53	"runtime/internal/sys",
54	"internal/abi",
55	"runtime/internal/math",
56	"internal/bytealg",
57	"internal/goexperiment",
58	"internal/runtime/syscall",
59	"runtime",
60}
61
62// Scoping note: the constants and apis in this file are internal
63// only, not expected to ever be exposed outside of the runtime (unlike
64// other coverage file formats and APIs, which will likely be shared
65// at some point).
66
67// NotHardCoded is a package pseudo-ID indicating that a given package
68// is not part of the runtime and doesn't require a hard-coded ID.
69const NotHardCoded = -1
70
71// HardCodedPkgID returns the hard-coded ID for the specified package
72// path, or -1 if we don't use a hard-coded ID. Hard-coded IDs start
73// at -2 and decrease as we go down the list.
74func HardCodedPkgID(pkgpath string) int {
75	for k, p := range rtPkgs {
76		if p == pkgpath {
77			return (0 - k) - 2
78		}
79	}
80	return NotHardCoded
81}
82