10b57cec5SDimitry Andric //===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This is the entry point to the clang driver; it is a thin wrapper 100b57cec5SDimitry Andric // for functionality in the Driver clang library. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "clang/Driver/Driver.h" 150b57cec5SDimitry Andric #include "clang/Basic/DiagnosticOptions.h" 16bdd1243dSDimitry Andric #include "clang/Basic/HeaderInclude.h" 17a7dea167SDimitry Andric #include "clang/Basic/Stack.h" 18480093f4SDimitry Andric #include "clang/Config/config.h" 190b57cec5SDimitry Andric #include "clang/Driver/Compilation.h" 200b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 210b57cec5SDimitry Andric #include "clang/Driver/Options.h" 220b57cec5SDimitry Andric #include "clang/Driver/ToolChain.h" 230b57cec5SDimitry Andric #include "clang/Frontend/ChainedDiagnosticConsumer.h" 240b57cec5SDimitry Andric #include "clang/Frontend/CompilerInvocation.h" 250b57cec5SDimitry Andric #include "clang/Frontend/SerializedDiagnosticPrinter.h" 260b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h" 270b57cec5SDimitry Andric #include "clang/Frontend/Utils.h" 280b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 290b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 300b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 31*0fca6ea1SDimitry Andric #include "llvm/ADT/StringSet.h" 320b57cec5SDimitry Andric #include "llvm/Option/ArgList.h" 330b57cec5SDimitry Andric #include "llvm/Option/OptTable.h" 340b57cec5SDimitry Andric #include "llvm/Option/Option.h" 35cd675bb6SDimitry Andric #include "llvm/Support/BuryPointer.h" 360b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 37480093f4SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h" 380b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 390b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 4006c3fb27SDimitry Andric #include "llvm/Support/LLVMDriver.h" 410b57cec5SDimitry Andric #include "llvm/Support/Path.h" 425ffd83dbSDimitry Andric #include "llvm/Support/PrettyStackTrace.h" 430b57cec5SDimitry Andric #include "llvm/Support/Process.h" 440b57cec5SDimitry Andric #include "llvm/Support/Program.h" 450b57cec5SDimitry Andric #include "llvm/Support/Signals.h" 460b57cec5SDimitry Andric #include "llvm/Support/StringSaver.h" 470b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h" 480b57cec5SDimitry Andric #include "llvm/Support/Timer.h" 490b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 5006c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h" 510b57cec5SDimitry Andric #include <memory> 52bdd1243dSDimitry Andric #include <optional> 530b57cec5SDimitry Andric #include <set> 540b57cec5SDimitry Andric #include <system_error> 550b57cec5SDimitry Andric using namespace clang; 560b57cec5SDimitry Andric using namespace clang::driver; 570b57cec5SDimitry Andric using namespace llvm::opt; 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) { 600b57cec5SDimitry Andric if (!CanonicalPrefixes) { 610b57cec5SDimitry Andric SmallString<128> ExecutablePath(Argv0); 620b57cec5SDimitry Andric // Do a PATH lookup if Argv0 isn't a valid path. 630b57cec5SDimitry Andric if (!llvm::sys::fs::exists(ExecutablePath)) 640b57cec5SDimitry Andric if (llvm::ErrorOr<std::string> P = 650b57cec5SDimitry Andric llvm::sys::findProgramByName(ExecutablePath)) 660b57cec5SDimitry Andric ExecutablePath = *P; 677a6dacacSDimitry Andric return std::string(ExecutablePath); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // This just needs to be some symbol in the binary; C++ doesn't 710b57cec5SDimitry Andric // allow taking the address of ::main however. 720b57cec5SDimitry Andric void *P = (void*) (intptr_t) GetExecutablePath; 730b57cec5SDimitry Andric return llvm::sys::fs::getMainExecutable(Argv0, P); 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 76*0fca6ea1SDimitry Andric static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) { 77*0fca6ea1SDimitry Andric return SavedStrings.insert(S).first->getKeyData(); 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, 810b57cec5SDimitry Andric void *MainAddr); 820b57cec5SDimitry Andric extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, 830b57cec5SDimitry Andric void *MainAddr); 840b57cec5SDimitry Andric extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv, 8506c3fb27SDimitry Andric const char *Argv0, void *MainAddr, 8606c3fb27SDimitry Andric const llvm::ToolContext &); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric static void insertTargetAndModeArgs(const ParsedClangName &NameParts, 890b57cec5SDimitry Andric SmallVectorImpl<const char *> &ArgVector, 90*0fca6ea1SDimitry Andric llvm::StringSet<> &SavedStrings) { 910b57cec5SDimitry Andric // Put target and mode arguments at the start of argument list so that 920b57cec5SDimitry Andric // arguments specified in command line could override them. Avoid putting 930b57cec5SDimitry Andric // them at index 0, as an option like '-cc1' must remain the first. 940b57cec5SDimitry Andric int InsertionPoint = 0; 950b57cec5SDimitry Andric if (ArgVector.size() > 0) 960b57cec5SDimitry Andric ++InsertionPoint; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric if (NameParts.DriverMode) { 990b57cec5SDimitry Andric // Add the mode flag to the arguments. 1000b57cec5SDimitry Andric ArgVector.insert(ArgVector.begin() + InsertionPoint, 1010b57cec5SDimitry Andric GetStableCStr(SavedStrings, NameParts.DriverMode)); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric if (NameParts.TargetIsValid) { 1050b57cec5SDimitry Andric const char *arr[] = {"-target", GetStableCStr(SavedStrings, 1060b57cec5SDimitry Andric NameParts.TargetPrefix)}; 1070b57cec5SDimitry Andric ArgVector.insert(ArgVector.begin() + InsertionPoint, 1080b57cec5SDimitry Andric std::begin(arr), std::end(arr)); 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver, 1130b57cec5SDimitry Andric SmallVectorImpl<const char *> &Opts) { 1140b57cec5SDimitry Andric llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts); 1150b57cec5SDimitry Andric // The first instance of '#' should be replaced with '=' in each option. 1160b57cec5SDimitry Andric for (const char *Opt : Opts) 1170b57cec5SDimitry Andric if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#'))) 1180b57cec5SDimitry Andric *NumberSignPtr = '='; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 121bdd1243dSDimitry Andric template <class T> 122bdd1243dSDimitry Andric static T checkEnvVar(const char *EnvOptSet, const char *EnvOptFile, 123fe6060f1SDimitry Andric std::string &OptFile) { 124bdd1243dSDimitry Andric const char *Str = ::getenv(EnvOptSet); 125bdd1243dSDimitry Andric if (!Str) 126bdd1243dSDimitry Andric return T{}; 127bdd1243dSDimitry Andric 128bdd1243dSDimitry Andric T OptVal = Str; 129fe6060f1SDimitry Andric if (const char *Var = ::getenv(EnvOptFile)) 130fe6060f1SDimitry Andric OptFile = Var; 131bdd1243dSDimitry Andric return OptVal; 132fe6060f1SDimitry Andric } 1330b57cec5SDimitry Andric 134bdd1243dSDimitry Andric static bool SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) { 135fe6060f1SDimitry Andric TheDriver.CCPrintOptions = 136bdd1243dSDimitry Andric checkEnvVar<bool>("CC_PRINT_OPTIONS", "CC_PRINT_OPTIONS_FILE", 137fe6060f1SDimitry Andric TheDriver.CCPrintOptionsFilename); 138bdd1243dSDimitry Andric if (checkEnvVar<bool>("CC_PRINT_HEADERS", "CC_PRINT_HEADERS_FILE", 139bdd1243dSDimitry Andric TheDriver.CCPrintHeadersFilename)) { 140bdd1243dSDimitry Andric TheDriver.CCPrintHeadersFormat = HIFMT_Textual; 141bdd1243dSDimitry Andric TheDriver.CCPrintHeadersFiltering = HIFIL_None; 142bdd1243dSDimitry Andric } else { 143bdd1243dSDimitry Andric std::string EnvVar = checkEnvVar<std::string>( 144bdd1243dSDimitry Andric "CC_PRINT_HEADERS_FORMAT", "CC_PRINT_HEADERS_FILE", 145fe6060f1SDimitry Andric TheDriver.CCPrintHeadersFilename); 146bdd1243dSDimitry Andric if (!EnvVar.empty()) { 147bdd1243dSDimitry Andric TheDriver.CCPrintHeadersFormat = 148bdd1243dSDimitry Andric stringToHeaderIncludeFormatKind(EnvVar.c_str()); 149bdd1243dSDimitry Andric if (!TheDriver.CCPrintHeadersFormat) { 150bdd1243dSDimitry Andric TheDriver.Diag(clang::diag::err_drv_print_header_env_var) 151bdd1243dSDimitry Andric << 0 << EnvVar; 152bdd1243dSDimitry Andric return false; 153bdd1243dSDimitry Andric } 154bdd1243dSDimitry Andric 155bdd1243dSDimitry Andric const char *FilteringStr = ::getenv("CC_PRINT_HEADERS_FILTERING"); 156bdd1243dSDimitry Andric HeaderIncludeFilteringKind Filtering; 157bdd1243dSDimitry Andric if (!stringToHeaderIncludeFiltering(FilteringStr, Filtering)) { 158bdd1243dSDimitry Andric TheDriver.Diag(clang::diag::err_drv_print_header_env_var) 159bdd1243dSDimitry Andric << 1 << FilteringStr; 160bdd1243dSDimitry Andric return false; 161bdd1243dSDimitry Andric } 162bdd1243dSDimitry Andric 163bdd1243dSDimitry Andric if ((TheDriver.CCPrintHeadersFormat == HIFMT_Textual && 164bdd1243dSDimitry Andric Filtering != HIFIL_None) || 165bdd1243dSDimitry Andric (TheDriver.CCPrintHeadersFormat == HIFMT_JSON && 166bdd1243dSDimitry Andric Filtering != HIFIL_Only_Direct_System)) { 167bdd1243dSDimitry Andric TheDriver.Diag(clang::diag::err_drv_print_header_env_var_combination) 168bdd1243dSDimitry Andric << EnvVar << FilteringStr; 169bdd1243dSDimitry Andric return false; 170bdd1243dSDimitry Andric } 171bdd1243dSDimitry Andric TheDriver.CCPrintHeadersFiltering = Filtering; 172bdd1243dSDimitry Andric } 173bdd1243dSDimitry Andric } 174bdd1243dSDimitry Andric 175fe6060f1SDimitry Andric TheDriver.CCLogDiagnostics = 176bdd1243dSDimitry Andric checkEnvVar<bool>("CC_LOG_DIAGNOSTICS", "CC_LOG_DIAGNOSTICS_FILE", 177fe6060f1SDimitry Andric TheDriver.CCLogDiagnosticsFilename); 178fe6060f1SDimitry Andric TheDriver.CCPrintProcessStats = 179bdd1243dSDimitry Andric checkEnvVar<bool>("CC_PRINT_PROC_STAT", "CC_PRINT_PROC_STAT_FILE", 180fe6060f1SDimitry Andric TheDriver.CCPrintStatReportFilename); 18106c3fb27SDimitry Andric TheDriver.CCPrintInternalStats = 18206c3fb27SDimitry Andric checkEnvVar<bool>("CC_PRINT_INTERNAL_STAT", "CC_PRINT_INTERNAL_STAT_FILE", 18306c3fb27SDimitry Andric TheDriver.CCPrintInternalStatReportFilename); 184bdd1243dSDimitry Andric 185bdd1243dSDimitry Andric return true; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient, 1890b57cec5SDimitry Andric const std::string &Path) { 1900b57cec5SDimitry Andric // If the clang binary happens to be named cl.exe for compatibility reasons, 1910b57cec5SDimitry Andric // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC. 1920b57cec5SDimitry Andric StringRef ExeBasename(llvm::sys::path::stem(Path)); 193fe6060f1SDimitry Andric if (ExeBasename.equals_insensitive("cl")) 1940b57cec5SDimitry Andric ExeBasename = "clang-cl"; 1955ffd83dbSDimitry Andric DiagClient->setPrefix(std::string(ExeBasename)); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 19806c3fb27SDimitry Andric static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV, 19906c3fb27SDimitry Andric const llvm::ToolContext &ToolContext) { 200480093f4SDimitry Andric // If we call the cc1 tool from the clangDriver library (through 201480093f4SDimitry Andric // Driver::CC1Main), we need to clean up the options usage count. The options 202480093f4SDimitry Andric // are currently global, and they might have been used previously by the 203480093f4SDimitry Andric // driver. 204480093f4SDimitry Andric llvm::cl::ResetAllOptionOccurrences(); 20555e4f9d5SDimitry Andric 20655e4f9d5SDimitry Andric llvm::BumpPtrAllocator A; 207bdd1243dSDimitry Andric llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine); 208bdd1243dSDimitry Andric if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) { 209bdd1243dSDimitry Andric llvm::errs() << toString(std::move(Err)) << '\n'; 210bdd1243dSDimitry Andric return 1; 211bdd1243dSDimitry Andric } 21255e4f9d5SDimitry Andric StringRef Tool = ArgV[1]; 2130b57cec5SDimitry Andric void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath; 214480093f4SDimitry Andric if (Tool == "-cc1") 215bdd1243dSDimitry Andric return cc1_main(ArrayRef(ArgV).slice(1), ArgV[0], GetExecutablePathVP); 216480093f4SDimitry Andric if (Tool == "-cc1as") 217bdd1243dSDimitry Andric return cc1as_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP); 218480093f4SDimitry Andric if (Tool == "-cc1gen-reproducer") 219bdd1243dSDimitry Andric return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0], 22006c3fb27SDimitry Andric GetExecutablePathVP, ToolContext); 2210b57cec5SDimitry Andric // Reject unknown tools. 222*0fca6ea1SDimitry Andric llvm::errs() 223*0fca6ea1SDimitry Andric << "error: unknown integrated tool '" << Tool << "'. " 224*0fca6ea1SDimitry Andric << "Valid tools include '-cc1', '-cc1as' and '-cc1gen-reproducer'.\n"; 2250b57cec5SDimitry Andric return 1; 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 22806c3fb27SDimitry Andric int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) { 229a7dea167SDimitry Andric noteBottomOfStack(); 2305ffd83dbSDimitry Andric llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL 2315ffd83dbSDimitry Andric " and include the crash backtrace, preprocessed " 2325ffd83dbSDimitry Andric "source, and associated run script.\n"); 233fe6060f1SDimitry Andric SmallVector<const char *, 256> Args(Argv, Argv + Argc); 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric if (llvm::sys::Process::FixupStandardFileDescriptors()) 2360b57cec5SDimitry Andric return 1; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric llvm::InitializeAllTargets(); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric llvm::BumpPtrAllocator A; 2410b57cec5SDimitry Andric llvm::StringSaver Saver(A); 2420b57cec5SDimitry Andric 24306c3fb27SDimitry Andric const char *ProgName = 24406c3fb27SDimitry Andric ToolContext.NeedsPrependArg ? ToolContext.PrependArg : ToolContext.Path; 24506c3fb27SDimitry Andric 246fe6060f1SDimitry Andric bool ClangCLMode = 24706c3fb27SDimitry Andric IsClangCL(getDriverMode(ProgName, llvm::ArrayRef(Args).slice(1))); 2480b57cec5SDimitry Andric 24906c3fb27SDimitry Andric if (llvm::Error Err = expandResponseFiles(Args, ClangCLMode, A)) { 250bdd1243dSDimitry Andric llvm::errs() << toString(std::move(Err)) << '\n'; 251bdd1243dSDimitry Andric return 1; 252bdd1243dSDimitry Andric } 2530b57cec5SDimitry Andric 25406c3fb27SDimitry Andric // Handle -cc1 integrated tools. 2555f757f3fSDimitry Andric if (Args.size() >= 2 && StringRef(Args[1]).starts_with("-cc1")) 25606c3fb27SDimitry Andric return ExecuteCC1Tool(Args, ToolContext); 2570b57cec5SDimitry Andric 25865286350SDimitry Andric // Handle options that need handling before the real command line parsing in 25965286350SDimitry Andric // Driver::BuildCompilation() 2600b57cec5SDimitry Andric bool CanonicalPrefixes = true; 261fe6060f1SDimitry Andric for (int i = 1, size = Args.size(); i < size; ++i) { 2620b57cec5SDimitry Andric // Skip end-of-line response file markers 263fe6060f1SDimitry Andric if (Args[i] == nullptr) 2640b57cec5SDimitry Andric continue; 265349cc55cSDimitry Andric if (StringRef(Args[i]) == "-canonical-prefixes") 266349cc55cSDimitry Andric CanonicalPrefixes = true; 267349cc55cSDimitry Andric else if (StringRef(Args[i]) == "-no-canonical-prefixes") 2680b57cec5SDimitry Andric CanonicalPrefixes = false; 2690b57cec5SDimitry Andric } 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric // Handle CL and _CL_ which permits additional command line options to be 2720b57cec5SDimitry Andric // prepended or appended. 2730b57cec5SDimitry Andric if (ClangCLMode) { 2740b57cec5SDimitry Andric // Arguments in "CL" are prepended. 275bdd1243dSDimitry Andric std::optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL"); 27681ad6265SDimitry Andric if (OptCL) { 2770b57cec5SDimitry Andric SmallVector<const char *, 8> PrependedOpts; 278bdd1243dSDimitry Andric getCLEnvVarOptions(*OptCL, Saver, PrependedOpts); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Insert right after the program name to prepend to the argument list. 281fe6060f1SDimitry Andric Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end()); 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric // Arguments in "_CL_" are appended. 284bdd1243dSDimitry Andric std::optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_"); 28581ad6265SDimitry Andric if (Opt_CL_) { 2860b57cec5SDimitry Andric SmallVector<const char *, 8> AppendedOpts; 287bdd1243dSDimitry Andric getCLEnvVarOptions(*Opt_CL_, Saver, AppendedOpts); 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric // Insert at the end of the argument list to append. 290fe6060f1SDimitry Andric Args.append(AppendedOpts.begin(), AppendedOpts.end()); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 294*0fca6ea1SDimitry Andric llvm::StringSet<> SavedStrings; 2950b57cec5SDimitry Andric // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the 2960b57cec5SDimitry Andric // scenes. 2970b57cec5SDimitry Andric if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) { 2980b57cec5SDimitry Andric // FIXME: Driver shouldn't take extra initial argument. 299*0fca6ea1SDimitry Andric driver::applyOverrideOptions(Args, OverrideStr, SavedStrings, 300*0fca6ea1SDimitry Andric &llvm::errs()); 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric 30306c3fb27SDimitry Andric std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes); 3040b57cec5SDimitry Andric 30565286350SDimitry Andric // Whether the cc1 tool should be called inside the current process, or if we 30665286350SDimitry Andric // should spawn a new clang subprocess (old behavior). 30765286350SDimitry Andric // Not having an additional process saves some execution time of Windows, 30865286350SDimitry Andric // and makes debugging and profiling easier. 309349cc55cSDimitry Andric bool UseNewCC1Process = CLANG_SPAWN_CC1; 310349cc55cSDimitry Andric for (const char *Arg : Args) 311349cc55cSDimitry Andric UseNewCC1Process = llvm::StringSwitch<bool>(Arg) 312349cc55cSDimitry Andric .Case("-fno-integrated-cc1", true) 313349cc55cSDimitry Andric .Case("-fintegrated-cc1", false) 314349cc55cSDimitry Andric .Default(UseNewCC1Process); 31565286350SDimitry Andric 3160b57cec5SDimitry Andric IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = 317349cc55cSDimitry Andric CreateAndPopulateDiagOpts(Args); 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric TextDiagnosticPrinter *DiagClient 3200b57cec5SDimitry Andric = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); 32106c3fb27SDimitry Andric FixupDiagPrefixExeName(DiagClient, ProgName); 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric if (!DiagOpts->DiagnosticSerializationFile.empty()) { 3280b57cec5SDimitry Andric auto SerializedConsumer = 3290b57cec5SDimitry Andric clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile, 3300b57cec5SDimitry Andric &*DiagOpts, /*MergeChildRecords=*/true); 3310b57cec5SDimitry Andric Diags.setClient(new ChainedDiagnosticConsumer( 3320b57cec5SDimitry Andric Diags.takeClient(), std::move(SerializedConsumer))); 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); 33806c3fb27SDimitry Andric auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(ProgName); 3390b57cec5SDimitry Andric TheDriver.setTargetAndMode(TargetAndMode); 34006c3fb27SDimitry Andric // If -canonical-prefixes is set, GetExecutablePath will have resolved Path 34106c3fb27SDimitry Andric // to the llvm driver binary, not clang. In this case, we need to use 34206c3fb27SDimitry Andric // PrependArg which should be clang-*. Checking just CanonicalPrefixes is 34306c3fb27SDimitry Andric // safe even in the normal case because PrependArg will be null so 34406c3fb27SDimitry Andric // setPrependArg will be a no-op. 34506c3fb27SDimitry Andric if (ToolContext.NeedsPrependArg || CanonicalPrefixes) 34606c3fb27SDimitry Andric TheDriver.setPrependArg(ToolContext.PrependArg); 3470b57cec5SDimitry Andric 348fe6060f1SDimitry Andric insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings); 3490b57cec5SDimitry Andric 350bdd1243dSDimitry Andric if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver)) 351bdd1243dSDimitry Andric return 1; 3520b57cec5SDimitry Andric 35365286350SDimitry Andric if (!UseNewCC1Process) { 35406c3fb27SDimitry Andric TheDriver.CC1Main = [ToolContext](SmallVectorImpl<const char *> &ArgV) { 35506c3fb27SDimitry Andric return ExecuteCC1Tool(ArgV, ToolContext); 35606c3fb27SDimitry Andric }; 35765286350SDimitry Andric // Ensure the CC1Command actually catches cc1 crashes 35865286350SDimitry Andric llvm::CrashRecoveryContext::Enable(); 35965286350SDimitry Andric } 36065286350SDimitry Andric 361fe6060f1SDimitry Andric std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args)); 36281ad6265SDimitry Andric 36381ad6265SDimitry Andric Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash; 36481ad6265SDimitry Andric if (Arg *A = C->getArgs().getLastArg(options::OPT_gen_reproducer_eq)) { 365bdd1243dSDimitry Andric auto Level = 366bdd1243dSDimitry Andric llvm::StringSwitch<std::optional<Driver::ReproLevel>>(A->getValue()) 36781ad6265SDimitry Andric .Case("off", Driver::ReproLevel::Off) 36881ad6265SDimitry Andric .Case("crash", Driver::ReproLevel::OnCrash) 36981ad6265SDimitry Andric .Case("error", Driver::ReproLevel::OnError) 37081ad6265SDimitry Andric .Case("always", Driver::ReproLevel::Always) 371bdd1243dSDimitry Andric .Default(std::nullopt); 37281ad6265SDimitry Andric if (!Level) { 37381ad6265SDimitry Andric llvm::errs() << "Unknown value for " << A->getSpelling() << ": '" 37481ad6265SDimitry Andric << A->getValue() << "'\n"; 37581ad6265SDimitry Andric return 1; 37681ad6265SDimitry Andric } 37781ad6265SDimitry Andric ReproLevel = *Level; 37881ad6265SDimitry Andric } 37981ad6265SDimitry Andric if (!!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) 38081ad6265SDimitry Andric ReproLevel = Driver::ReproLevel::Always; 38181ad6265SDimitry Andric 3820b57cec5SDimitry Andric int Res = 1; 383cd675bb6SDimitry Andric bool IsCrash = false; 38481ad6265SDimitry Andric Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok; 38581ad6265SDimitry Andric // Pretend the first command failed if ReproStatus is Always. 38681ad6265SDimitry Andric const Command *FailingCommand = nullptr; 38781ad6265SDimitry Andric if (!C->getJobs().empty()) 38881ad6265SDimitry Andric FailingCommand = &*C->getJobs().begin(); 3890b57cec5SDimitry Andric if (C && !C->containsError()) { 3900b57cec5SDimitry Andric SmallVector<std::pair<int, const Command *>, 4> FailingCommands; 3910b57cec5SDimitry Andric Res = TheDriver.ExecuteCompilation(*C, FailingCommands); 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric for (const auto &P : FailingCommands) { 3940b57cec5SDimitry Andric int CommandRes = P.first; 39581ad6265SDimitry Andric FailingCommand = P.second; 3960b57cec5SDimitry Andric if (!Res) 3970b57cec5SDimitry Andric Res = CommandRes; 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric // If result status is < 0, then the driver command signalled an error. 4000b57cec5SDimitry Andric // If result status is 70, then the driver command reported a fatal error. 4010b57cec5SDimitry Andric // On Windows, abort will return an exit code of 3. In these cases, 4020b57cec5SDimitry Andric // generate additional diagnostic information if possible. 403cd675bb6SDimitry Andric IsCrash = CommandRes < 0 || CommandRes == 70; 4040b57cec5SDimitry Andric #ifdef _WIN32 405cd675bb6SDimitry Andric IsCrash |= CommandRes == 3; 4060b57cec5SDimitry Andric #endif 407e8d8bef9SDimitry Andric #if LLVM_ON_UNIX 408e8d8bef9SDimitry Andric // When running in integrated-cc1 mode, the CrashRecoveryContext returns 409e8d8bef9SDimitry Andric // the same codes as if the program crashed. See section "Exit Status for 410e8d8bef9SDimitry Andric // Commands": 411e8d8bef9SDimitry Andric // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html 412e8d8bef9SDimitry Andric IsCrash |= CommandRes > 128; 413e8d8bef9SDimitry Andric #endif 41481ad6265SDimitry Andric CommandStatus = 41581ad6265SDimitry Andric IsCrash ? Driver::CommandStatus::Crash : Driver::CommandStatus::Error; 41681ad6265SDimitry Andric if (IsCrash) 4170b57cec5SDimitry Andric break; 4180b57cec5SDimitry Andric } 4190b57cec5SDimitry Andric } 42081ad6265SDimitry Andric 42181ad6265SDimitry Andric // Print the bug report message that would be printed if we did actually 42281ad6265SDimitry Andric // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH. 42381ad6265SDimitry Andric if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) 42481ad6265SDimitry Andric llvm::dbgs() << llvm::getBugReportMsg(); 42581ad6265SDimitry Andric if (FailingCommand != nullptr && 42681ad6265SDimitry Andric TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel, 42781ad6265SDimitry Andric *C, *FailingCommand)) 42881ad6265SDimitry Andric Res = 1; 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric Diags.getClient()->finish(); 4310b57cec5SDimitry Andric 432cd675bb6SDimitry Andric if (!UseNewCC1Process && IsCrash) { 433cd675bb6SDimitry Andric // When crashing in -fintegrated-cc1 mode, bury the timer pointers, because 434cd675bb6SDimitry Andric // the internal linked list might point to already released stack frames. 435cd675bb6SDimitry Andric llvm::BuryPointer(llvm::TimerGroup::aquireDefaultGroup()); 436cd675bb6SDimitry Andric } else { 4370b57cec5SDimitry Andric // If any timers were active but haven't been destroyed yet, print their 4380b57cec5SDimitry Andric // results now. This happens in -disable-free mode. 4390b57cec5SDimitry Andric llvm::TimerGroup::printAll(llvm::errs()); 440a7dea167SDimitry Andric llvm::TimerGroup::clearAll(); 441cd675bb6SDimitry Andric } 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric #ifdef _WIN32 4440b57cec5SDimitry Andric // Exit status should not be negative on Win32, unless abnormal termination. 445480093f4SDimitry Andric // Once abnormal termination was caught, negative status should not be 4460b57cec5SDimitry Andric // propagated. 4470b57cec5SDimitry Andric if (Res < 0) 4480b57cec5SDimitry Andric Res = 1; 4490b57cec5SDimitry Andric #endif 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric // If we have multiple failing commands, we return the result of the first 4520b57cec5SDimitry Andric // failing command. 4530b57cec5SDimitry Andric return Res; 4540b57cec5SDimitry Andric } 455