/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/XRayArgs.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- XRayArgs.cpp - Arguments for XRay --------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | #include "clang/Driver/XRayArgs.h" |
9 | | #include "ToolChains/CommonArgs.h" |
10 | | #include "clang/Driver/Driver.h" |
11 | | #include "clang/Driver/DriverDiagnostic.h" |
12 | | #include "clang/Driver/Options.h" |
13 | | #include "clang/Driver/ToolChain.h" |
14 | | #include "llvm/ADT/StringExtras.h" |
15 | | #include "llvm/ADT/StringSwitch.h" |
16 | | #include "llvm/Support/Path.h" |
17 | | #include "llvm/Support/ScopedPrinter.h" |
18 | | #include "llvm/Support/SpecialCaseList.h" |
19 | | #include "llvm/Support/VirtualFileSystem.h" |
20 | | |
21 | | using namespace clang; |
22 | | using namespace clang::driver; |
23 | | using namespace llvm::opt; |
24 | | |
25 | | namespace { |
26 | | constexpr char XRayInstrumentOption[] = "-fxray-instrument"; |
27 | | constexpr char XRayInstructionThresholdOption[] = |
28 | | "-fxray-instruction-threshold="; |
29 | | constexpr const char *const XRaySupportedModes[] = {"xray-fdr", "xray-basic"}; |
30 | | } // namespace |
31 | | |
32 | 46.5k | XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { |
33 | 46.5k | const Driver &D = TC.getDriver(); |
34 | 46.5k | const llvm::Triple &Triple = TC.getTriple(); |
35 | 46.5k | if (!Args.hasFlag(options::OPT_fxray_instrument, |
36 | 46.5k | options::OPT_fno_xray_instrument, false)) |
37 | 46.5k | return; |
38 | 9 | if (Triple.getOS() == llvm::Triple::Linux) { |
39 | 3 | switch (Triple.getArch()) { |
40 | 2 | case llvm::Triple::x86_64: |
41 | 2 | case llvm::Triple::arm: |
42 | 3 | case llvm::Triple::aarch64: |
43 | 3 | case llvm::Triple::ppc64le: |
44 | 3 | case llvm::Triple::mips: |
45 | 3 | case llvm::Triple::mipsel: |
46 | 3 | case llvm::Triple::mips64: |
47 | 3 | case llvm::Triple::mips64el: |
48 | 3 | break; |
49 | 0 | default: |
50 | 0 | D.Diag(diag::err_drv_clang_unsupported) |
51 | 0 | << (std::string(XRayInstrumentOption) + " on " + Triple.str()); |
52 | 3 | } |
53 | 8 | } else if (6 Triple.isOSFreeBSD()6 || Triple.isOSOpenBSD() || |
54 | 8 | Triple.isOSNetBSD() || Triple.isMacOSX()) { |
55 | 3 | if (Triple.getArch() != llvm::Triple::x86_64) { |
56 | 0 | D.Diag(diag::err_drv_clang_unsupported) |
57 | 0 | << (std::string(XRayInstrumentOption) + " on " + Triple.str()); |
58 | 0 | } |
59 | 3 | } else if (Triple.getOS() == llvm::Triple::Fuchsia) { |
60 | 2 | switch (Triple.getArch()) { |
61 | 1 | case llvm::Triple::x86_64: |
62 | 2 | case llvm::Triple::aarch64: |
63 | 2 | break; |
64 | 0 | default: |
65 | 0 | D.Diag(diag::err_drv_clang_unsupported) |
66 | 0 | << (std::string(XRayInstrumentOption) + " on " + Triple.str()); |
67 | 2 | } |
68 | 1 | } else { |
69 | 1 | D.Diag(diag::err_drv_clang_unsupported) |
70 | 1 | << (std::string(XRayInstrumentOption) + " on " + Triple.str()); |
71 | 1 | } |
72 | | |
73 | | // Both XRay and -fpatchable-function-entry use |
74 | | // TargetOpcode::PATCHABLE_FUNCTION_ENTER. |
75 | 9 | if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) |
76 | 1 | D.Diag(diag::err_drv_argument_not_allowed_with) |
77 | 1 | << "-fxray-instrument" << A->getSpelling(); |
78 | | |
79 | 9 | XRayInstrument = true; |
80 | 9 | if (const Arg *A = |
81 | 0 | Args.getLastArg(options::OPT_fxray_instruction_threshold_, |
82 | 0 | options::OPT_fxray_instruction_threshold_EQ)) { |
83 | 0 | StringRef S = A->getValue(); |
84 | 0 | if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0) |
85 | 0 | D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; |
86 | 0 | } |
87 | | |
88 | | // By default, the back-end will not emit the lowering for XRay customevent |
89 | | // calls if the function is not instrumented. In the future we will change |
90 | | // this default to be the reverse, but in the meantime we're going to |
91 | | // introduce the new functionality behind a flag. |
92 | 9 | if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, |
93 | 9 | options::OPT_fno_xray_always_emit_customevents, false)) |
94 | 0 | XRayAlwaysEmitCustomEvents = true; |
95 | | |
96 | 9 | if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents, |
97 | 9 | options::OPT_fno_xray_always_emit_typedevents, false)) |
98 | 0 | XRayAlwaysEmitTypedEvents = true; |
99 | | |
100 | 9 | if (!Args.hasFlag(options::OPT_fxray_link_deps, |
101 | 9 | options::OPT_fnoxray_link_deps, true)) |
102 | 0 | XRayRT = false; |
103 | | |
104 | 9 | if (Args.hasFlag(options::OPT_fxray_ignore_loops, |
105 | 9 | options::OPT_fno_xray_ignore_loops, false)) |
106 | 1 | XRayIgnoreLoops = true; |
107 | | |
108 | 9 | XRayFunctionIndex = Args.hasFlag(options::OPT_fxray_function_index, |
109 | 9 | options::OPT_fno_xray_function_index, true); |
110 | | |
111 | 9 | auto Bundles = |
112 | 9 | Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); |
113 | 9 | if (Bundles.empty()) |
114 | 11 | InstrumentationBundle.Mask = XRayInstrKind::All; |
115 | 18.4E | else |
116 | 18.4E | for (const auto &B : Bundles) { |
117 | 0 | llvm::SmallVector<StringRef, 2> BundleParts; |
118 | 0 | llvm::SplitString(B, BundleParts, ","); |
119 | 0 | for (const auto &P : BundleParts) { |
120 | | // TODO: Automate the generation of the string case table. |
121 | 0 | auto Valid = llvm::StringSwitch<bool>(P) |
122 | 0 | .Cases("none", "all", "function", "function-entry", |
123 | 0 | "function-exit", "custom", true) |
124 | 0 | .Default(false); |
125 | |
|
126 | 0 | if (!Valid) { |
127 | 0 | D.Diag(clang::diag::err_drv_invalid_value) |
128 | 0 | << "-fxray-instrumentation-bundle=" << P; |
129 | 0 | continue; |
130 | 0 | } |
131 | | |
132 | 0 | auto Mask = parseXRayInstrValue(P); |
133 | 0 | if (Mask == XRayInstrKind::None) { |
134 | 0 | InstrumentationBundle.clear(); |
135 | 0 | break; |
136 | 0 | } |
137 | | |
138 | 0 | InstrumentationBundle.Mask |= Mask; |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | | // Validate the always/never attribute files. We also make sure that they |
143 | | // are treated as actual dependencies. |
144 | 9 | for (const auto &Filename : |
145 | 1 | Args.getAllArgValues(options::OPT_fxray_always_instrument)) { |
146 | 1 | if (D.getVFS().exists(Filename)) { |
147 | 1 | AlwaysInstrumentFiles.push_back(Filename); |
148 | 1 | ExtraDeps.push_back(Filename); |
149 | 1 | } else |
150 | 0 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
151 | 1 | } |
152 | | |
153 | 9 | for (const auto &Filename : |
154 | 1 | Args.getAllArgValues(options::OPT_fxray_never_instrument)) { |
155 | 1 | if (D.getVFS().exists(Filename)) { |
156 | 1 | NeverInstrumentFiles.push_back(Filename); |
157 | 1 | ExtraDeps.push_back(Filename); |
158 | 1 | } else |
159 | 0 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
160 | 1 | } |
161 | | |
162 | 9 | for (const auto &Filename : |
163 | 1 | Args.getAllArgValues(options::OPT_fxray_attr_list)) { |
164 | 1 | if (D.getVFS().exists(Filename)) { |
165 | 1 | AttrListFiles.push_back(Filename); |
166 | 1 | ExtraDeps.push_back(Filename); |
167 | 1 | } else |
168 | 0 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
169 | 1 | } |
170 | | |
171 | | // Get the list of modes we want to support. |
172 | 9 | auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes); |
173 | 9 | if (SpecifiedModes.empty()) |
174 | 9 | llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); |
175 | 0 | else |
176 | 2 | for (const auto &Arg : SpecifiedModes)0 { |
177 | | // Parse CSV values for -fxray-modes=... |
178 | 2 | llvm::SmallVector<StringRef, 2> ModeParts; |
179 | 2 | llvm::SplitString(Arg, ModeParts, ","); |
180 | 2 | for (const auto &M : ModeParts) |
181 | 2 | if (M == "none") |
182 | 0 | Modes.clear(); |
183 | 2 | else if (M == "all") |
184 | 0 | llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); |
185 | 2 | else |
186 | 2 | Modes.push_back(std::string(M)); |
187 | 2 | } |
188 | | |
189 | 9 | if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) { |
190 | 0 | StringRef S = A->getValue(); |
191 | 0 | if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1) |
192 | 0 | D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; |
193 | 0 | } |
194 | | |
195 | 9 | if (const Arg *A = |
196 | 0 | Args.getLastArg(options::OPT_fxray_selected_function_group)) { |
197 | 0 | StringRef S = A->getValue(); |
198 | 0 | if (S.getAsInteger(0, XRaySelectedFunctionGroup) || |
199 | 0 | XRaySelectedFunctionGroup < 0 || |
200 | 0 | XRaySelectedFunctionGroup >= XRayFunctionGroups) |
201 | 0 | D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; |
202 | 0 | } |
203 | | |
204 | | // Then we want to sort and unique the modes we've collected. |
205 | 9 | llvm::sort(Modes); |
206 | 9 | Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); |
207 | 9 | } |
208 | | |
209 | | void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, |
210 | 44.3k | ArgStringList &CmdArgs, types::ID InputType) const { |
211 | 44.3k | if (!XRayInstrument) |
212 | 44.3k | return; |
213 | | |
214 | 12 | CmdArgs.push_back(XRayInstrumentOption); |
215 | | |
216 | 12 | if (XRayAlwaysEmitCustomEvents) |
217 | 0 | CmdArgs.push_back("-fxray-always-emit-customevents"); |
218 | | |
219 | 12 | if (XRayAlwaysEmitTypedEvents) |
220 | 0 | CmdArgs.push_back("-fxray-always-emit-typedevents"); |
221 | | |
222 | 12 | if (XRayIgnoreLoops) |
223 | 1 | CmdArgs.push_back("-fxray-ignore-loops"); |
224 | | |
225 | 12 | if (!XRayFunctionIndex) |
226 | 1 | CmdArgs.push_back("-fno-xray-function-index"); |
227 | | |
228 | 12 | if (XRayFunctionGroups > 1) { |
229 | 0 | CmdArgs.push_back(Args.MakeArgString(Twine("-fxray-function-groups=") + |
230 | 0 | Twine(XRayFunctionGroups))); |
231 | 0 | } |
232 | | |
233 | 12 | if (XRaySelectedFunctionGroup != 0) { |
234 | 0 | CmdArgs.push_back( |
235 | 0 | Args.MakeArgString(Twine("-fxray-selected-function-group=") + |
236 | 0 | Twine(XRaySelectedFunctionGroup))); |
237 | 0 | } |
238 | | |
239 | 12 | CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + |
240 | 12 | Twine(InstructionThreshold))); |
241 | | |
242 | 1 | for (const auto &Always : AlwaysInstrumentFiles) { |
243 | 1 | SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); |
244 | 1 | AlwaysInstrumentOpt += Always; |
245 | 1 | CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); |
246 | 1 | } |
247 | | |
248 | 1 | for (const auto &Never : NeverInstrumentFiles) { |
249 | 1 | SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); |
250 | 1 | NeverInstrumentOpt += Never; |
251 | 1 | CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); |
252 | 1 | } |
253 | | |
254 | 1 | for (const auto &AttrFile : AttrListFiles) { |
255 | 1 | SmallString<64> AttrListFileOpt("-fxray-attr-list="); |
256 | 1 | AttrListFileOpt += AttrFile; |
257 | 1 | CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt)); |
258 | 1 | } |
259 | | |
260 | 3 | for (const auto &Dep : ExtraDeps) { |
261 | 3 | SmallString<64> ExtraDepOpt("-fdepfile-entry="); |
262 | 3 | ExtraDepOpt += Dep; |
263 | 3 | CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); |
264 | 3 | } |
265 | | |
266 | 20 | for (const auto &Mode : Modes) { |
267 | 20 | SmallString<64> ModeOpt("-fxray-modes="); |
268 | 20 | ModeOpt += Mode; |
269 | 20 | CmdArgs.push_back(Args.MakeArgString(ModeOpt)); |
270 | 20 | } |
271 | | |
272 | 12 | SmallString<64> Bundle("-fxray-instrumentation-bundle="); |
273 | 12 | if (InstrumentationBundle.full()) { |
274 | 11 | Bundle += "all"; |
275 | 1 | } else if (InstrumentationBundle.empty()) { |
276 | 0 | Bundle += "none"; |
277 | 1 | } else { |
278 | 1 | if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry) && |
279 | 0 | InstrumentationBundle.has(XRayInstrKind::FunctionExit)) |
280 | 0 | Bundle += "function"; |
281 | 1 | else if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry)) |
282 | 0 | Bundle += "function-entry"; |
283 | 1 | else if (InstrumentationBundle.has(XRayInstrKind::FunctionExit)) |
284 | 0 | Bundle += "function-exit"; |
285 | | |
286 | 1 | if (InstrumentationBundle.has(XRayInstrKind::Custom)) |
287 | 0 | Bundle += "custom"; |
288 | 1 | if (InstrumentationBundle.has(XRayInstrKind::Typed)) |
289 | 0 | Bundle += "typed"; |
290 | 1 | } |
291 | 12 | CmdArgs.push_back(Args.MakeArgString(Bundle)); |
292 | 12 | } |