1 //===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
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 //===----------------------------------------------------------------------===//
8 //
9 // This is the entry point to the clang driver; it is a thin wrapper
10 // for functionality in the Driver clang library.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/Driver/Driver.h"
15 #include "clang/Basic/DiagnosticOptions.h"
16 #include "clang/Basic/HeaderInclude.h"
17 #include "clang/Basic/Stack.h"
18 #include "clang/Config/config.h"
19 #include "clang/Driver/Compilation.h"
20 #include "clang/Driver/DriverDiagnostic.h"
21 #include "clang/Driver/Options.h"
22 #include "clang/Driver/ToolChain.h"
23 #include "clang/Frontend/ChainedDiagnosticConsumer.h"
24 #include "clang/Frontend/CompilerInvocation.h"
25 #include "clang/Frontend/SerializedDiagnosticPrinter.h"
26 #include "clang/Frontend/TextDiagnosticPrinter.h"
27 #include "clang/Frontend/Utils.h"
28 #include "llvm/ADT/ArrayRef.h"
29 #include "llvm/ADT/SmallString.h"
30 #include "llvm/ADT/SmallVector.h"
31 #include "llvm/Option/ArgList.h"
32 #include "llvm/Option/OptTable.h"
33 #include "llvm/Option/Option.h"
34 #include "llvm/Support/BuryPointer.h"
35 #include "llvm/Support/CommandLine.h"
36 #include "llvm/Support/CrashRecoveryContext.h"
37 #include "llvm/Support/ErrorHandling.h"
38 #include "llvm/Support/FileSystem.h"
39 #include "llvm/Support/Host.h"
40 #include "llvm/Support/InitLLVM.h"
41 #include "llvm/Support/Path.h"
42 #include "llvm/Support/PrettyStackTrace.h"
43 #include "llvm/Support/Process.h"
44 #include "llvm/Support/Program.h"
45 #include "llvm/Support/Regex.h"
46 #include "llvm/Support/Signals.h"
47 #include "llvm/Support/StringSaver.h"
48 #include "llvm/Support/TargetSelect.h"
49 #include "llvm/Support/Timer.h"
50 #include "llvm/Support/raw_ostream.h"
51 #include <memory>
52 #include <optional>
53 #include <set>
54 #include <system_error>
55 using namespace clang;
56 using namespace clang::driver;
57 using namespace llvm::opt;
58
GetExecutablePath(const char * Argv0,bool CanonicalPrefixes)59 std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
60 if (!CanonicalPrefixes) {
61 SmallString<128> ExecutablePath(Argv0);
62 // Do a PATH lookup if Argv0 isn't a valid path.
63 if (!llvm::sys::fs::exists(ExecutablePath))
64 if (llvm::ErrorOr<std::string> P =
65 llvm::sys::findProgramByName(ExecutablePath))
66 ExecutablePath = *P;
67 return std::string(ExecutablePath.str());
68 }
69
70 // This just needs to be some symbol in the binary; C++ doesn't
71 // allow taking the address of ::main however.
72 void *P = (void*) (intptr_t) GetExecutablePath;
73 return llvm::sys::fs::getMainExecutable(Argv0, P);
74 }
75
GetStableCStr(std::set<std::string> & SavedStrings,StringRef S)76 static const char *GetStableCStr(std::set<std::string> &SavedStrings,
77 StringRef S) {
78 return SavedStrings.insert(std::string(S)).first->c_str();
79 }
80
81 /// ApplyQAOverride - Apply a list of edits to the input argument lists.
82 ///
83 /// The input string is a space separate list of edits to perform,
84 /// they are applied in order to the input argument lists. Edits
85 /// should be one of the following forms:
86 ///
87 /// '#': Silence information about the changes to the command line arguments.
88 ///
89 /// '^': Add FOO as a new argument at the beginning of the command line.
90 ///
91 /// '+': Add FOO as a new argument at the end of the command line.
92 ///
93 /// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
94 /// line.
95 ///
96 /// 'xOPTION': Removes all instances of the literal argument OPTION.
97 ///
98 /// 'XOPTION': Removes all instances of the literal argument OPTION,
99 /// and the following argument.
100 ///
101 /// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
102 /// at the end of the command line.
103 ///
104 /// \param OS - The stream to write edit information to.
105 /// \param Args - The vector of command line arguments.
106 /// \param Edit - The override command to perform.
107 /// \param SavedStrings - Set to use for storing string representations.
ApplyOneQAOverride(raw_ostream & OS,SmallVectorImpl<const char * > & Args,StringRef Edit,std::set<std::string> & SavedStrings)108 static void ApplyOneQAOverride(raw_ostream &OS,
109 SmallVectorImpl<const char*> &Args,
110 StringRef Edit,
111 std::set<std::string> &SavedStrings) {
112 // This does not need to be efficient.
113
114 if (Edit[0] == '^') {
115 const char *Str =
116 GetStableCStr(SavedStrings, Edit.substr(1));
117 OS << "### Adding argument " << Str << " at beginning\n";
118 Args.insert(Args.begin() + 1, Str);
119 } else if (Edit[0] == '+') {
120 const char *Str =
121 GetStableCStr(SavedStrings, Edit.substr(1));
122 OS << "### Adding argument " << Str << " at end\n";
123 Args.push_back(Str);
124 } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
125 Edit.slice(2, Edit.size() - 1).contains('/')) {
126 StringRef MatchPattern = Edit.substr(2).split('/').first;
127 StringRef ReplPattern = Edit.substr(2).split('/').second;
128 ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
129
130 for (unsigned i = 1, e = Args.size(); i != e; ++i) {
131 // Ignore end-of-line response file markers
132 if (Args[i] == nullptr)
133 continue;
134 std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
135
136 if (Repl != Args[i]) {
137 OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
138 Args[i] = GetStableCStr(SavedStrings, Repl);
139 }
140 }
141 } else if (Edit[0] == 'x' || Edit[0] == 'X') {
142 auto Option = Edit.substr(1);
143 for (unsigned i = 1; i < Args.size();) {
144 if (Option == Args[i]) {
145 OS << "### Deleting argument " << Args[i] << '\n';
146 Args.erase(Args.begin() + i);
147 if (Edit[0] == 'X') {
148 if (i < Args.size()) {
149 OS << "### Deleting argument " << Args[i] << '\n';
150 Args.erase(Args.begin() + i);
151 } else
152 OS << "### Invalid X edit, end of command line!\n";
153 }
154 } else
155 ++i;
156 }
157 } else if (Edit[0] == 'O') {
158 for (unsigned i = 1; i < Args.size();) {
159 const char *A = Args[i];
160 // Ignore end-of-line response file markers
161 if (A == nullptr)
162 continue;
163 if (A[0] == '-' && A[1] == 'O' &&
164 (A[2] == '\0' ||
165 (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
166 ('0' <= A[2] && A[2] <= '9'))))) {
167 OS << "### Deleting argument " << Args[i] << '\n';
168 Args.erase(Args.begin() + i);
169 } else
170 ++i;
171 }
172 OS << "### Adding argument " << Edit << " at end\n";
173 Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
174 } else {
175 OS << "### Unrecognized edit: " << Edit << "\n";
176 }
177 }
178
179 /// ApplyQAOverride - Apply a comma separate list of edits to the
180 /// input argument lists. See ApplyOneQAOverride.
ApplyQAOverride(SmallVectorImpl<const char * > & Args,const char * OverrideStr,std::set<std::string> & SavedStrings)181 static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
182 const char *OverrideStr,
183 std::set<std::string> &SavedStrings) {
184 raw_ostream *OS = &llvm::errs();
185
186 if (OverrideStr[0] == '#') {
187 ++OverrideStr;
188 OS = &llvm::nulls();
189 }
190
191 *OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
192
193 // This does not need to be efficient.
194
195 const char *S = OverrideStr;
196 while (*S) {
197 const char *End = ::strchr(S, ' ');
198 if (!End)
199 End = S + strlen(S);
200 if (End != S)
201 ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
202 S = End;
203 if (*S != '\0')
204 ++S;
205 }
206 }
207
208 extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
209 void *MainAddr);
210 extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
211 void *MainAddr);
212 extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
213 const char *Argv0, void *MainAddr);
214
insertTargetAndModeArgs(const ParsedClangName & NameParts,SmallVectorImpl<const char * > & ArgVector,std::set<std::string> & SavedStrings)215 static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
216 SmallVectorImpl<const char *> &ArgVector,
217 std::set<std::string> &SavedStrings) {
218 // Put target and mode arguments at the start of argument list so that
219 // arguments specified in command line could override them. Avoid putting
220 // them at index 0, as an option like '-cc1' must remain the first.
221 int InsertionPoint = 0;
222 if (ArgVector.size() > 0)
223 ++InsertionPoint;
224
225 if (NameParts.DriverMode) {
226 // Add the mode flag to the arguments.
227 ArgVector.insert(ArgVector.begin() + InsertionPoint,
228 GetStableCStr(SavedStrings, NameParts.DriverMode));
229 }
230
231 if (NameParts.TargetIsValid) {
232 const char *arr[] = {"-target", GetStableCStr(SavedStrings,
233 NameParts.TargetPrefix)};
234 ArgVector.insert(ArgVector.begin() + InsertionPoint,
235 std::begin(arr), std::end(arr));
236 }
237 }
238
getCLEnvVarOptions(std::string & EnvValue,llvm::StringSaver & Saver,SmallVectorImpl<const char * > & Opts)239 static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
240 SmallVectorImpl<const char *> &Opts) {
241 llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts);
242 // The first instance of '#' should be replaced with '=' in each option.
243 for (const char *Opt : Opts)
244 if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#')))
245 *NumberSignPtr = '=';
246 }
247
248 template <class T>
checkEnvVar(const char * EnvOptSet,const char * EnvOptFile,std::string & OptFile)249 static T checkEnvVar(const char *EnvOptSet, const char *EnvOptFile,
250 std::string &OptFile) {
251 const char *Str = ::getenv(EnvOptSet);
252 if (!Str)
253 return T{};
254
255 T OptVal = Str;
256 if (const char *Var = ::getenv(EnvOptFile))
257 OptFile = Var;
258 return OptVal;
259 }
260
SetBackdoorDriverOutputsFromEnvVars(Driver & TheDriver)261 static bool SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
262 TheDriver.CCPrintOptions =
263 checkEnvVar<bool>("CC_PRINT_OPTIONS", "CC_PRINT_OPTIONS_FILE",
264 TheDriver.CCPrintOptionsFilename);
265 if (checkEnvVar<bool>("CC_PRINT_HEADERS", "CC_PRINT_HEADERS_FILE",
266 TheDriver.CCPrintHeadersFilename)) {
267 TheDriver.CCPrintHeadersFormat = HIFMT_Textual;
268 TheDriver.CCPrintHeadersFiltering = HIFIL_None;
269 } else {
270 std::string EnvVar = checkEnvVar<std::string>(
271 "CC_PRINT_HEADERS_FORMAT", "CC_PRINT_HEADERS_FILE",
272 TheDriver.CCPrintHeadersFilename);
273 if (!EnvVar.empty()) {
274 TheDriver.CCPrintHeadersFormat =
275 stringToHeaderIncludeFormatKind(EnvVar.c_str());
276 if (!TheDriver.CCPrintHeadersFormat) {
277 TheDriver.Diag(clang::diag::err_drv_print_header_env_var)
278 << 0 << EnvVar;
279 return false;
280 }
281
282 const char *FilteringStr = ::getenv("CC_PRINT_HEADERS_FILTERING");
283 HeaderIncludeFilteringKind Filtering;
284 if (!stringToHeaderIncludeFiltering(FilteringStr, Filtering)) {
285 TheDriver.Diag(clang::diag::err_drv_print_header_env_var)
286 << 1 << FilteringStr;
287 return false;
288 }
289
290 if ((TheDriver.CCPrintHeadersFormat == HIFMT_Textual &&
291 Filtering != HIFIL_None) ||
292 (TheDriver.CCPrintHeadersFormat == HIFMT_JSON &&
293 Filtering != HIFIL_Only_Direct_System)) {
294 TheDriver.Diag(clang::diag::err_drv_print_header_env_var_combination)
295 << EnvVar << FilteringStr;
296 return false;
297 }
298 TheDriver.CCPrintHeadersFiltering = Filtering;
299 }
300 }
301
302 TheDriver.CCLogDiagnostics =
303 checkEnvVar<bool>("CC_LOG_DIAGNOSTICS", "CC_LOG_DIAGNOSTICS_FILE",
304 TheDriver.CCLogDiagnosticsFilename);
305 TheDriver.CCPrintProcessStats =
306 checkEnvVar<bool>("CC_PRINT_PROC_STAT", "CC_PRINT_PROC_STAT_FILE",
307 TheDriver.CCPrintStatReportFilename);
308
309 return true;
310 }
311
FixupDiagPrefixExeName(TextDiagnosticPrinter * DiagClient,const std::string & Path)312 static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
313 const std::string &Path) {
314 // If the clang binary happens to be named cl.exe for compatibility reasons,
315 // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
316 StringRef ExeBasename(llvm::sys::path::stem(Path));
317 if (ExeBasename.equals_insensitive("cl"))
318 ExeBasename = "clang-cl";
319 DiagClient->setPrefix(std::string(ExeBasename));
320 }
321
SetInstallDir(SmallVectorImpl<const char * > & argv,Driver & TheDriver,bool CanonicalPrefixes)322 static void SetInstallDir(SmallVectorImpl<const char *> &argv,
323 Driver &TheDriver, bool CanonicalPrefixes) {
324 // Attempt to find the original path used to invoke the driver, to determine
325 // the installed path. We do this manually, because we want to support that
326 // path being a symlink.
327 SmallString<128> InstalledPath(argv[0]);
328
329 // Do a PATH lookup, if there are no directory components.
330 if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
331 if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
332 llvm::sys::path::filename(InstalledPath.str())))
333 InstalledPath = *Tmp;
334
335 // FIXME: We don't actually canonicalize this, we just make it absolute.
336 if (CanonicalPrefixes)
337 llvm::sys::fs::make_absolute(InstalledPath);
338
339 StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
340 if (llvm::sys::fs::exists(InstalledPathParent))
341 TheDriver.setInstalledDir(InstalledPathParent);
342 }
343
ExecuteCC1Tool(SmallVectorImpl<const char * > & ArgV)344 static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
345 // If we call the cc1 tool from the clangDriver library (through
346 // Driver::CC1Main), we need to clean up the options usage count. The options
347 // are currently global, and they might have been used previously by the
348 // driver.
349 llvm::cl::ResetAllOptionOccurrences();
350
351 llvm::BumpPtrAllocator A;
352 llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine);
353 if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) {
354 llvm::errs() << toString(std::move(Err)) << '\n';
355 return 1;
356 }
357 StringRef Tool = ArgV[1];
358 void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
359 if (Tool == "-cc1")
360 return cc1_main(ArrayRef(ArgV).slice(1), ArgV[0], GetExecutablePathVP);
361 if (Tool == "-cc1as")
362 return cc1as_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP);
363 if (Tool == "-cc1gen-reproducer")
364 return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0],
365 GetExecutablePathVP);
366 // Reject unknown tools.
367 llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
368 << "Valid tools include '-cc1' and '-cc1as'.\n";
369 return 1;
370 }
371
clang_main(int Argc,char ** Argv)372 int clang_main(int Argc, char **Argv) {
373 noteBottomOfStack();
374 llvm::InitLLVM X(Argc, Argv);
375 llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL
376 " and include the crash backtrace, preprocessed "
377 "source, and associated run script.\n");
378 SmallVector<const char *, 256> Args(Argv, Argv + Argc);
379
380 if (llvm::sys::Process::FixupStandardFileDescriptors())
381 return 1;
382
383 llvm::InitializeAllTargets();
384
385 llvm::BumpPtrAllocator A;
386 llvm::StringSaver Saver(A);
387
388 // Parse response files using the GNU syntax, unless we're in CL mode. There
389 // are two ways to put clang in CL compatibility mode: Args[0] is either
390 // clang-cl or cl, or --driver-mode=cl is on the command line. The normal
391 // command line parsing can't happen until after response file parsing, so we
392 // have to manually search for a --driver-mode=cl argument the hard way.
393 // Finally, our -cc1 tools don't care which tokenization mode we use because
394 // response files written by clang will tokenize the same way in either mode.
395 bool ClangCLMode =
396 IsClangCL(getDriverMode(Args[0], llvm::ArrayRef(Args).slice(1)));
397 enum { Default, POSIX, Windows } RSPQuoting = Default;
398 for (const char *F : Args) {
399 if (strcmp(F, "--rsp-quoting=posix") == 0)
400 RSPQuoting = POSIX;
401 else if (strcmp(F, "--rsp-quoting=windows") == 0)
402 RSPQuoting = Windows;
403 }
404
405 // Determines whether we want nullptr markers in Args to indicate response
406 // files end-of-lines. We only use this for the /LINK driver argument with
407 // clang-cl.exe on Windows.
408 bool MarkEOLs = ClangCLMode;
409
410 llvm::cl::TokenizerCallback Tokenizer;
411 if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
412 Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
413 else
414 Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
415
416 if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).startswith("-cc1"))
417 MarkEOLs = false;
418 llvm::cl::ExpansionContext ECtx(A, Tokenizer);
419 ECtx.setMarkEOLs(MarkEOLs);
420 if (llvm::Error Err = ECtx.expandResponseFiles(Args)) {
421 llvm::errs() << toString(std::move(Err)) << '\n';
422 return 1;
423 }
424
425 // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
426 // file.
427 auto FirstArg = llvm::find_if(llvm::drop_begin(Args),
428 [](const char *A) { return A != nullptr; });
429 if (FirstArg != Args.end() && StringRef(*FirstArg).startswith("-cc1")) {
430 // If -cc1 came from a response file, remove the EOL sentinels.
431 if (MarkEOLs) {
432 auto newEnd = std::remove(Args.begin(), Args.end(), nullptr);
433 Args.resize(newEnd - Args.begin());
434 }
435 return ExecuteCC1Tool(Args);
436 }
437
438 // Handle options that need handling before the real command line parsing in
439 // Driver::BuildCompilation()
440 bool CanonicalPrefixes = true;
441 for (int i = 1, size = Args.size(); i < size; ++i) {
442 // Skip end-of-line response file markers
443 if (Args[i] == nullptr)
444 continue;
445 if (StringRef(Args[i]) == "-canonical-prefixes")
446 CanonicalPrefixes = true;
447 else if (StringRef(Args[i]) == "-no-canonical-prefixes")
448 CanonicalPrefixes = false;
449 }
450
451 // Handle CL and _CL_ which permits additional command line options to be
452 // prepended or appended.
453 if (ClangCLMode) {
454 // Arguments in "CL" are prepended.
455 std::optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
456 if (OptCL) {
457 SmallVector<const char *, 8> PrependedOpts;
458 getCLEnvVarOptions(*OptCL, Saver, PrependedOpts);
459
460 // Insert right after the program name to prepend to the argument list.
461 Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
462 }
463 // Arguments in "_CL_" are appended.
464 std::optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
465 if (Opt_CL_) {
466 SmallVector<const char *, 8> AppendedOpts;
467 getCLEnvVarOptions(*Opt_CL_, Saver, AppendedOpts);
468
469 // Insert at the end of the argument list to append.
470 Args.append(AppendedOpts.begin(), AppendedOpts.end());
471 }
472 }
473
474 std::set<std::string> SavedStrings;
475 // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
476 // scenes.
477 if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
478 // FIXME: Driver shouldn't take extra initial argument.
479 ApplyQAOverride(Args, OverrideStr, SavedStrings);
480 }
481
482 std::string Path = GetExecutablePath(Args[0], CanonicalPrefixes);
483
484 // Whether the cc1 tool should be called inside the current process, or if we
485 // should spawn a new clang subprocess (old behavior).
486 // Not having an additional process saves some execution time of Windows,
487 // and makes debugging and profiling easier.
488 bool UseNewCC1Process = CLANG_SPAWN_CC1;
489 for (const char *Arg : Args)
490 UseNewCC1Process = llvm::StringSwitch<bool>(Arg)
491 .Case("-fno-integrated-cc1", true)
492 .Case("-fintegrated-cc1", false)
493 .Default(UseNewCC1Process);
494
495 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
496 CreateAndPopulateDiagOpts(Args);
497
498 TextDiagnosticPrinter *DiagClient
499 = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
500 FixupDiagPrefixExeName(DiagClient, Path);
501
502 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
503
504 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
505
506 if (!DiagOpts->DiagnosticSerializationFile.empty()) {
507 auto SerializedConsumer =
508 clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
509 &*DiagOpts, /*MergeChildRecords=*/true);
510 Diags.setClient(new ChainedDiagnosticConsumer(
511 Diags.takeClient(), std::move(SerializedConsumer)));
512 }
513
514 ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
515
516 Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
517 SetInstallDir(Args, TheDriver, CanonicalPrefixes);
518 auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Args[0]);
519 TheDriver.setTargetAndMode(TargetAndMode);
520
521 insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings);
522
523 if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver))
524 return 1;
525
526 if (!UseNewCC1Process) {
527 TheDriver.CC1Main = &ExecuteCC1Tool;
528 // Ensure the CC1Command actually catches cc1 crashes
529 llvm::CrashRecoveryContext::Enable();
530 }
531
532 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args));
533
534 Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash;
535 if (Arg *A = C->getArgs().getLastArg(options::OPT_gen_reproducer_eq)) {
536 auto Level =
537 llvm::StringSwitch<std::optional<Driver::ReproLevel>>(A->getValue())
538 .Case("off", Driver::ReproLevel::Off)
539 .Case("crash", Driver::ReproLevel::OnCrash)
540 .Case("error", Driver::ReproLevel::OnError)
541 .Case("always", Driver::ReproLevel::Always)
542 .Default(std::nullopt);
543 if (!Level) {
544 llvm::errs() << "Unknown value for " << A->getSpelling() << ": '"
545 << A->getValue() << "'\n";
546 return 1;
547 }
548 ReproLevel = *Level;
549 }
550 if (!!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
551 ReproLevel = Driver::ReproLevel::Always;
552
553 int Res = 1;
554 bool IsCrash = false;
555 Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok;
556 // Pretend the first command failed if ReproStatus is Always.
557 const Command *FailingCommand = nullptr;
558 if (!C->getJobs().empty())
559 FailingCommand = &*C->getJobs().begin();
560 if (C && !C->containsError()) {
561 SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
562 Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
563
564 for (const auto &P : FailingCommands) {
565 int CommandRes = P.first;
566 FailingCommand = P.second;
567 if (!Res)
568 Res = CommandRes;
569
570 // If result status is < 0, then the driver command signalled an error.
571 // If result status is 70, then the driver command reported a fatal error.
572 // On Windows, abort will return an exit code of 3. In these cases,
573 // generate additional diagnostic information if possible.
574 IsCrash = CommandRes < 0 || CommandRes == 70;
575 #ifdef _WIN32
576 IsCrash |= CommandRes == 3;
577 #endif
578 #if LLVM_ON_UNIX
579 // When running in integrated-cc1 mode, the CrashRecoveryContext returns
580 // the same codes as if the program crashed. See section "Exit Status for
581 // Commands":
582 // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
583 IsCrash |= CommandRes > 128;
584 #endif
585 CommandStatus =
586 IsCrash ? Driver::CommandStatus::Crash : Driver::CommandStatus::Error;
587 if (IsCrash)
588 break;
589 }
590 }
591
592 // Print the bug report message that would be printed if we did actually
593 // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH.
594 if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
595 llvm::dbgs() << llvm::getBugReportMsg();
596 if (FailingCommand != nullptr &&
597 TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel,
598 *C, *FailingCommand))
599 Res = 1;
600
601 Diags.getClient()->finish();
602
603 if (!UseNewCC1Process && IsCrash) {
604 // When crashing in -fintegrated-cc1 mode, bury the timer pointers, because
605 // the internal linked list might point to already released stack frames.
606 llvm::BuryPointer(llvm::TimerGroup::aquireDefaultGroup());
607 } else {
608 // If any timers were active but haven't been destroyed yet, print their
609 // results now. This happens in -disable-free mode.
610 llvm::TimerGroup::printAll(llvm::errs());
611 llvm::TimerGroup::clearAll();
612 }
613
614 #ifdef _WIN32
615 // Exit status should not be negative on Win32, unless abnormal termination.
616 // Once abnormal termination was caught, negative status should not be
617 // propagated.
618 if (Res < 0)
619 Res = 1;
620 #endif
621
622 // If we have multiple failing commands, we return the result of the first
623 // failing command.
624 return Res;
625 }
626