1 //===--- Job.cpp - Command to Execute -------------------------------------===//
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 
10 #include "clang/Driver/Driver.h"
11 #include "clang/Driver/DriverDiagnostic.h"
12 #include "clang/Driver/Job.h"
13 #include "clang/Driver/Tool.h"
14 #include "clang/Driver/ToolChain.h"
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/StringSet.h"
19 #include "llvm/ADT/StringSwitch.h"
20 #include "llvm/Support/Program.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include <cassert>
23 using namespace clang::driver;
24 using llvm::raw_ostream;
25 using llvm::StringRef;
26 using llvm::ArrayRef;
27 
28 Job::~Job() {}
29 
30 Command::Command(const Action &_Source, const Tool &_Creator,
31                  const char *_Executable,
32                  const ArgStringList &_Arguments)
33     : Job(CommandClass), Source(_Source), Creator(_Creator),
34       Executable(_Executable), Arguments(_Arguments),
35       ResponseFile(nullptr) {}
36 
37 static int skipArgs(const char *Flag) {
38   // These flags are all of the form -Flag <Arg> and are treated as two
39   // arguments.  Therefore, we need to skip the flag and the next argument.
40   bool Res = llvm::StringSwitch<bool>(Flag)
41     .Cases("-I", "-MF", "-MT", "-MQ", true)
42     .Cases("-o", "-coverage-file", "-dependency-file", true)
43     .Cases("-fdebug-compilation-dir", "-idirafter", true)
44     .Cases("-include", "-include-pch", "-internal-isystem", true)
45     .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
46     .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
47     .Cases("-resource-dir", "-serialize-diagnostic-file", true)
48     .Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
49     .Default(false);
50 
51   // Match found.
52   if (Res)
53     return 2;
54 
55   // The remaining flags are treated as a single argument.
56 
57   // These flags are all of the form -Flag and have no second argument.
58   Res = llvm::StringSwitch<bool>(Flag)
59     .Cases("-M", "-MM", "-MG", "-MP", "-MD", true)
60     .Case("-MMD", true)
61     .Default(false);
62 
63   // Match found.
64   if (Res)
65     return 1;
66 
67   // These flags are treated as a single argument (e.g., -F<Dir>).
68   StringRef FlagRef(Flag);
69   if (FlagRef.startswith("-F") || FlagRef.startswith("-I") ||
70       FlagRef.startswith("-fmodules-cache-path="))
71     return 1;
72 
73   return 0;
74 }
75 
76 static bool quoteNextArg(const char *flag) {
77   return llvm::StringSwitch<bool>(flag)
78     .Case("-D", true)
79     .Default(false);
80 }
81 
82 static void PrintArg(raw_ostream &OS, const char *Arg, bool Quote) {
83   const bool Escape = std::strpbrk(Arg, "\"\\$");
84 
85   if (!Quote && !Escape) {
86     OS << Arg;
87     return;
88   }
89 
90   // Quote and escape. This isn't really complete, but good enough.
91   OS << '"';
92   while (const char c = *Arg++) {
93     if (c == '"' || c == '\\' || c == '$')
94       OS << '\\';
95     OS << c;
96   }
97   OS << '"';
98 }
99 
100 void Command::writeResponseFile(raw_ostream &OS) const {
101   // In a file list, we only write the set of inputs to the response file
102   if (Creator.getResponseFilesSupport() == Tool::RF_FileList) {
103     for (const char *Arg : InputFileList) {
104       OS << Arg << '\n';
105     }
106     return;
107   }
108 
109   // In regular response files, we send all arguments to the response file
110   for (const char *Arg : Arguments) {
111     OS << '"';
112 
113     for (; *Arg != '\0'; Arg++) {
114       if (*Arg == '\"' || *Arg == '\\') {
115         OS << '\\';
116       }
117       OS << *Arg;
118     }
119 
120     OS << "\" ";
121   }
122 }
123 
124 void Command::buildArgvForResponseFile(
125     llvm::SmallVectorImpl<const char *> &Out) const {
126   // When not a file list, all arguments are sent to the response file.
127   // This leaves us to set the argv to a single parameter, requesting the tool
128   // to read the response file.
129   if (Creator.getResponseFilesSupport() != Tool::RF_FileList) {
130     Out.push_back(Executable);
131     Out.push_back(ResponseFileFlag.c_str());
132     return;
133   }
134 
135   llvm::StringSet<> Inputs;
136   for (const char *InputName : InputFileList)
137     Inputs.insert(InputName);
138   Out.push_back(Executable);
139   // In a file list, build args vector ignoring parameters that will go in the
140   // response file (elements of the InputFileList vector)
141   bool FirstInput = true;
142   for (const char *Arg : Arguments) {
143     if (Inputs.count(Arg) == 0) {
144       Out.push_back(Arg);
145     } else if (FirstInput) {
146       FirstInput = false;
147       Out.push_back(Creator.getResponseFileFlag());
148       Out.push_back(ResponseFile);
149     }
150   }
151 }
152 
153 void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
154                     bool CrashReport) const {
155   // Always quote the exe.
156   OS << ' ';
157   PrintArg(OS, Executable, /*Quote=*/true);
158 
159   llvm::ArrayRef<const char *> Args = Arguments;
160   llvm::SmallVector<const char *, 128> ArgsRespFile;
161   if (ResponseFile != nullptr) {
162     buildArgvForResponseFile(ArgsRespFile);
163     Args = ArrayRef<const char *>(ArgsRespFile).slice(1); // no executable name
164   }
165 
166   for (size_t i = 0, e = Args.size(); i < e; ++i) {
167     const char *const Arg = Args[i];
168 
169     if (CrashReport) {
170       if (int Skip = skipArgs(Arg)) {
171         i += Skip - 1;
172         continue;
173       }
174     }
175 
176     OS << ' ';
177     PrintArg(OS, Arg, Quote);
178 
179     if (CrashReport && quoteNextArg(Arg) && i + 1 < e) {
180       OS << ' ';
181       PrintArg(OS, Args[++i], true);
182     }
183   }
184 
185   if (ResponseFile != nullptr) {
186     OS << "\n Arguments passed via response file:\n";
187     writeResponseFile(OS);
188     // Avoiding duplicated newline terminator, since FileLists are
189     // newline-separated.
190     if (Creator.getResponseFilesSupport() != Tool::RF_FileList)
191       OS << "\n";
192     OS << " (end of response file)";
193   }
194 
195   OS << Terminator;
196 }
197 
198 void Command::setResponseFile(const char *FileName) {
199   ResponseFile = FileName;
200   ResponseFileFlag = Creator.getResponseFileFlag();
201   ResponseFileFlag += FileName;
202 }
203 
204 int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
205                      bool *ExecutionFailed) const {
206   SmallVector<const char*, 128> Argv;
207 
208   if (ResponseFile == nullptr) {
209     Argv.push_back(Executable);
210     for (size_t i = 0, e = Arguments.size(); i != e; ++i)
211       Argv.push_back(Arguments[i]);
212     Argv.push_back(nullptr);
213 
214     return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
215                                      Redirects, /*secondsToWait*/ 0,
216                                      /*memoryLimit*/ 0, ErrMsg,
217                                      ExecutionFailed);
218   }
219 
220   // We need to put arguments in a response file (command is too large)
221   // Open stream to store the response file contents
222   std::string RespContents;
223   llvm::raw_string_ostream SS(RespContents);
224 
225   // Write file contents and build the Argv vector
226   writeResponseFile(SS);
227   buildArgvForResponseFile(Argv);
228   Argv.push_back(nullptr);
229   SS.flush();
230 
231   // Save the response file in the appropriate encoding
232   if (std::error_code EC = writeFileWithEncoding(
233           ResponseFile, RespContents, Creator.getResponseFileEncoding())) {
234     if (ErrMsg)
235       *ErrMsg = EC.message();
236     if (ExecutionFailed)
237       *ExecutionFailed = true;
238     return -1;
239   }
240 
241   return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
242                                    Redirects, /*secondsToWait*/ 0,
243                                    /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
244 }
245 
246 FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
247                                  const char *Executable_,
248                                  const ArgStringList &Arguments_,
249                                  std::unique_ptr<Command> Fallback_)
250     : Command(Source_, Creator_, Executable_, Arguments_),
251       Fallback(std::move(Fallback_)) {}
252 
253 void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
254                             bool Quote, bool CrashReport) const {
255   Command::Print(OS, "", Quote, CrashReport);
256   OS << " ||";
257   Fallback->Print(OS, Terminator, Quote, CrashReport);
258 }
259 
260 static bool ShouldFallback(int ExitCode) {
261   // FIXME: We really just want to fall back for internal errors, such
262   // as when some symbol cannot be mangled, when we should be able to
263   // parse something but can't, etc.
264   return ExitCode != 0;
265 }
266 
267 int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
268                              bool *ExecutionFailed) const {
269   int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
270   if (!ShouldFallback(PrimaryStatus))
271     return PrimaryStatus;
272 
273   // Clear ExecutionFailed and ErrMsg before falling back.
274   if (ErrMsg)
275     ErrMsg->clear();
276   if (ExecutionFailed)
277     *ExecutionFailed = false;
278 
279   const Driver &D = getCreator().getToolChain().getDriver();
280   D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
281 
282   int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
283   return SecondaryStatus;
284 }
285 
286 JobList::JobList() : Job(JobListClass) {}
287 
288 void JobList::Print(raw_ostream &OS, const char *Terminator, bool Quote,
289                     bool CrashReport) const {
290   for (const_iterator it = begin(), ie = end(); it != ie; ++it)
291     (*it)->Print(OS, Terminator, Quote, CrashReport);
292 }
293 
294 void JobList::clear() { Jobs.clear(); }
295