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