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