clang  19.0.0git
XRayArgs.cpp
Go to the documentation of this file.
1 //===--- XRayArgs.cpp - Arguments for XRay --------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
10 #include "clang/Driver/Driver.h"
12 #include "clang/Driver/Options.h"
13 #include "clang/Driver/ToolChain.h"
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/Support/Path.h"
17 #include "llvm/Support/ScopedPrinter.h"
18 #include "llvm/Support/SpecialCaseList.h"
19 #include "llvm/Support/VirtualFileSystem.h"
20 
21 using namespace clang;
22 using namespace clang::driver;
23 using namespace llvm::opt;
24 
25 constexpr const char *XRaySupportedModes[] = {"xray-fdr", "xray-basic"};
26 
27 XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
28  const Driver &D = TC.getDriver();
29  const llvm::Triple &Triple = TC.getTriple();
30  if (!Args.hasFlag(options::OPT_fxray_instrument,
31  options::OPT_fno_xray_instrument, false))
32  return;
33  XRayInstrument = Args.getLastArg(options::OPT_fxray_instrument);
34  if (Triple.isMacOSX()) {
35  switch (Triple.getArch()) {
36  case llvm::Triple::aarch64:
37  case llvm::Triple::x86_64:
38  break;
39  default:
40  D.Diag(diag::err_drv_unsupported_opt_for_target)
41  << XRayInstrument->getSpelling() << Triple.str();
42  break;
43  }
44  } else if (Triple.isOSBinFormatELF()) {
45  switch (Triple.getArch()) {
46  case llvm::Triple::x86_64:
47  case llvm::Triple::arm:
48  case llvm::Triple::aarch64:
49  case llvm::Triple::hexagon:
50  case llvm::Triple::ppc64le:
51  case llvm::Triple::loongarch64:
52  case llvm::Triple::mips:
53  case llvm::Triple::mipsel:
54  case llvm::Triple::mips64:
55  case llvm::Triple::mips64el:
56  break;
57  default:
58  D.Diag(diag::err_drv_unsupported_opt_for_target)
59  << XRayInstrument->getSpelling() << Triple.str();
60  }
61  } else {
62  D.Diag(diag::err_drv_unsupported_opt_for_target)
63  << XRayInstrument->getSpelling() << Triple.str();
64  }
65 
66  // Both XRay and -fpatchable-function-entry use
67  // TargetOpcode::PATCHABLE_FUNCTION_ENTER.
68  if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ))
69  D.Diag(diag::err_drv_argument_not_allowed_with)
70  << XRayInstrument->getSpelling() << A->getSpelling();
71 
72  if (!Args.hasFlag(options::OPT_fxray_link_deps,
73  options::OPT_fno_xray_link_deps, true))
74  XRayRT = false;
75 
76  auto Bundles =
77  Args.getAllArgValues(options::OPT_fxray_instrumentation_bundle);
78  if (Bundles.empty())
79  InstrumentationBundle.Mask = XRayInstrKind::All;
80  else
81  for (const auto &B : Bundles) {
83  llvm::SplitString(B, BundleParts, ",");
84  for (const auto &P : BundleParts) {
85  // TODO: Automate the generation of the string case table.
86  auto Valid = llvm::StringSwitch<bool>(P)
87  .Cases("none", "all", "function", "function-entry",
88  "function-exit", "custom", true)
89  .Default(false);
90 
91  if (!Valid) {
92  D.Diag(clang::diag::err_drv_invalid_value)
93  << "-fxray-instrumentation-bundle=" << P;
94  continue;
95  }
96 
97  auto Mask = parseXRayInstrValue(P);
98  if (Mask == XRayInstrKind::None) {
99  InstrumentationBundle.clear();
100  break;
101  }
102 
103  InstrumentationBundle.Mask |= Mask;
104  }
105  }
106 
107  // Validate the always/never attribute files. We also make sure that they
108  // are treated as actual dependencies.
109  for (const auto &Filename :
110  Args.getAllArgValues(options::OPT_fxray_always_instrument)) {
111  if (D.getVFS().exists(Filename)) {
112  AlwaysInstrumentFiles.push_back(Filename);
113  ExtraDeps.push_back(Filename);
114  } else
115  D.Diag(clang::diag::err_drv_no_such_file) << Filename;
116  }
117 
118  for (const auto &Filename :
119  Args.getAllArgValues(options::OPT_fxray_never_instrument)) {
120  if (D.getVFS().exists(Filename)) {
121  NeverInstrumentFiles.push_back(Filename);
122  ExtraDeps.push_back(Filename);
123  } else
124  D.Diag(clang::diag::err_drv_no_such_file) << Filename;
125  }
126 
127  for (const auto &Filename :
128  Args.getAllArgValues(options::OPT_fxray_attr_list)) {
129  if (D.getVFS().exists(Filename)) {
130  AttrListFiles.push_back(Filename);
131  ExtraDeps.push_back(Filename);
132  } else
133  D.Diag(clang::diag::err_drv_no_such_file) << Filename;
134  }
135 
136  // Get the list of modes we want to support.
137  auto SpecifiedModes = Args.getAllArgValues(options::OPT_fxray_modes);
138  if (SpecifiedModes.empty())
139  llvm::copy(XRaySupportedModes, std::back_inserter(Modes));
140  else
141  for (const auto &Arg : SpecifiedModes) {
142  // Parse CSV values for -fxray-modes=...
144  llvm::SplitString(Arg, ModeParts, ",");
145  for (const auto &M : ModeParts)
146  if (M == "none")
147  Modes.clear();
148  else if (M == "all")
149  llvm::copy(XRaySupportedModes, std::back_inserter(Modes));
150  else
151  Modes.push_back(std::string(M));
152  }
153 
154  // Then we want to sort and unique the modes we've collected.
155  llvm::sort(Modes);
156  Modes.erase(std::unique(Modes.begin(), Modes.end()), Modes.end());
157 }
158 
159 void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args,
160  ArgStringList &CmdArgs, types::ID InputType) const {
161  if (!XRayInstrument)
162  return;
163  const Driver &D = TC.getDriver();
164  XRayInstrument->render(Args, CmdArgs);
165 
166  // By default, the back-end will not emit the lowering for XRay customevent
167  // calls if the function is not instrumented. In the future we will change
168  // this default to be the reverse, but in the meantime we're going to
169  // introduce the new functionality behind a flag.
170  Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_customevents,
171  options::OPT_fno_xray_always_emit_customevents);
172 
173  Args.addOptInFlag(CmdArgs, options::OPT_fxray_always_emit_typedevents,
174  options::OPT_fno_xray_always_emit_typedevents);
175  Args.addOptInFlag(CmdArgs, options::OPT_fxray_ignore_loops,
176  options::OPT_fno_xray_ignore_loops);
177  Args.addOptOutFlag(CmdArgs, options::OPT_fxray_function_index,
178  options::OPT_fno_xray_function_index);
179 
180  if (const Arg *A =
181  Args.getLastArg(options::OPT_fxray_instruction_threshold_EQ)) {
182  int Value;
183  StringRef S = A->getValue();
184  if (S.getAsInteger(0, Value) || Value < 0)
185  D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
186  else
187  A->render(Args, CmdArgs);
188  }
189 
190  int XRayFunctionGroups = 1;
191  int XRaySelectedFunctionGroup = 0;
192  if (const Arg *A = Args.getLastArg(options::OPT_fxray_function_groups)) {
193  StringRef S = A->getValue();
194  if (S.getAsInteger(0, XRayFunctionGroups) || XRayFunctionGroups < 1)
195  D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
196  if (XRayFunctionGroups > 1)
197  A->render(Args, CmdArgs);
198  }
199  if (const Arg *A =
200  Args.getLastArg(options::OPT_fxray_selected_function_group)) {
201  StringRef S = A->getValue();
202  if (S.getAsInteger(0, XRaySelectedFunctionGroup) ||
203  XRaySelectedFunctionGroup < 0 ||
204  XRaySelectedFunctionGroup >= XRayFunctionGroups)
205  D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
206  if (XRaySelectedFunctionGroup != 0)
207  A->render(Args, CmdArgs);
208  }
209 
210  for (const auto &Always : AlwaysInstrumentFiles) {
211  SmallString<64> AlwaysInstrumentOpt("-fxray-always-instrument=");
212  AlwaysInstrumentOpt += Always;
213  CmdArgs.push_back(Args.MakeArgString(AlwaysInstrumentOpt));
214  }
215 
216  for (const auto &Never : NeverInstrumentFiles) {
217  SmallString<64> NeverInstrumentOpt("-fxray-never-instrument=");
218  NeverInstrumentOpt += Never;
219  CmdArgs.push_back(Args.MakeArgString(NeverInstrumentOpt));
220  }
221 
222  for (const auto &AttrFile : AttrListFiles) {
223  SmallString<64> AttrListFileOpt("-fxray-attr-list=");
224  AttrListFileOpt += AttrFile;
225  CmdArgs.push_back(Args.MakeArgString(AttrListFileOpt));
226  }
227 
228  for (const auto &Dep : ExtraDeps) {
229  SmallString<64> ExtraDepOpt("-fdepfile-entry=");
230  ExtraDepOpt += Dep;
231  CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt));
232  }
233 
234  for (const auto &Mode : Modes) {
235  SmallString<64> ModeOpt("-fxray-modes=");
236  ModeOpt += Mode;
237  CmdArgs.push_back(Args.MakeArgString(ModeOpt));
238  }
239 
240  SmallString<64> Bundle("-fxray-instrumentation-bundle=");
241  if (InstrumentationBundle.full()) {
242  Bundle += "all";
243  } else if (InstrumentationBundle.empty()) {
244  Bundle += "none";
245  } else {
246  if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry) &&
247  InstrumentationBundle.has(XRayInstrKind::FunctionExit))
248  Bundle += "function";
249  else if (InstrumentationBundle.has(XRayInstrKind::FunctionEntry))
250  Bundle += "function-entry";
251  else if (InstrumentationBundle.has(XRayInstrKind::FunctionExit))
252  Bundle += "function-exit";
253 
254  if (InstrumentationBundle.has(XRayInstrKind::Custom))
255  Bundle += "custom";
256  if (InstrumentationBundle.has(XRayInstrKind::Typed))
257  Bundle += "typed";
258  }
259  CmdArgs.push_back(Args.MakeArgString(Bundle));
260 }
StringRef P
StringRef Filename
Definition: Format.cpp:2976
constexpr const char * XRaySupportedModes[]
Definition: XRayArgs.cpp:25
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:77
llvm::vfs::FileSystem & getVFS() const
Definition: Driver.h:405
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:146
ToolChain - Access to tools for a single platform.
Definition: ToolChain.h:92
const Driver & getDriver() const
Definition: ToolChain.h:269
const llvm::Triple & getTriple() const
Definition: ToolChain.h:271
void addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const
Definition: XRayArgs.cpp:159
XRayArgs(const ToolChain &TC, const llvm::opt::ArgList &Args)
Parses the XRay arguments from an argument list.
Definition: XRayArgs.cpp:27
constexpr XRayInstrMask Typed
Definition: XRayInstr.h:42
constexpr XRayInstrMask FunctionExit
Definition: XRayInstr.h:40
constexpr XRayInstrMask None
Definition: XRayInstr.h:38
constexpr XRayInstrMask FunctionEntry
Definition: XRayInstr.h:39
constexpr XRayInstrMask All
Definition: XRayInstr.h:43
constexpr XRayInstrMask Custom
Definition: XRayInstr.h:41
The JSON file list parser is used to communicate input to InstallAPI.
XRayInstrMask parseXRayInstrValue(StringRef Value)
Parses a command line argument into a mask.
Definition: XRayInstr.cpp:19