/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 | | constexpr const char *XRaySupportedModes[] = {"xray-fdr", "xray-basic"}; |
26 | | |
27 | 49.9k | XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { |
28 | 49.9k | const Driver &D = TC.getDriver(); |
29 | 49.9k | const llvm::Triple &Triple = TC.getTriple(); |
30 | 49.9k | if (!Args.hasFlag(options::OPT_fxray_instrument, |
31 | 49.9k | options::OPT_fno_xray_instrument, false)) |
32 | 49.9k | return; |
33 | 28 | XRayInstrument = Args.getLastArg(options::OPT_fxray_instrument); |
34 | 28 | if (Triple.isMacOSX()) { |
35 | 2 | switch (Triple.getArch()) { |
36 | 1 | case llvm::Triple::aarch64: |
37 | 2 | case llvm::Triple::x86_64: |
38 | 2 | break; |
39 | 0 | default: |
40 | 0 | D.Diag(diag::err_drv_unsupported_opt_for_target) |
41 | 0 | << XRayInstrument->getSpelling() << Triple.str(); |
42 | 0 | break; |
43 | 2 | } |
44 | 26 | } else if (Triple.isOSBinFormatELF()) { |
45 | 25 | switch (Triple.getArch()) { |
46 | 17 | case llvm::Triple::x86_64: |
47 | 18 | case llvm::Triple::arm: |
48 | 25 | case llvm::Triple::aarch64: |
49 | 25 | case llvm::Triple::hexagon: |
50 | 25 | case llvm::Triple::ppc64le: |
51 | 25 | case llvm::Triple::loongarch64: |
52 | 25 | case llvm::Triple::mips: |
53 | 25 | case llvm::Triple::mipsel: |
54 | 25 | case llvm::Triple::mips64: |
55 | 25 | case llvm::Triple::mips64el: |
56 | 25 | break; |
57 | 0 | default: |
58 | 0 | D.Diag(diag::err_drv_unsupported_opt_for_target) |
59 | 0 | << XRayInstrument->getSpelling() << Triple.str(); |
60 | 25 | } |
61 | 25 | } else { |
62 | 1 | D.Diag(diag::err_drv_unsupported_opt_for_target) |
63 | 1 | << XRayInstrument->getSpelling() << Triple.str(); |
64 | 1 | } |
65 | | |
66 | | // Both XRay and -fpatchable-function-entry use |
67 | | // TargetOpcode::PATCHABLE_FUNCTION_ENTER. |
68 | 28 | if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) |
69 | 1 | D.Diag(diag::err_drv_argument_not_allowed_with) |
70 | 1 | << XRayInstrument->getSpelling() << A->getSpelling(); |
71 | | |
72 | 28 | if (!Args.hasFlag(options::OPT_fxray_link_deps, |
73 | 28 | options::OPT_fno_xray_link_deps, true)) |
74 | 1 | XRayRT = false; |
75 | | |
76 | 28 | auto Bundles = |
77 | 28 | Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); |
78 | 28 | if (Bundles.empty()) |
79 | 27 | InstrumentationBundle.Mask = XRayInstrKind::All; |
80 | 1 | else |
81 | 1 | for (const auto &B : Bundles) { |
82 | 1 | llvm::SmallVector<StringRef, 2> BundleParts; |
83 | 1 | llvm::SplitString(B, BundleParts, ","); |
84 | 1 | for (const auto &P : BundleParts) { |
85 | | // TODO: Automate the generation of the string case table. |
86 | 1 | auto Valid = llvm::StringSwitch<bool>(P) |
87 | 1 | .Cases("none", "all", "function", "function-entry", |
88 | 1 | "function-exit", "custom", true) |
89 | 1 | .Default(false); |
90 | | |
91 | 1 | if (!Valid) { |
92 | 0 | D.Diag(clang::diag::err_drv_invalid_value) |
93 | 0 | << "-fxray-instrumentation-bundle=" << P; |
94 | 0 | continue; |
95 | 0 | } |
96 | | |
97 | 1 | auto Mask = parseXRayInstrValue(P); |
98 | 1 | if (Mask == XRayInstrKind::None) { |
99 | 0 | InstrumentationBundle.clear(); |
100 | 0 | break; |
101 | 0 | } |
102 | | |
103 | 1 | InstrumentationBundle.Mask |= Mask; |
104 | 1 | } |
105 | 1 | } |
106 | | |
107 | | // Validate the always/never attribute files. We also make sure that they |
108 | | // are treated as actual dependencies. |
109 | 28 | for (const auto &Filename : |
110 | 28 | Args.getAllArgValues(options::OPT_fxray_always_instrument)) { |
111 | 1 | if (D.getVFS().exists(Filename)) { |
112 | 1 | AlwaysInstrumentFiles.push_back(Filename); |
113 | 1 | ExtraDeps.push_back(Filename); |
114 | 1 | } else |
115 | 0 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
116 | 1 | } |
117 | | |
118 | 28 | for (const auto &Filename : |
119 | 28 | Args.getAllArgValues(options::OPT_fxray_never_instrument)) { |
120 | 1 | if (D.getVFS().exists(Filename)) { |
121 | 1 | NeverInstrumentFiles.push_back(Filename); |
122 | 1 | ExtraDeps.push_back(Filename); |
123 | 1 | } else |
124 | 0 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
125 | 1 | } |
126 | | |
127 | 28 | for (const auto &Filename : |
128 | 28 | Args.getAllArgValues(options::OPT_fxray_attr_list)) { |
129 | 1 | if (D.getVFS().exists(Filename)) { |
130 | 1 | AttrListFiles.push_back(Filename); |
131 | 1 | ExtraDeps.push_back(Filename); |
132 | 1 | } else |
133 | 0 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
134 | 1 | } |
135 | | |
136 | | // Get the list of modes we want to support. |
137 | 28 | auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes); |
138 | 28 | if (SpecifiedModes.empty()) |
139 | 16 | llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); |
140 | 12 | else |
141 | 14 | for (const auto &Arg : SpecifiedModes)12 { |
142 | | // Parse CSV values for -fxray-modes=... |
143 | 14 | llvm::SmallVector<StringRef, 2> ModeParts; |
144 | 14 | llvm::SplitString(Arg, ModeParts, ","); |
145 | 14 | for (const auto &M : ModeParts) |
146 | 17 | if (M == "none") |
147 | 4 | Modes.clear(); |
148 | 13 | else if (M == "all") |
149 | 2 | llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); |
150 | 11 | else |
151 | 11 | Modes.push_back(std::string(M)); |
152 | 14 | } |
153 | | |
154 | | // Then we want to sort and unique the modes we've collected. |
155 | 28 | llvm::sort(Modes); |
156 | 28 | Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); |
157 | 28 | } |
158 | | |
159 | | void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, |
160 | 47.7k | ArgStringList &CmdArgs, types::ID InputType) const { |
161 | 47.7k | if (!XRayInstrument) |
162 | 47.7k | return; |
163 | 33 | const Driver &D = TC.getDriver(); |
164 | 33 | XRayInstrument->render(Args, CmdArgs); |
165 | | |
166 | | // By default, the back-end will not emit the lowering for XRay customevent |
167 | | // calls if the function is not instrumented. In the future we will change |
168 | | // this default to be the reverse, but in the meantime we're going to |
169 | | // introduce the new functionality behind a flag. |
170 | 33 | Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_customevents, |
171 | 33 | options::OPT_fno_xray_always_emit_customevents); |
172 | | |
173 | 33 | Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_typedevents, |
174 | 33 | options::OPT_fno_xray_always_emit_typedevents); |
175 | 33 | Args.addOptInFlag(CmdArgs, options::OPT_fxray_ignore_loops, |
176 | 33 | options::OPT_fno_xray_ignore_loops); |
177 | 33 | Args.addOptOutFlag(CmdArgs, options::OPT_fxray_function_index, |
178 | 33 | options::OPT_fno_xray_function_index); |
179 | | |
180 | 33 | if (const Arg *A = |
181 | 33 | Args.getLastArg(options::OPT_fxray_instruction_threshold_EQ)) { |
182 | 0 | int Value; |
183 | 0 | StringRef S = A->getValue(); |
184 | 0 | if (S.getAsInteger(0, Value) || Value < 0) |
185 | 0 | D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; |
186 | 0 | else |
187 | 0 | A->render(Args, CmdArgs); |
188 | 0 | } |
189 | | |
190 | 33 | int XRayFunctionGroups = 1; |
191 | 33 | int XRaySelectedFunctionGroup = 0; |
192 | 33 | if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) { |
193 | 3 | StringRef S = A->getValue(); |
194 | 3 | if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1) |
195 | 0 | D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; |
196 | 3 | if (XRayFunctionGroups > 1) |
197 | 3 | A->render(Args, CmdArgs); |
198 | 3 | } |
199 | 33 | if (const Arg *A = |
200 | 33 | Args.getLastArg(options::OPT_fxray_selected_function_group)) { |
201 | 2 | StringRef S = A->getValue(); |
202 | 2 | if (S.getAsInteger(0, XRaySelectedFunctionGroup) || |
203 | 2 | XRaySelectedFunctionGroup < 0 || |
204 | 2 | XRaySelectedFunctionGroup >= XRayFunctionGroups) |
205 | 0 | D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; |
206 | 2 | if (XRaySelectedFunctionGroup != 0) |
207 | 1 | A->render(Args, CmdArgs); |
208 | 2 | } |
209 | | |
210 | 33 | for (const auto &Always : AlwaysInstrumentFiles) { |
211 | 1 | SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); |
212 | 1 | AlwaysInstrumentOpt += Always; |
213 | 1 | CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); |
214 | 1 | } |
215 | | |
216 | 33 | for (const auto &Never : NeverInstrumentFiles) { |
217 | 1 | SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); |
218 | 1 | NeverInstrumentOpt += Never; |
219 | 1 | CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); |
220 | 1 | } |
221 | | |
222 | 33 | for (const auto &AttrFile : AttrListFiles) { |
223 | 1 | SmallString<64> AttrListFileOpt("-fxray-attr-list="); |
224 | 1 | AttrListFileOpt += AttrFile; |
225 | 1 | CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt)); |
226 | 1 | } |
227 | | |
228 | 33 | for (const auto &Dep : ExtraDeps) { |
229 | 3 | SmallString<64> ExtraDepOpt("-fdepfile-entry="); |
230 | 3 | ExtraDepOpt += Dep; |
231 | 3 | CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); |
232 | 3 | } |
233 | | |
234 | 45 | for (const auto &Mode : Modes) { |
235 | 45 | SmallString<64> ModeOpt("-fxray-modes="); |
236 | 45 | ModeOpt += Mode; |
237 | 45 | CmdArgs.push_back(Args.MakeArgString(ModeOpt)); |
238 | 45 | } |
239 | | |
240 | 33 | SmallString<64> Bundle("-fxray-instrumentation-bundle="); |
241 | 33 | if (InstrumentationBundle.full()) { |
242 | 27 | Bundle += "all"; |
243 | 27 | } else if (6 InstrumentationBundle.empty()6 ) { |
244 | 0 | Bundle += "none"; |
245 | 6 | } else { |
246 | 6 | if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry) && |
247 | 6 | InstrumentationBundle.has(XRayInstrKind::FunctionExit)1 ) |
248 | 1 | Bundle += "function"; |
249 | 5 | else if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry)) |
250 | 0 | Bundle += "function-entry"; |
251 | 5 | else if (InstrumentationBundle.has(XRayInstrKind::FunctionExit)) |
252 | 0 | Bundle += "function-exit"; |
253 | | |
254 | 6 | if (InstrumentationBundle.has(XRayInstrKind::Custom)) |
255 | 0 | Bundle += "custom"; |
256 | 6 | if (InstrumentationBundle.has(XRayInstrKind::Typed)) |
257 | 0 | Bundle += "typed"; |
258 | 6 | } |
259 | 33 | CmdArgs.push_back(Args.MakeArgString(Bundle)); |
260 | 33 | } |