10b57cec5SDimitry Andric //===--- XRayArgs.cpp - Arguments for XRay --------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric #include "clang/Driver/XRayArgs.h"
90b57cec5SDimitry Andric #include "ToolChains/CommonArgs.h"
100b57cec5SDimitry Andric #include "clang/Driver/Driver.h"
110b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
120b57cec5SDimitry Andric #include "clang/Driver/Options.h"
130b57cec5SDimitry Andric #include "clang/Driver/ToolChain.h"
140b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
160b57cec5SDimitry Andric #include "llvm/Support/Path.h"
170b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
180b57cec5SDimitry Andric #include "llvm/Support/SpecialCaseList.h"
195ffd83dbSDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric using namespace clang;
220b57cec5SDimitry Andric using namespace clang::driver;
230b57cec5SDimitry Andric using namespace llvm::opt;
240b57cec5SDimitry Andric
25*06c3fb27SDimitry Andric constexpr const char *XRaySupportedModes[] = {"xray-fdr", "xray-basic"};
260b57cec5SDimitry Andric
XRayArgs(const ToolChain & TC,const ArgList & Args)270b57cec5SDimitry Andric XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
280b57cec5SDimitry Andric const Driver &D = TC.getDriver();
290b57cec5SDimitry Andric const llvm::Triple &Triple = TC.getTriple();
305ffd83dbSDimitry Andric if (!Args.hasFlag(options::OPT_fxray_instrument,
315ffd83dbSDimitry Andric options::OPT_fno_xray_instrument, false))
325ffd83dbSDimitry Andric return;
33*06c3fb27SDimitry Andric XRayInstrument = Args.getLastArg(options::OPT_fxray_instrument);
34*06c3fb27SDimitry Andric if (Triple.isMacOSX()) {
35*06c3fb27SDimitry Andric switch (Triple.getArch()) {
36*06c3fb27SDimitry Andric case llvm::Triple::aarch64:
37*06c3fb27SDimitry Andric case llvm::Triple::x86_64:
38*06c3fb27SDimitry Andric break;
39*06c3fb27SDimitry Andric default:
40*06c3fb27SDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target)
41*06c3fb27SDimitry Andric << XRayInstrument->getSpelling() << Triple.str();
42*06c3fb27SDimitry Andric break;
43*06c3fb27SDimitry Andric }
44*06c3fb27SDimitry Andric } else if (Triple.isOSBinFormatELF()) {
450b57cec5SDimitry Andric switch (Triple.getArch()) {
460b57cec5SDimitry Andric case llvm::Triple::x86_64:
470b57cec5SDimitry Andric case llvm::Triple::arm:
480b57cec5SDimitry Andric case llvm::Triple::aarch64:
490eae32dcSDimitry Andric case llvm::Triple::hexagon:
500b57cec5SDimitry Andric case llvm::Triple::ppc64le:
51*06c3fb27SDimitry Andric case llvm::Triple::loongarch64:
520b57cec5SDimitry Andric case llvm::Triple::mips:
530b57cec5SDimitry Andric case llvm::Triple::mipsel:
540b57cec5SDimitry Andric case llvm::Triple::mips64:
550b57cec5SDimitry Andric case llvm::Triple::mips64el:
560b57cec5SDimitry Andric break;
570b57cec5SDimitry Andric default:
58*06c3fb27SDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target)
59*06c3fb27SDimitry Andric << XRayInstrument->getSpelling() << Triple.str();
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric } else {
62*06c3fb27SDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target)
63*06c3fb27SDimitry Andric << XRayInstrument->getSpelling() << Triple.str();
640b57cec5SDimitry Andric }
65480093f4SDimitry Andric
66480093f4SDimitry Andric // Both XRay and -fpatchable-function-entry use
67480093f4SDimitry Andric // TargetOpcode::PATCHABLE_FUNCTION_ENTER.
68480093f4SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ))
69480093f4SDimitry Andric D.Diag(diag::err_drv_argument_not_allowed_with)
70*06c3fb27SDimitry Andric << XRayInstrument->getSpelling() << A->getSpelling();
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric if (!Args.hasFlag(options::OPT_fxray_link_deps,
73*06c3fb27SDimitry Andric options::OPT_fno_xray_link_deps, true))
740b57cec5SDimitry Andric XRayRT = false;
750b57cec5SDimitry Andric
760b57cec5SDimitry Andric auto Bundles =
770b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle);
780b57cec5SDimitry Andric if (Bundles.empty())
790b57cec5SDimitry Andric InstrumentationBundle.Mask = XRayInstrKind::All;
800b57cec5SDimitry Andric else
810b57cec5SDimitry Andric for (const auto &B : Bundles) {
820b57cec5SDimitry Andric llvm::SmallVector<StringRef, 2> BundleParts;
830b57cec5SDimitry Andric llvm::SplitString(B, BundleParts, ",");
840b57cec5SDimitry Andric for (const auto &P : BundleParts) {
850b57cec5SDimitry Andric // TODO: Automate the generation of the string case table.
860b57cec5SDimitry Andric auto Valid = llvm::StringSwitch<bool>(P)
875ffd83dbSDimitry Andric .Cases("none", "all", "function", "function-entry",
885ffd83dbSDimitry Andric "function-exit", "custom", true)
890b57cec5SDimitry Andric .Default(false);
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric if (!Valid) {
920b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_invalid_value)
930b57cec5SDimitry Andric << "-fxray-instrumentation-bundle=" << P;
940b57cec5SDimitry Andric continue;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric auto Mask = parseXRayInstrValue(P);
980b57cec5SDimitry Andric if (Mask == XRayInstrKind::None) {
990b57cec5SDimitry Andric InstrumentationBundle.clear();
1000b57cec5SDimitry Andric break;
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric InstrumentationBundle.Mask |= Mask;
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric // Validate the always/never attribute files. We also make sure that they
1080b57cec5SDimitry Andric // are treated as actual dependencies.
1090b57cec5SDimitry Andric for (const auto &Filename :
1100b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_always_instrument)) {
111480093f4SDimitry Andric if (D.getVFS().exists(Filename)) {
1120b57cec5SDimitry Andric AlwaysInstrumentFiles.push_back(Filename);
1130b57cec5SDimitry Andric ExtraDeps.push_back(Filename);
1140b57cec5SDimitry Andric } else
1150b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename;
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric for (const auto &Filename :
1190b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_never_instrument)) {
120480093f4SDimitry Andric if (D.getVFS().exists(Filename)) {
1210b57cec5SDimitry Andric NeverInstrumentFiles.push_back(Filename);
1220b57cec5SDimitry Andric ExtraDeps.push_back(Filename);
1230b57cec5SDimitry Andric } else
1240b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric for (const auto &Filename :
1280b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_attr_list)) {
129480093f4SDimitry Andric if (D.getVFS().exists(Filename)) {
1300b57cec5SDimitry Andric AttrListFiles.push_back(Filename);
1310b57cec5SDimitry Andric ExtraDeps.push_back(Filename);
1320b57cec5SDimitry Andric } else
1330b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric // Get the list of modes we want to support.
1370b57cec5SDimitry Andric auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes);
1380b57cec5SDimitry Andric if (SpecifiedModes.empty())
1390b57cec5SDimitry Andric llvm::copy(XRaySupportedModes, std::back_inserter(Modes));
1400b57cec5SDimitry Andric else
1410b57cec5SDimitry Andric for (const auto &Arg : SpecifiedModes) {
1420b57cec5SDimitry Andric // Parse CSV values for -fxray-modes=...
1430b57cec5SDimitry Andric llvm::SmallVector<StringRef, 2> ModeParts;
1440b57cec5SDimitry Andric llvm::SplitString(Arg, ModeParts, ",");
1450b57cec5SDimitry Andric for (const auto &M : ModeParts)
1460b57cec5SDimitry Andric if (M == "none")
1470b57cec5SDimitry Andric Modes.clear();
1480b57cec5SDimitry Andric else if (M == "all")
1490b57cec5SDimitry Andric llvm::copy(XRaySupportedModes, std::back_inserter(Modes));
1500b57cec5SDimitry Andric else
1515ffd83dbSDimitry Andric Modes.push_back(std::string(M));
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric // Then we want to sort and unique the modes we've collected.
1550b57cec5SDimitry Andric llvm::sort(Modes);
1560b57cec5SDimitry Andric Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end());
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric
addArgs(const ToolChain & TC,const ArgList & Args,ArgStringList & CmdArgs,types::ID InputType) const1590b57cec5SDimitry Andric void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
1600b57cec5SDimitry Andric ArgStringList &CmdArgs, types::ID InputType) const {
1610b57cec5SDimitry Andric if (!XRayInstrument)
1620b57cec5SDimitry Andric return;
163*06c3fb27SDimitry Andric const Driver &D = TC.getDriver();
164*06c3fb27SDimitry Andric XRayInstrument->render(Args, CmdArgs);
1650b57cec5SDimitry Andric
166*06c3fb27SDimitry Andric // By default, the back-end will not emit the lowering for XRay customevent
167*06c3fb27SDimitry Andric // calls if the function is not instrumented. In the future we will change
168*06c3fb27SDimitry Andric // this default to be the reverse, but in the meantime we're going to
169*06c3fb27SDimitry Andric // introduce the new functionality behind a flag.
170*06c3fb27SDimitry Andric Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_customevents,
171*06c3fb27SDimitry Andric options::OPT_fno_xray_always_emit_customevents);
1720b57cec5SDimitry Andric
173*06c3fb27SDimitry Andric Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_typedevents,
174*06c3fb27SDimitry Andric options::OPT_fno_xray_always_emit_typedevents);
175*06c3fb27SDimitry Andric Args.addOptInFlag(CmdArgs, options::OPT_fxray_ignore_loops,
176*06c3fb27SDimitry Andric options::OPT_fno_xray_ignore_loops);
177*06c3fb27SDimitry Andric Args.addOptOutFlag(CmdArgs, options::OPT_fxray_function_index,
178*06c3fb27SDimitry Andric options::OPT_fno_xray_function_index);
1790b57cec5SDimitry Andric
180*06c3fb27SDimitry Andric if (const Arg *A =
181*06c3fb27SDimitry Andric Args.getLastArg(options::OPT_fxray_instruction_threshold_EQ)) {
182*06c3fb27SDimitry Andric int Value;
183*06c3fb27SDimitry Andric StringRef S = A->getValue();
184*06c3fb27SDimitry Andric if (S.getAsInteger(0, Value) || Value < 0)
185*06c3fb27SDimitry Andric D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
186*06c3fb27SDimitry Andric else
187*06c3fb27SDimitry Andric A->render(Args, CmdArgs);
188e8d8bef9SDimitry Andric }
189e8d8bef9SDimitry Andric
190*06c3fb27SDimitry Andric int XRayFunctionGroups = 1;
191*06c3fb27SDimitry Andric int XRaySelectedFunctionGroup = 0;
192*06c3fb27SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) {
193*06c3fb27SDimitry Andric StringRef S = A->getValue();
194*06c3fb27SDimitry Andric if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1)
195*06c3fb27SDimitry Andric D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
196*06c3fb27SDimitry Andric if (XRayFunctionGroups > 1)
197*06c3fb27SDimitry Andric A->render(Args, CmdArgs);
198e8d8bef9SDimitry Andric }
199*06c3fb27SDimitry Andric if (const Arg *A =
200*06c3fb27SDimitry Andric Args.getLastArg(options::OPT_fxray_selected_function_group)) {
201*06c3fb27SDimitry Andric StringRef S = A->getValue();
202*06c3fb27SDimitry Andric if (S.getAsInteger(0, XRaySelectedFunctionGroup) ||
203*06c3fb27SDimitry Andric XRaySelectedFunctionGroup < 0 ||
204*06c3fb27SDimitry Andric XRaySelectedFunctionGroup >= XRayFunctionGroups)
205*06c3fb27SDimitry Andric D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
206*06c3fb27SDimitry Andric if (XRaySelectedFunctionGroup != 0)
207*06c3fb27SDimitry Andric A->render(Args, CmdArgs);
208*06c3fb27SDimitry Andric }
2090b57cec5SDimitry Andric
2100b57cec5SDimitry Andric for (const auto &Always : AlwaysInstrumentFiles) {
2110b57cec5SDimitry Andric SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument=");
2120b57cec5SDimitry Andric AlwaysInstrumentOpt += Always;
2130b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt));
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric for (const auto &Never : NeverInstrumentFiles) {
2170b57cec5SDimitry Andric SmallString<64> NeverInstrumentOpt("-fxray-never-instrument=");
2180b57cec5SDimitry Andric NeverInstrumentOpt += Never;
2190b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt));
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric
2220b57cec5SDimitry Andric for (const auto &AttrFile : AttrListFiles) {
2230b57cec5SDimitry Andric SmallString<64> AttrListFileOpt("-fxray-attr-list=");
2240b57cec5SDimitry Andric AttrListFileOpt += AttrFile;
2250b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt));
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric for (const auto &Dep : ExtraDeps) {
2290b57cec5SDimitry Andric SmallString<64> ExtraDepOpt("-fdepfile-entry=");
2300b57cec5SDimitry Andric ExtraDepOpt += Dep;
2310b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric for (const auto &Mode : Modes) {
2350b57cec5SDimitry Andric SmallString<64> ModeOpt("-fxray-modes=");
2360b57cec5SDimitry Andric ModeOpt += Mode;
2370b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(ModeOpt));
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric
2400b57cec5SDimitry Andric SmallString<64> Bundle("-fxray-instrumentation-bundle=");
2410b57cec5SDimitry Andric if (InstrumentationBundle.full()) {
2420b57cec5SDimitry Andric Bundle += "all";
2430b57cec5SDimitry Andric } else if (InstrumentationBundle.empty()) {
2440b57cec5SDimitry Andric Bundle += "none";
2450b57cec5SDimitry Andric } else {
2465ffd83dbSDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry) &&
2475ffd83dbSDimitry Andric InstrumentationBundle.has(XRayInstrKind::FunctionExit))
2480b57cec5SDimitry Andric Bundle += "function";
2495ffd83dbSDimitry Andric else if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry))
2505ffd83dbSDimitry Andric Bundle += "function-entry";
2515ffd83dbSDimitry Andric else if (InstrumentationBundle.has(XRayInstrKind::FunctionExit))
2525ffd83dbSDimitry Andric Bundle += "function-exit";
2535ffd83dbSDimitry Andric
2540b57cec5SDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::Custom))
2550b57cec5SDimitry Andric Bundle += "custom";
2560b57cec5SDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::Typed))
2570b57cec5SDimitry Andric Bundle += "typed";
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Bundle));
2600b57cec5SDimitry Andric }
261