1// Copyright 2023 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 objabi
6
7import "sync"
8
9// PkgSpecial indicates special build properties of a given runtime-related
10// package.
11type PkgSpecial struct {
12	// Runtime indicates that this package is "runtime" or imported by
13	// "runtime". This has several effects (which maybe should be split out):
14	//
15	// - Implicit allocation is disallowed.
16	//
17	// - Various runtime pragmas are enabled.
18	//
19	// - Optimizations are always enabled.
20	//
21	// - Checkptr is always disabled.
22	//
23	// This should be set for runtime and all packages it imports, and may be
24	// set for additional packages.
25	Runtime bool
26
27	// NoInstrument indicates this package should not receive sanitizer
28	// instrumentation. In many of these, instrumentation could cause infinite
29	// recursion. This is all runtime packages, plus those that support the
30	// sanitizers.
31	NoInstrument bool
32
33	// NoRaceFunc indicates functions in this package should not get
34	// racefuncenter/racefuncexit instrumentation Memory accesses in these
35	// packages are either uninteresting or will cause false positives.
36	NoRaceFunc bool
37
38	// AllowAsmABI indicates that assembly in this package is allowed to use ABI
39	// selectors in symbol names. Generally this is needed for packages that
40	// interact closely with the runtime package or have performance-critical
41	// assembly.
42	AllowAsmABI bool
43}
44
45var runtimePkgs = []string{
46	"runtime",
47
48	"internal/runtime/atomic",
49	"internal/runtime/exithook",
50	"runtime/internal/math",
51	"runtime/internal/sys",
52	"internal/runtime/syscall",
53
54	"internal/abi",
55	"internal/bytealg",
56	"internal/byteorder",
57	"internal/chacha8rand",
58	"internal/coverage/rtcov",
59	"internal/cpu",
60	"internal/goarch",
61	"internal/godebugs",
62	"internal/goexperiment",
63	"internal/goos",
64	"internal/profilerecord",
65	"internal/stringslite",
66}
67
68// extraNoInstrumentPkgs is the set of packages in addition to runtimePkgs that
69// should have NoInstrument set.
70var extraNoInstrumentPkgs = []string{
71	"runtime/race",
72	"runtime/msan",
73	"runtime/asan",
74	// We omit bytealg even though it's imported by runtime because it also
75	// backs a lot of package bytes. Currently we don't have a way to omit race
76	// instrumentation when used from the runtime while keeping race
77	// instrumentation when used from user code. Somehow this doesn't seem to
78	// cause problems, though we may be skating on thin ice. See #61204.
79	"-internal/bytealg",
80}
81
82var noRaceFuncPkgs = []string{"sync", "sync/atomic", "internal/runtime/atomic"}
83
84var allowAsmABIPkgs = []string{
85	"runtime",
86	"reflect",
87	"syscall",
88	"internal/bytealg",
89	"internal/chacha8rand",
90	"internal/runtime/syscall",
91	"runtime/internal/startlinetest",
92}
93
94var (
95	pkgSpecials     map[string]PkgSpecial
96	pkgSpecialsOnce sync.Once
97)
98
99// LookupPkgSpecial returns special build properties for the given package path.
100func LookupPkgSpecial(pkgPath string) PkgSpecial {
101	pkgSpecialsOnce.Do(func() {
102		// Construct pkgSpecials from various package lists. This lets us use
103		// more flexible logic, while keeping the final map simple, and avoids
104		// the init-time cost of a map.
105		pkgSpecials = make(map[string]PkgSpecial)
106		set := func(elt string, f func(*PkgSpecial)) {
107			s := pkgSpecials[elt]
108			f(&s)
109			pkgSpecials[elt] = s
110		}
111		for _, pkg := range runtimePkgs {
112			set(pkg, func(ps *PkgSpecial) { ps.Runtime = true; ps.NoInstrument = true })
113		}
114		for _, pkg := range extraNoInstrumentPkgs {
115			if pkg[0] == '-' {
116				set(pkg[1:], func(ps *PkgSpecial) { ps.NoInstrument = false })
117			} else {
118				set(pkg, func(ps *PkgSpecial) { ps.NoInstrument = true })
119			}
120		}
121		for _, pkg := range noRaceFuncPkgs {
122			set(pkg, func(ps *PkgSpecial) { ps.NoRaceFunc = true })
123		}
124		for _, pkg := range allowAsmABIPkgs {
125			set(pkg, func(ps *PkgSpecial) { ps.AllowAsmABI = true })
126		}
127	})
128	return pkgSpecials[pkgPath]
129}
130