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 rtcov
6
7import "unsafe"
8
9// This package contains types whose structure is shared between
10// the runtime package and the "runtime/coverage" implementation.
11
12// CovMetaBlob is a container for holding the meta-data symbol (an
13// RODATA variable) for an instrumented Go package. Here "p" points to
14// the symbol itself, "len" is the length of the sym in bytes, and
15// "hash" is an md5sum for the sym computed by the compiler. When
16// the init function for a coverage-instrumented package executes, it
17// will make a call into the runtime which will create a covMetaBlob
18// object for the package and chain it onto a global list.
19type CovMetaBlob struct {
20	P                  *byte
21	Len                uint32
22	Hash               [16]byte
23	PkgPath            string
24	PkgID              int
25	CounterMode        uint8 // coverage.CounterMode
26	CounterGranularity uint8 // coverage.CounterGranularity
27}
28
29// CovCounterBlob is a container for encapsulating a counter section
30// (BSS variable) for an instrumented Go module. Here "counters"
31// points to the counter payload and "len" is the number of uint32
32// entries in the section.
33type CovCounterBlob struct {
34	Counters *uint32
35	Len      uint64
36}
37
38// Meta is the top-level container for bits of state related to
39// code coverage meta-data in the runtime.
40var Meta struct {
41	// List contains the list of currently registered meta-data
42	// blobs for the running program.
43	List []CovMetaBlob
44
45	// PkgMap records mappings from hard-coded package IDs to
46	// slots in the List above.
47	PkgMap map[int]int
48
49	// Set to true if we discover a package mapping glitch.
50	hardCodedListNeedsUpdating bool
51}
52
53// AddMeta is invoked during package "init" functions by the
54// compiler when compiling for coverage instrumentation; here 'p' is a
55// meta-data blob of length 'dlen' for the package in question, 'hash'
56// is a compiler-computed md5.sum for the blob, 'pkpath' is the
57// package path, 'pkid' is the hard-coded ID that the compiler is
58// using for the package (or -1 if the compiler doesn't think a
59// hard-coded ID is needed), and 'cmode'/'cgran' are the coverage
60// counter mode and granularity requested by the user. Return value is
61// the ID for the package for use by the package code itself,
62// or 0 for impossible errors.
63func AddMeta(p unsafe.Pointer, dlen uint32, hash [16]byte, pkgpath string, pkgid int, cmode uint8, cgran uint8) uint32 {
64	slot := len(Meta.List)
65	Meta.List = append(Meta.List, CovMetaBlob{
66		P:                  (*byte)(p),
67		Len:                dlen,
68		Hash:               hash,
69		PkgPath:            pkgpath,
70		PkgID:              pkgid,
71		CounterMode:        cmode,
72		CounterGranularity: cgran,
73	})
74	if pkgid != -1 {
75		if Meta.PkgMap == nil {
76			Meta.PkgMap = make(map[int]int)
77		}
78		if _, ok := Meta.PkgMap[pkgid]; ok {
79			return 0
80		}
81		// Record the real slot (position on meta-list) for this
82		// package; we'll use the map to fix things up later on.
83		Meta.PkgMap[pkgid] = slot
84	}
85
86	// ID zero is reserved as invalid.
87	return uint32(slot + 1)
88}
89