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/FileSystem.h" 170b57cec5SDimitry Andric #include "llvm/Support/Path.h" 180b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h" 190b57cec5SDimitry Andric #include "llvm/Support/SpecialCaseList.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(); 350b57cec5SDimitry Andric if (Args.hasFlag(options::OPT_fxray_instrument, 360b57cec5SDimitry Andric options::OPT_fnoxray_instrument, false)) { 370b57cec5SDimitry Andric if (Triple.getOS() == llvm::Triple::Linux) { 380b57cec5SDimitry Andric switch (Triple.getArch()) { 390b57cec5SDimitry Andric case llvm::Triple::x86_64: 400b57cec5SDimitry Andric case llvm::Triple::arm: 410b57cec5SDimitry Andric case llvm::Triple::aarch64: 420b57cec5SDimitry Andric case llvm::Triple::ppc64le: 430b57cec5SDimitry Andric case llvm::Triple::mips: 440b57cec5SDimitry Andric case llvm::Triple::mipsel: 450b57cec5SDimitry Andric case llvm::Triple::mips64: 460b57cec5SDimitry Andric case llvm::Triple::mips64el: 470b57cec5SDimitry Andric break; 480b57cec5SDimitry Andric default: 490b57cec5SDimitry Andric D.Diag(diag::err_drv_clang_unsupported) 500b57cec5SDimitry Andric << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric } else if (Triple.isOSFreeBSD() || 530b57cec5SDimitry Andric Triple.isOSOpenBSD() || 540b57cec5SDimitry Andric Triple.isOSNetBSD() || 55a7dea167SDimitry Andric Triple.isMacOSX()) { 560b57cec5SDimitry Andric if (Triple.getArch() != llvm::Triple::x86_64) { 570b57cec5SDimitry Andric D.Diag(diag::err_drv_clang_unsupported) 580b57cec5SDimitry Andric << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric } else if (Triple.getOS() == llvm::Triple::Fuchsia) { 610b57cec5SDimitry Andric switch (Triple.getArch()) { 620b57cec5SDimitry Andric case llvm::Triple::x86_64: 630b57cec5SDimitry Andric case llvm::Triple::aarch64: 640b57cec5SDimitry Andric break; 650b57cec5SDimitry Andric default: 660b57cec5SDimitry Andric D.Diag(diag::err_drv_clang_unsupported) 670b57cec5SDimitry Andric << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric } else { 700b57cec5SDimitry Andric D.Diag(diag::err_drv_clang_unsupported) 710b57cec5SDimitry Andric << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 720b57cec5SDimitry Andric } 73*480093f4SDimitry Andric 74*480093f4SDimitry Andric // Both XRay and -fpatchable-function-entry use 75*480093f4SDimitry Andric // TargetOpcode::PATCHABLE_FUNCTION_ENTER. 76*480093f4SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) 77*480093f4SDimitry Andric D.Diag(diag::err_drv_argument_not_allowed_with) 78*480093f4SDimitry Andric << "-fxray-instrument" << A->getSpelling(); 79*480093f4SDimitry Andric 800b57cec5SDimitry Andric XRayInstrument = true; 810b57cec5SDimitry Andric if (const Arg *A = 820b57cec5SDimitry Andric Args.getLastArg(options::OPT_fxray_instruction_threshold_, 830b57cec5SDimitry Andric options::OPT_fxray_instruction_threshold_EQ)) { 840b57cec5SDimitry Andric StringRef S = A->getValue(); 850b57cec5SDimitry Andric if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0) 860b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric // By default, the back-end will not emit the lowering for XRay customevent 900b57cec5SDimitry Andric // calls if the function is not instrumented. In the future we will change 910b57cec5SDimitry Andric // this default to be the reverse, but in the meantime we're going to 920b57cec5SDimitry Andric // introduce the new functionality behind a flag. 930b57cec5SDimitry Andric if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, 940b57cec5SDimitry Andric options::OPT_fnoxray_always_emit_customevents, false)) 950b57cec5SDimitry Andric XRayAlwaysEmitCustomEvents = true; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents, 980b57cec5SDimitry Andric options::OPT_fnoxray_always_emit_typedevents, false)) 990b57cec5SDimitry Andric XRayAlwaysEmitTypedEvents = true; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric if (!Args.hasFlag(options::OPT_fxray_link_deps, 1020b57cec5SDimitry Andric options::OPT_fnoxray_link_deps, true)) 1030b57cec5SDimitry Andric XRayRT = false; 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric auto Bundles = 1060b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); 1070b57cec5SDimitry Andric if (Bundles.empty()) 1080b57cec5SDimitry Andric InstrumentationBundle.Mask = XRayInstrKind::All; 1090b57cec5SDimitry Andric else 1100b57cec5SDimitry Andric for (const auto &B : Bundles) { 1110b57cec5SDimitry Andric llvm::SmallVector<StringRef, 2> BundleParts; 1120b57cec5SDimitry Andric llvm::SplitString(B, BundleParts, ","); 1130b57cec5SDimitry Andric for (const auto &P : BundleParts) { 1140b57cec5SDimitry Andric // TODO: Automate the generation of the string case table. 1150b57cec5SDimitry Andric auto Valid = llvm::StringSwitch<bool>(P) 1160b57cec5SDimitry Andric .Cases("none", "all", "function", "custom", true) 1170b57cec5SDimitry Andric .Default(false); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric if (!Valid) { 1200b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_invalid_value) 1210b57cec5SDimitry Andric << "-fxray-instrumentation-bundle=" << P; 1220b57cec5SDimitry Andric continue; 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric auto Mask = parseXRayInstrValue(P); 1260b57cec5SDimitry Andric if (Mask == XRayInstrKind::None) { 1270b57cec5SDimitry Andric InstrumentationBundle.clear(); 1280b57cec5SDimitry Andric break; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric InstrumentationBundle.Mask |= Mask; 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric // Validate the always/never attribute files. We also make sure that they 1360b57cec5SDimitry Andric // are treated as actual dependencies. 1370b57cec5SDimitry Andric for (const auto &Filename : 1380b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_always_instrument)) { 139*480093f4SDimitry Andric if (D.getVFS().exists(Filename)) { 1400b57cec5SDimitry Andric AlwaysInstrumentFiles.push_back(Filename); 1410b57cec5SDimitry Andric ExtraDeps.push_back(Filename); 1420b57cec5SDimitry Andric } else 1430b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename; 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric for (const auto &Filename : 1470b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_never_instrument)) { 148*480093f4SDimitry Andric if (D.getVFS().exists(Filename)) { 1490b57cec5SDimitry Andric NeverInstrumentFiles.push_back(Filename); 1500b57cec5SDimitry Andric ExtraDeps.push_back(Filename); 1510b57cec5SDimitry Andric } else 1520b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename; 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric for (const auto &Filename : 1560b57cec5SDimitry Andric Args.getAllArgValues(options::OPT_fxray_attr_list)) { 157*480093f4SDimitry Andric if (D.getVFS().exists(Filename)) { 1580b57cec5SDimitry Andric AttrListFiles.push_back(Filename); 1590b57cec5SDimitry Andric ExtraDeps.push_back(Filename); 1600b57cec5SDimitry Andric } else 1610b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_no_such_file) << Filename; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric // Get the list of modes we want to support. 1650b57cec5SDimitry Andric auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes); 1660b57cec5SDimitry Andric if (SpecifiedModes.empty()) 1670b57cec5SDimitry Andric llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); 1680b57cec5SDimitry Andric else 1690b57cec5SDimitry Andric for (const auto &Arg : SpecifiedModes) { 1700b57cec5SDimitry Andric // Parse CSV values for -fxray-modes=... 1710b57cec5SDimitry Andric llvm::SmallVector<StringRef, 2> ModeParts; 1720b57cec5SDimitry Andric llvm::SplitString(Arg, ModeParts, ","); 1730b57cec5SDimitry Andric for (const auto &M : ModeParts) 1740b57cec5SDimitry Andric if (M == "none") 1750b57cec5SDimitry Andric Modes.clear(); 1760b57cec5SDimitry Andric else if (M == "all") 1770b57cec5SDimitry Andric llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); 1780b57cec5SDimitry Andric else 1790b57cec5SDimitry Andric Modes.push_back(M); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric // Then we want to sort and unique the modes we've collected. 1830b57cec5SDimitry Andric llvm::sort(Modes); 1840b57cec5SDimitry Andric Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, 1890b57cec5SDimitry Andric ArgStringList &CmdArgs, types::ID InputType) const { 1900b57cec5SDimitry Andric if (!XRayInstrument) 1910b57cec5SDimitry Andric return; 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric CmdArgs.push_back(XRayInstrumentOption); 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric if (XRayAlwaysEmitCustomEvents) 1960b57cec5SDimitry Andric CmdArgs.push_back("-fxray-always-emit-customevents"); 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric if (XRayAlwaysEmitTypedEvents) 1990b57cec5SDimitry Andric CmdArgs.push_back("-fxray-always-emit-typedevents"); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + 2020b57cec5SDimitry Andric Twine(InstructionThreshold))); 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric for (const auto &Always : AlwaysInstrumentFiles) { 2050b57cec5SDimitry Andric SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); 2060b57cec5SDimitry Andric AlwaysInstrumentOpt += Always; 2070b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric for (const auto &Never : NeverInstrumentFiles) { 2110b57cec5SDimitry Andric SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); 2120b57cec5SDimitry Andric NeverInstrumentOpt += Never; 2130b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric for (const auto &AttrFile : AttrListFiles) { 2170b57cec5SDimitry Andric SmallString<64> AttrListFileOpt("-fxray-attr-list="); 2180b57cec5SDimitry Andric AttrListFileOpt += AttrFile; 2190b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt)); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric for (const auto &Dep : ExtraDeps) { 2230b57cec5SDimitry Andric SmallString<64> ExtraDepOpt("-fdepfile-entry="); 2240b57cec5SDimitry Andric ExtraDepOpt += Dep; 2250b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric for (const auto &Mode : Modes) { 2290b57cec5SDimitry Andric SmallString<64> ModeOpt("-fxray-modes="); 2300b57cec5SDimitry Andric ModeOpt += Mode; 2310b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(ModeOpt)); 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric SmallString<64> Bundle("-fxray-instrumentation-bundle="); 2350b57cec5SDimitry Andric if (InstrumentationBundle.full()) { 2360b57cec5SDimitry Andric Bundle += "all"; 2370b57cec5SDimitry Andric } else if (InstrumentationBundle.empty()) { 2380b57cec5SDimitry Andric Bundle += "none"; 2390b57cec5SDimitry Andric } else { 2400b57cec5SDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::Function)) 2410b57cec5SDimitry Andric Bundle += "function"; 2420b57cec5SDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::Custom)) 2430b57cec5SDimitry Andric Bundle += "custom"; 2440b57cec5SDimitry Andric if (InstrumentationBundle.has(XRayInstrKind::Typed)) 2450b57cec5SDimitry Andric Bundle += "typed"; 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Bundle)); 2480b57cec5SDimitry Andric } 249