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