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" 19*5ffd83dbSDimitry 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 250b57cec5SDimitry Andric namespace { 260b57cec5SDimitry Andric constexpr char XRayInstrumentOption[] = "-fxray-instrument"; 270b57cec5SDimitry Andric constexpr char XRayInstructionThresholdOption[] = 280b57cec5SDimitry Andric "-fxray-instruction-threshold="; 290b57cec5SDimitry Andric constexpr const char *const XRaySupportedModes[] = {"xray-fdr", "xray-basic"}; 300b57cec5SDimitry Andric } // namespace 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { 330b57cec5SDimitry Andric const Driver &D = TC.getDriver(); 340b57cec5SDimitry Andric const llvm::Triple &Triple = TC.getTriple(); 35*5ffd83dbSDimitry Andric if (!Args.hasFlag(options::OPT_fxray_instrument, 36*5ffd83dbSDimitry Andric options::OPT_fno_xray_instrument, false)) 37*5ffd83dbSDimitry Andric return; 380b57cec5SDimitry Andric if (Triple.getOS() == llvm::Triple::Linux) { 390b57cec5SDimitry Andric switch (Triple.getArch()) { 400b57cec5SDimitry Andric case llvm::Triple::x86_64: 410b57cec5SDimitry Andric case llvm::Triple::arm: 420b57cec5SDimitry Andric case llvm::Triple::aarch64: 430b57cec5SDimitry Andric case llvm::Triple::ppc64le: 440b57cec5SDimitry Andric case llvm::Triple::mips: 450b57cec5SDimitry Andric case llvm::Triple::mipsel: 460b57cec5SDimitry Andric case llvm::Triple::mips64: 470b57cec5SDimitry Andric case llvm::Triple::mips64el: 480b57cec5SDimitry Andric break; 490b57cec5SDimitry Andric default: 500b57cec5SDimitry Andric D.Diag(diag::err_drv_clang_unsupported) 510b57cec5SDimitry Andric << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 520b57cec5SDimitry Andric } 53*5ffd83dbSDimitry Andric } else if (Triple.isOSFreeBSD() || Triple.isOSOpenBSD() || 54*5ffd83dbSDimitry Andric Triple.isOSNetBSD() || Triple.isMacOSX()) { 550b57cec5SDimitry Andric if (Triple.getArch() != llvm::Triple::x86_64) { 560b57cec5SDimitry Andric D.Diag(diag::err_drv_clang_unsupported) 570b57cec5SDimitry Andric << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric } else if (Triple.getOS() == llvm::Triple::Fuchsia) { 600b57cec5SDimitry Andric switch (Triple.getArch()) { 610b57cec5SDimitry Andric case llvm::Triple::x86_64: 620b57cec5SDimitry Andric case llvm::Triple::aarch64: 630b57cec5SDimitry Andric break; 640b57cec5SDimitry Andric default: 650b57cec5SDimitry Andric D.Diag(diag::err_drv_clang_unsupported) 660b57cec5SDimitry Andric << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric } else { 690b57cec5SDimitry Andric D.Diag(diag::err_drv_clang_unsupported) 700b57cec5SDimitry Andric << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 710b57cec5SDimitry Andric } 72480093f4SDimitry Andric 73480093f4SDimitry Andric // Both XRay and -fpatchable-function-entry use 74480093f4SDimitry Andric // TargetOpcode::PATCHABLE_FUNCTION_ENTER. 75480093f4SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) 76480093f4SDimitry Andric D.Diag(diag::err_drv_argument_not_allowed_with) 77480093f4SDimitry Andric << "-fxray-instrument" << A->getSpelling(); 78480093f4SDimitry Andric 790b57cec5SDimitry Andric XRayInstrument = true; 800b57cec5SDimitry Andric if (const Arg *A = 810b57cec5SDimitry Andric Args.getLastArg(options::OPT_fxray_instruction_threshold_, 820b57cec5SDimitry Andric options::OPT_fxray_instruction_threshold_EQ)) { 830b57cec5SDimitry Andric StringRef S = A->getValue(); 840b57cec5SDimitry Andric if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0) 850b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric // By default, the back-end will not emit the lowering for XRay customevent 890b57cec5SDimitry Andric // calls if the function is not instrumented. In the future we will change 900b57cec5SDimitry Andric // this default to be the reverse, but in the meantime we're going to 910b57cec5SDimitry Andric // introduce the new functionality behind a flag. 920b57cec5SDimitry Andric if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, 93*5ffd83dbSDimitry Andric options::OPT_fno_xray_always_emit_customevents, false)) 940b57cec5SDimitry Andric XRayAlwaysEmitCustomEvents = true; 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents, 97*5ffd83dbSDimitry Andric options::OPT_fno_xray_always_emit_typedevents, false)) 980b57cec5SDimitry Andric XRayAlwaysEmitTypedEvents = true; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric if (!Args.hasFlag(options::OPT_fxray_link_deps, 1010b57cec5SDimitry Andric options::OPT_fnoxray_link_deps, true)) 1020b57cec5SDimitry Andric XRayRT = false; 1030b57cec5SDimitry Andric 104*5ffd83dbSDimitry Andric if (Args.hasFlag(options::OPT_fxray_ignore_loops, 105*5ffd83dbSDimitry Andric options::OPT_fno_xray_ignore_loops, false)) 106*5ffd83dbSDimitry Andric XRayIgnoreLoops = true; 107*5ffd83dbSDimitry Andric 108*5ffd83dbSDimitry Andric XRayFunctionIndex = Args.hasFlag(options::OPT_fxray_function_index, 109*5ffd83dbSDimitry Andric options::OPT_fno_xray_function_index, true); 110*5ffd83dbSDimitry Andric 1110b57cec5SDimitry Andric auto Bundles = 1120b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); 1130b57cec5SDimitry Andric if (Bundles.empty()) 1140b57cec5SDimitry Andric InstrumentationBundle.Mask = XRayInstrKind::All; 1150b57cec5SDimitry Andric else 1160b57cec5SDimitry Andric for (const auto &B : Bundles) { 1170b57cec5SDimitry Andric llvm::SmallVector<StringRef, 2> BundleParts; 1180b57cec5SDimitry Andric llvm::SplitString(B, BundleParts, ","); 1190b57cec5SDimitry Andric for (const auto &P : BundleParts) { 1200b57cec5SDimitry Andric // TODO: Automate the generation of the string case table. 1210b57cec5SDimitry Andric auto Valid = llvm::StringSwitch<bool>(P) 122*5ffd83dbSDimitry Andric .Cases("none", "all", "function", "function-entry", 123*5ffd83dbSDimitry Andric "function-exit", "custom", true) 1240b57cec5SDimitry Andric .Default(false); 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric if (!Valid) { 1270b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_invalid_value) 1280b57cec5SDimitry Andric << "-fxray-instrumentation-bundle=" << P; 1290b57cec5SDimitry Andric continue; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric auto Mask = parseXRayInstrValue(P); 1330b57cec5SDimitry Andric if (Mask == XRayInstrKind::None) { 1340b57cec5SDimitry Andric InstrumentationBundle.clear(); 1350b57cec5SDimitry Andric break; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric InstrumentationBundle.Mask |= Mask; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // Validate the always/never attribute files. We also make sure that they 1430b57cec5SDimitry Andric // are treated as actual dependencies. 1440b57cec5SDimitry Andric for (const auto &Filename : 1450b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_always_instrument)) { 146480093f4SDimitry Andric if (D.getVFS().exists(Filename)) { 1470b57cec5SDimitry Andric AlwaysInstrumentFiles.push_back(Filename); 1480b57cec5SDimitry Andric ExtraDeps.push_back(Filename); 1490b57cec5SDimitry Andric } else 1500b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric for (const auto &Filename : 1540b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_never_instrument)) { 155480093f4SDimitry Andric if (D.getVFS().exists(Filename)) { 1560b57cec5SDimitry Andric NeverInstrumentFiles.push_back(Filename); 1570b57cec5SDimitry Andric ExtraDeps.push_back(Filename); 1580b57cec5SDimitry Andric } else 1590b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric for (const auto &Filename : 1630b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_attr_list)) { 164480093f4SDimitry Andric if (D.getVFS().exists(Filename)) { 1650b57cec5SDimitry Andric AttrListFiles.push_back(Filename); 1660b57cec5SDimitry Andric ExtraDeps.push_back(Filename); 1670b57cec5SDimitry Andric } else 1680b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric // Get the list of modes we want to support. 1720b57cec5SDimitry Andric auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes); 1730b57cec5SDimitry Andric if (SpecifiedModes.empty()) 1740b57cec5SDimitry Andric llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); 1750b57cec5SDimitry Andric else 1760b57cec5SDimitry Andric for (const auto &Arg : SpecifiedModes) { 1770b57cec5SDimitry Andric // Parse CSV values for -fxray-modes=... 1780b57cec5SDimitry Andric llvm::SmallVector<StringRef, 2> ModeParts; 1790b57cec5SDimitry Andric llvm::SplitString(Arg, ModeParts, ","); 1800b57cec5SDimitry Andric for (const auto &M : ModeParts) 1810b57cec5SDimitry Andric if (M == "none") 1820b57cec5SDimitry Andric Modes.clear(); 1830b57cec5SDimitry Andric else if (M == "all") 1840b57cec5SDimitry Andric llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); 1850b57cec5SDimitry Andric else 186*5ffd83dbSDimitry Andric Modes.push_back(std::string(M)); 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric // Then we want to sort and unique the modes we've collected. 1900b57cec5SDimitry Andric llvm::sort(Modes); 1910b57cec5SDimitry Andric Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, 1950b57cec5SDimitry Andric ArgStringList &CmdArgs, types::ID InputType) const { 1960b57cec5SDimitry Andric if (!XRayInstrument) 1970b57cec5SDimitry Andric return; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric CmdArgs.push_back(XRayInstrumentOption); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric if (XRayAlwaysEmitCustomEvents) 2020b57cec5SDimitry Andric CmdArgs.push_back("-fxray-always-emit-customevents"); 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric if (XRayAlwaysEmitTypedEvents) 2050b57cec5SDimitry Andric CmdArgs.push_back("-fxray-always-emit-typedevents"); 2060b57cec5SDimitry Andric 207*5ffd83dbSDimitry Andric if (XRayIgnoreLoops) 208*5ffd83dbSDimitry Andric CmdArgs.push_back("-fxray-ignore-loops"); 209*5ffd83dbSDimitry Andric 210*5ffd83dbSDimitry Andric if (!XRayFunctionIndex) 211*5ffd83dbSDimitry Andric CmdArgs.push_back("-fno-xray-function-index"); 212*5ffd83dbSDimitry Andric 2130b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + 2140b57cec5SDimitry Andric Twine(InstructionThreshold))); 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric for (const auto &Always : AlwaysInstrumentFiles) { 2170b57cec5SDimitry Andric SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); 2180b57cec5SDimitry Andric AlwaysInstrumentOpt += Always; 2190b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric for (const auto &Never : NeverInstrumentFiles) { 2230b57cec5SDimitry Andric SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); 2240b57cec5SDimitry Andric NeverInstrumentOpt += Never; 2250b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric for (const auto &AttrFile : AttrListFiles) { 2290b57cec5SDimitry Andric SmallString<64> AttrListFileOpt("-fxray-attr-list="); 2300b57cec5SDimitry Andric AttrListFileOpt += AttrFile; 2310b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt)); 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric for (const auto &Dep : ExtraDeps) { 2350b57cec5SDimitry Andric SmallString<64> ExtraDepOpt("-fdepfile-entry="); 2360b57cec5SDimitry Andric ExtraDepOpt += Dep; 2370b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric for (const auto &Mode : Modes) { 2410b57cec5SDimitry Andric SmallString<64> ModeOpt("-fxray-modes="); 2420b57cec5SDimitry Andric ModeOpt += Mode; 2430b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(ModeOpt)); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric SmallString<64> Bundle("-fxray-instrumentation-bundle="); 2470b57cec5SDimitry Andric if (InstrumentationBundle.full()) { 2480b57cec5SDimitry Andric Bundle += "all"; 2490b57cec5SDimitry Andric } else if (InstrumentationBundle.empty()) { 2500b57cec5SDimitry Andric Bundle += "none"; 2510b57cec5SDimitry Andric } else { 252*5ffd83dbSDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry) && 253*5ffd83dbSDimitry Andric InstrumentationBundle.has(XRayInstrKind::FunctionExit)) 2540b57cec5SDimitry Andric Bundle += "function"; 255*5ffd83dbSDimitry Andric else if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry)) 256*5ffd83dbSDimitry Andric Bundle += "function-entry"; 257*5ffd83dbSDimitry Andric else if (InstrumentationBundle.has(XRayInstrKind::FunctionExit)) 258*5ffd83dbSDimitry Andric Bundle += "function-exit"; 259*5ffd83dbSDimitry Andric 2600b57cec5SDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::Custom)) 2610b57cec5SDimitry Andric Bundle += "custom"; 2620b57cec5SDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::Typed)) 2630b57cec5SDimitry Andric Bundle += "typed"; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Bundle)); 2660b57cec5SDimitry Andric } 267