1 | |
2 | |
3 | |
4 | |
5 | |
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/FileSystem.h" |
17 | #include "llvm/Support/Path.h" |
18 | #include "llvm/Support/ScopedPrinter.h" |
19 | #include "llvm/Support/SpecialCaseList.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 | } |
31 | |
32 | XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { |
33 | const Driver &D = TC.getDriver(); |
34 | const llvm::Triple &Triple = TC.getTriple(); |
35 | if (Args.hasFlag(options::OPT_fxray_instrument, |
36 | options::OPT_fnoxray_instrument, false)) { |
37 | if (Triple.getOS() == llvm::Triple::Linux) { |
38 | switch (Triple.getArch()) { |
39 | case llvm::Triple::x86_64: |
40 | case llvm::Triple::arm: |
41 | case llvm::Triple::aarch64: |
42 | case llvm::Triple::ppc64le: |
43 | case llvm::Triple::mips: |
44 | case llvm::Triple::mipsel: |
45 | case llvm::Triple::mips64: |
46 | case llvm::Triple::mips64el: |
47 | break; |
48 | default: |
49 | D.Diag(diag::err_drv_clang_unsupported) |
50 | << (std::string(XRayInstrumentOption) + " on " + Triple.str()); |
51 | } |
52 | } else if (Triple.isOSFreeBSD() || |
53 | Triple.isOSOpenBSD() || |
54 | Triple.isOSNetBSD() || |
55 | Triple.getOS() == llvm::Triple::Darwin) { |
56 | if (Triple.getArch() != llvm::Triple::x86_64) { |
57 | D.Diag(diag::err_drv_clang_unsupported) |
58 | << (std::string(XRayInstrumentOption) + " on " + Triple.str()); |
59 | } |
60 | } else if (Triple.getOS() == llvm::Triple::Fuchsia) { |
61 | switch (Triple.getArch()) { |
62 | case llvm::Triple::x86_64: |
63 | case llvm::Triple::aarch64: |
64 | break; |
65 | default: |
66 | D.Diag(diag::err_drv_clang_unsupported) |
67 | << (std::string(XRayInstrumentOption) + " on " + Triple.str()); |
68 | } |
69 | } else { |
70 | D.Diag(diag::err_drv_clang_unsupported) |
71 | << (std::string(XRayInstrumentOption) + " on " + Triple.str()); |
72 | } |
73 | XRayInstrument = true; |
74 | if (const Arg *A = |
75 | Args.getLastArg(options::OPT_fxray_instruction_threshold_, |
76 | options::OPT_fxray_instruction_threshold_EQ)) { |
77 | StringRef S = A->getValue(); |
78 | if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0) |
79 | D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; |
80 | } |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, |
87 | options::OPT_fnoxray_always_emit_customevents, false)) |
88 | XRayAlwaysEmitCustomEvents = true; |
89 | |
90 | if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents, |
91 | options::OPT_fnoxray_always_emit_typedevents, false)) |
92 | XRayAlwaysEmitTypedEvents = true; |
93 | |
94 | if (!Args.hasFlag(options::OPT_fxray_link_deps, |
95 | options::OPT_fnoxray_link_deps, true)) |
96 | XRayRT = false; |
97 | |
98 | auto Bundles = |
99 | Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); |
100 | if (Bundles.empty()) |
101 | InstrumentationBundle.Mask = XRayInstrKind::All; |
102 | else |
103 | for (const auto &B : Bundles) { |
104 | llvm::SmallVector<StringRef, 2> BundleParts; |
105 | llvm::SplitString(B, BundleParts, ","); |
106 | for (const auto &P : BundleParts) { |
107 | |
108 | auto Valid = llvm::StringSwitch<bool>(P) |
109 | .Cases("none", "all", "function", "custom", true) |
110 | .Default(false); |
111 | |
112 | if (!Valid) { |
113 | D.Diag(clang::diag::err_drv_invalid_value) |
114 | << "-fxray-instrumentation-bundle=" << P; |
115 | continue; |
116 | } |
117 | |
118 | auto Mask = parseXRayInstrValue(P); |
119 | if (Mask == XRayInstrKind::None) { |
120 | InstrumentationBundle.clear(); |
121 | break; |
122 | } |
123 | |
124 | InstrumentationBundle.Mask |= Mask; |
125 | } |
126 | } |
127 | |
128 | |
129 | |
130 | for (const auto &Filename : |
131 | Args.getAllArgValues(options::OPT_fxray_always_instrument)) { |
132 | if (llvm::sys::fs::exists(Filename)) { |
133 | AlwaysInstrumentFiles.push_back(Filename); |
134 | ExtraDeps.push_back(Filename); |
135 | } else |
136 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
137 | } |
138 | |
139 | for (const auto &Filename : |
140 | Args.getAllArgValues(options::OPT_fxray_never_instrument)) { |
141 | if (llvm::sys::fs::exists(Filename)) { |
142 | NeverInstrumentFiles.push_back(Filename); |
143 | ExtraDeps.push_back(Filename); |
144 | } else |
145 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
146 | } |
147 | |
148 | for (const auto &Filename : |
149 | Args.getAllArgValues(options::OPT_fxray_attr_list)) { |
150 | if (llvm::sys::fs::exists(Filename)) { |
151 | AttrListFiles.push_back(Filename); |
152 | ExtraDeps.push_back(Filename); |
153 | } else |
154 | D.Diag(clang::diag::err_drv_no_such_file) << Filename; |
155 | } |
156 | |
157 | |
158 | auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes); |
159 | if (SpecifiedModes.empty()) |
160 | llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); |
161 | else |
162 | for (const auto &Arg : SpecifiedModes) { |
163 | |
164 | llvm::SmallVector<StringRef, 2> ModeParts; |
165 | llvm::SplitString(Arg, ModeParts, ","); |
166 | for (const auto &M : ModeParts) |
167 | if (M == "none") |
168 | Modes.clear(); |
169 | else if (M == "all") |
170 | llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); |
171 | else |
172 | Modes.push_back(M); |
173 | } |
174 | |
175 | |
176 | llvm::sort(Modes); |
177 | Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); |
178 | } |
179 | } |
180 | |
181 | void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, |
182 | ArgStringList &CmdArgs, types::ID InputType) const { |
183 | if (!XRayInstrument) |
184 | return; |
185 | |
186 | CmdArgs.push_back(XRayInstrumentOption); |
187 | |
188 | if (XRayAlwaysEmitCustomEvents) |
189 | CmdArgs.push_back("-fxray-always-emit-customevents"); |
190 | |
191 | if (XRayAlwaysEmitTypedEvents) |
192 | CmdArgs.push_back("-fxray-always-emit-typedevents"); |
193 | |
194 | CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + |
195 | Twine(InstructionThreshold))); |
196 | |
197 | for (const auto &Always : AlwaysInstrumentFiles) { |
198 | SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); |
199 | AlwaysInstrumentOpt += Always; |
200 | CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); |
201 | } |
202 | |
203 | for (const auto &Never : NeverInstrumentFiles) { |
204 | SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); |
205 | NeverInstrumentOpt += Never; |
206 | CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); |
207 | } |
208 | |
209 | for (const auto &AttrFile : AttrListFiles) { |
210 | SmallString<64> AttrListFileOpt("-fxray-attr-list="); |
211 | AttrListFileOpt += AttrFile; |
212 | CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt)); |
213 | } |
214 | |
215 | for (const auto &Dep : ExtraDeps) { |
216 | SmallString<64> ExtraDepOpt("-fdepfile-entry="); |
217 | ExtraDepOpt += Dep; |
218 | CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); |
219 | } |
220 | |
221 | for (const auto &Mode : Modes) { |
222 | SmallString<64> ModeOpt("-fxray-modes="); |
223 | ModeOpt += Mode; |
224 | CmdArgs.push_back(Args.MakeArgString(ModeOpt)); |
225 | } |
226 | |
227 | SmallString<64> Bundle("-fxray-instrumentation-bundle="); |
228 | if (InstrumentationBundle.full()) { |
229 | Bundle += "all"; |
230 | } else if (InstrumentationBundle.empty()) { |
231 | Bundle += "none"; |
232 | } else { |
233 | if (InstrumentationBundle.has(XRayInstrKind::Function)) |
234 | Bundle += "function"; |
235 | if (InstrumentationBundle.has(XRayInstrKind::Custom)) |
236 | Bundle += "custom"; |
237 | if (InstrumentationBundle.has(XRayInstrKind::Typed)) |
238 | Bundle += "typed"; |
239 | } |
240 | CmdArgs.push_back(Args.MakeArgString(Bundle)); |
241 | } |
242 | |