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 Triple.getOS() == llvm::Triple::NetBSD) { 56 if (Triple.getArch() != llvm::Triple::x86_64) { 57 D.Diag(diag::err_drv_clang_unsupported) 58 << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 59 } 60 } else { 61 D.Diag(diag::err_drv_clang_unsupported) 62 << (std::string(XRayInstrumentOption) + " on " + Triple.str()); 63 } 64 XRayInstrument = true; 65 if (const Arg *A = 66 Args.getLastArg(options::OPT_fxray_instruction_threshold_, 67 options::OPT_fxray_instruction_threshold_EQ)) { 68 StringRef S = A->getValue(); 69 if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0) 70 D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; 71 } 72 73 // By default, the back-end will not emit the lowering for XRay customevent 74 // calls if the function is not instrumented. In the future we will change 75 // this default to be the reverse, but in the meantime we're going to 76 // introduce the new functionality behind a flag. 77 if (Args.hasFlag(options::OPT_fxray_always_emit_customevents, 78 options::OPT_fnoxray_always_emit_customevents, false)) 79 XRayAlwaysEmitCustomEvents = true; 80 81 if (Args.hasFlag(options::OPT_fxray_always_emit_typedevents, 82 options::OPT_fnoxray_always_emit_typedevents, false)) 83 XRayAlwaysEmitTypedEvents = true; 84 85 if (!Args.hasFlag(options::OPT_fxray_link_deps, 86 options::OPT_fnoxray_link_deps, true)) 87 XRayRT = false; 88 89 auto Bundles = 90 Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle); 91 if (Bundles.empty()) 92 InstrumentationBundle.Mask = XRayInstrKind::All; 93 else 94 for (const auto &B : Bundles) { 95 llvm::SmallVector<StringRef, 2> BundleParts; 96 llvm::SplitString(B, BundleParts, ","); 97 for (const auto &P : BundleParts) { 98 // TODO: Automate the generation of the string case table. 99 auto Valid = llvm::StringSwitch<bool>(P) 100 .Cases("none", "all", "function", "custom", true) 101 .Default(false); 102 103 if (!Valid) { 104 D.Diag(clang::diag::err_drv_invalid_value) 105 << "-fxray-instrumentation-bundle=" << P; 106 continue; 107 } 108 109 auto Mask = parseXRayInstrValue(P); 110 if (Mask == XRayInstrKind::None) { 111 InstrumentationBundle.clear(); 112 break; 113 } 114 115 InstrumentationBundle.Mask |= Mask; 116 } 117 } 118 119 // Validate the always/never attribute files. We also make sure that they 120 // are treated as actual dependencies. 121 for (const auto &Filename : 122 Args.getAllArgValues(options::OPT_fxray_always_instrument)) { 123 if (llvm::sys::fs::exists(Filename)) { 124 AlwaysInstrumentFiles.push_back(Filename); 125 ExtraDeps.push_back(Filename); 126 } else 127 D.Diag(clang::diag::err_drv_no_such_file) << Filename; 128 } 129 130 for (const auto &Filename : 131 Args.getAllArgValues(options::OPT_fxray_never_instrument)) { 132 if (llvm::sys::fs::exists(Filename)) { 133 NeverInstrumentFiles.push_back(Filename); 134 ExtraDeps.push_back(Filename); 135 } else 136 D.Diag(clang::diag::err_drv_no_such_file) << Filename; 137 } 138 139 for (const auto &Filename : 140 Args.getAllArgValues(options::OPT_fxray_attr_list)) { 141 if (llvm::sys::fs::exists(Filename)) { 142 AttrListFiles.push_back(Filename); 143 ExtraDeps.push_back(Filename); 144 } else 145 D.Diag(clang::diag::err_drv_no_such_file) << Filename; 146 } 147 148 // Get the list of modes we want to support. 149 auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes); 150 if (SpecifiedModes.empty()) 151 llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); 152 else 153 for (const auto &Arg : SpecifiedModes) { 154 // Parse CSV values for -fxray-modes=... 155 llvm::SmallVector<StringRef, 2> ModeParts; 156 llvm::SplitString(Arg, ModeParts, ","); 157 for (const auto &M : ModeParts) 158 if (M == "none") 159 Modes.clear(); 160 else if (M == "all") 161 llvm::copy(XRaySupportedModes, std::back_inserter(Modes)); 162 else 163 Modes.push_back(M); 164 } 165 166 // Then we want to sort and unique the modes we've collected. 167 llvm::sort(Modes.begin(), Modes.end()); 168 Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end()); 169 } 170 } 171 172 void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, 173 ArgStringList &CmdArgs, types::ID InputType) const { 174 if (!XRayInstrument) 175 return; 176 177 CmdArgs.push_back(XRayInstrumentOption); 178 179 if (XRayAlwaysEmitCustomEvents) 180 CmdArgs.push_back("-fxray-always-emit-customevents"); 181 182 if (XRayAlwaysEmitTypedEvents) 183 CmdArgs.push_back("-fxray-always-emit-typedevents"); 184 185 CmdArgs.push_back(Args.MakeArgString(Twine(XRayInstructionThresholdOption) + 186 Twine(InstructionThreshold))); 187 188 for (const auto &Always : AlwaysInstrumentFiles) { 189 SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument="); 190 AlwaysInstrumentOpt += Always; 191 CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt)); 192 } 193 194 for (const auto &Never : NeverInstrumentFiles) { 195 SmallString<64> NeverInstrumentOpt("-fxray-never-instrument="); 196 NeverInstrumentOpt += Never; 197 CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt)); 198 } 199 200 for (const auto &AttrFile : AttrListFiles) { 201 SmallString<64> AttrListFileOpt("-fxray-attr-list="); 202 AttrListFileOpt += AttrFile; 203 CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt)); 204 } 205 206 for (const auto &Dep : ExtraDeps) { 207 SmallString<64> ExtraDepOpt("-fdepfile-entry="); 208 ExtraDepOpt += Dep; 209 CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); 210 } 211 212 for (const auto &Mode : Modes) { 213 SmallString<64> ModeOpt("-fxray-modes="); 214 ModeOpt += Mode; 215 CmdArgs.push_back(Args.MakeArgString(ModeOpt)); 216 } 217 } 218