xref: /freebsd-src/contrib/llvm-project/lld/Common/DriverDispatcher.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===- DriverDispatcher.cpp - Support using LLD as a library --------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "lld/Common/CommonLinkerContext.h"
1006c3fb27SDimitry Andric #include "lld/Common/Driver.h"
1106c3fb27SDimitry Andric #include "lld/Common/ErrorHandler.h"
1206c3fb27SDimitry Andric #include "lld/Common/Memory.h"
1306c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h"
1406c3fb27SDimitry Andric #include "llvm/ADT/SmallVector.h"
1506c3fb27SDimitry Andric #include "llvm/ADT/StringSwitch.h"
1606c3fb27SDimitry Andric #include "llvm/ADT/Twine.h"
1706c3fb27SDimitry Andric #include "llvm/Support/CommandLine.h"
1806c3fb27SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h"
1906c3fb27SDimitry Andric #include "llvm/Support/Path.h"
2006c3fb27SDimitry Andric #include "llvm/Support/Process.h"
2106c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
2206c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
2306c3fb27SDimitry Andric #include <cstdlib>
2406c3fb27SDimitry Andric 
2506c3fb27SDimitry Andric using namespace lld;
2606c3fb27SDimitry Andric using namespace llvm;
2706c3fb27SDimitry Andric using namespace llvm::sys;
2806c3fb27SDimitry Andric 
2906c3fb27SDimitry Andric static void err(const Twine &s) { llvm::errs() << s << "\n"; }
3006c3fb27SDimitry Andric 
3106c3fb27SDimitry Andric static Flavor getFlavor(StringRef s) {
3206c3fb27SDimitry Andric   return StringSwitch<Flavor>(s)
3306c3fb27SDimitry Andric       .CasesLower("ld", "ld.lld", "gnu", Gnu)
3406c3fb27SDimitry Andric       .CasesLower("wasm", "ld-wasm", Wasm)
3506c3fb27SDimitry Andric       .CaseLower("link", WinLink)
3606c3fb27SDimitry Andric       .CasesLower("ld64", "ld64.lld", "darwin", Darwin)
3706c3fb27SDimitry Andric       .Default(Invalid);
3806c3fb27SDimitry Andric }
3906c3fb27SDimitry Andric 
4006c3fb27SDimitry Andric static cl::TokenizerCallback getDefaultQuotingStyle() {
4106c3fb27SDimitry Andric   if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
4206c3fb27SDimitry Andric     return cl::TokenizeWindowsCommandLine;
4306c3fb27SDimitry Andric   return cl::TokenizeGNUCommandLine;
4406c3fb27SDimitry Andric }
4506c3fb27SDimitry Andric 
4606c3fb27SDimitry Andric static bool isPETargetName(StringRef s) {
47*0fca6ea1SDimitry Andric   return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe" ||
48*0fca6ea1SDimitry Andric          s == "arm64ecpe";
4906c3fb27SDimitry Andric }
5006c3fb27SDimitry Andric 
5106c3fb27SDimitry Andric static std::optional<bool> isPETarget(llvm::ArrayRef<const char *> args) {
5206c3fb27SDimitry Andric   for (auto it = args.begin(); it + 1 != args.end(); ++it) {
5306c3fb27SDimitry Andric     if (StringRef(*it) != "-m")
5406c3fb27SDimitry Andric       continue;
5506c3fb27SDimitry Andric     return isPETargetName(*(it + 1));
5606c3fb27SDimitry Andric   }
5706c3fb27SDimitry Andric 
5806c3fb27SDimitry Andric   // Expand response files (arguments in the form of @<filename>)
5906c3fb27SDimitry Andric   // to allow detecting the -m argument from arguments in them.
6006c3fb27SDimitry Andric   SmallVector<const char *, 256> expandedArgs(args.data(),
6106c3fb27SDimitry Andric                                               args.data() + args.size());
6206c3fb27SDimitry Andric   BumpPtrAllocator a;
6306c3fb27SDimitry Andric   StringSaver saver(a);
6406c3fb27SDimitry Andric   cl::ExpansionContext ectx(saver.getAllocator(), getDefaultQuotingStyle());
6506c3fb27SDimitry Andric   if (Error e = ectx.expandResponseFiles(expandedArgs)) {
6606c3fb27SDimitry Andric     err(toString(std::move(e)));
6706c3fb27SDimitry Andric     return std::nullopt;
6806c3fb27SDimitry Andric   }
6906c3fb27SDimitry Andric 
7006c3fb27SDimitry Andric   for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) {
7106c3fb27SDimitry Andric     if (StringRef(*it) != "-m")
7206c3fb27SDimitry Andric       continue;
7306c3fb27SDimitry Andric     return isPETargetName(*(it + 1));
7406c3fb27SDimitry Andric   }
7506c3fb27SDimitry Andric 
7606c3fb27SDimitry Andric #ifdef LLD_DEFAULT_LD_LLD_IS_MINGW
7706c3fb27SDimitry Andric   return true;
7806c3fb27SDimitry Andric #else
7906c3fb27SDimitry Andric   return false;
8006c3fb27SDimitry Andric #endif
8106c3fb27SDimitry Andric }
8206c3fb27SDimitry Andric 
8306c3fb27SDimitry Andric static Flavor parseProgname(StringRef progname) {
8406c3fb27SDimitry Andric   // Use GNU driver for "ld" by default.
8506c3fb27SDimitry Andric   if (progname == "ld")
8606c3fb27SDimitry Andric     return Gnu;
8706c3fb27SDimitry Andric 
8806c3fb27SDimitry Andric   // Progname may be something like "lld-gnu". Parse it.
8906c3fb27SDimitry Andric   SmallVector<StringRef, 3> v;
9006c3fb27SDimitry Andric   progname.split(v, "-");
9106c3fb27SDimitry Andric   for (StringRef s : v)
9206c3fb27SDimitry Andric     if (Flavor f = getFlavor(s))
9306c3fb27SDimitry Andric       return f;
9406c3fb27SDimitry Andric   return Invalid;
9506c3fb27SDimitry Andric }
9606c3fb27SDimitry Andric 
9706c3fb27SDimitry Andric static Flavor
9806c3fb27SDimitry Andric parseFlavorWithoutMinGW(llvm::SmallVectorImpl<const char *> &argsV) {
9906c3fb27SDimitry Andric   // Parse -flavor option.
10006c3fb27SDimitry Andric   if (argsV.size() > 1 && argsV[1] == StringRef("-flavor")) {
10106c3fb27SDimitry Andric     if (argsV.size() <= 2) {
10206c3fb27SDimitry Andric       err("missing arg value for '-flavor'");
10306c3fb27SDimitry Andric       return Invalid;
10406c3fb27SDimitry Andric     }
10506c3fb27SDimitry Andric     Flavor f = getFlavor(argsV[2]);
10606c3fb27SDimitry Andric     if (f == Invalid) {
10706c3fb27SDimitry Andric       err("Unknown flavor: " + StringRef(argsV[2]));
10806c3fb27SDimitry Andric       return Invalid;
10906c3fb27SDimitry Andric     }
11006c3fb27SDimitry Andric     argsV.erase(argsV.begin() + 1, argsV.begin() + 3);
11106c3fb27SDimitry Andric     return f;
11206c3fb27SDimitry Andric   }
11306c3fb27SDimitry Andric 
11406c3fb27SDimitry Andric   // Deduct the flavor from argv[0].
11506c3fb27SDimitry Andric   StringRef arg0 = path::filename(argsV[0]);
11606c3fb27SDimitry Andric   if (arg0.ends_with_insensitive(".exe"))
11706c3fb27SDimitry Andric     arg0 = arg0.drop_back(4);
11806c3fb27SDimitry Andric   Flavor f = parseProgname(arg0);
11906c3fb27SDimitry Andric   if (f == Invalid) {
12006c3fb27SDimitry Andric     err("lld is a generic driver.\n"
12106c3fb27SDimitry Andric         "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"
12206c3fb27SDimitry Andric         " (WebAssembly) instead");
12306c3fb27SDimitry Andric     return Invalid;
12406c3fb27SDimitry Andric   }
12506c3fb27SDimitry Andric   return f;
12606c3fb27SDimitry Andric }
12706c3fb27SDimitry Andric 
12806c3fb27SDimitry Andric static Flavor parseFlavor(llvm::SmallVectorImpl<const char *> &argsV) {
12906c3fb27SDimitry Andric   Flavor f = parseFlavorWithoutMinGW(argsV);
13006c3fb27SDimitry Andric   if (f == Gnu) {
13106c3fb27SDimitry Andric     auto isPE = isPETarget(argsV);
13206c3fb27SDimitry Andric     if (!isPE)
13306c3fb27SDimitry Andric       return Invalid;
13406c3fb27SDimitry Andric     if (*isPE)
13506c3fb27SDimitry Andric       return MinGW;
13606c3fb27SDimitry Andric   }
13706c3fb27SDimitry Andric   return f;
13806c3fb27SDimitry Andric }
13906c3fb27SDimitry Andric 
14006c3fb27SDimitry Andric static Driver whichDriver(llvm::SmallVectorImpl<const char *> &argsV,
14106c3fb27SDimitry Andric                           llvm::ArrayRef<DriverDef> drivers) {
14206c3fb27SDimitry Andric   Flavor f = parseFlavor(argsV);
14306c3fb27SDimitry Andric   auto it =
14406c3fb27SDimitry Andric       llvm::find_if(drivers, [=](auto &driverdef) { return driverdef.f == f; });
14506c3fb27SDimitry Andric   if (it == drivers.end()) {
14606c3fb27SDimitry Andric     // Driver is invalid or not available in this build.
14706c3fb27SDimitry Andric     return [](llvm::ArrayRef<const char *>, llvm::raw_ostream &,
14806c3fb27SDimitry Andric               llvm::raw_ostream &, bool, bool) { return false; };
14906c3fb27SDimitry Andric   }
15006c3fb27SDimitry Andric   return it->d;
15106c3fb27SDimitry Andric }
15206c3fb27SDimitry Andric 
15306c3fb27SDimitry Andric namespace lld {
15406c3fb27SDimitry Andric bool inTestOutputDisabled = false;
15506c3fb27SDimitry Andric 
15606c3fb27SDimitry Andric /// Universal linker main(). This linker emulates the gnu, darwin, or
15706c3fb27SDimitry Andric /// windows linker based on the argv[0] or -flavor option.
15806c3fb27SDimitry Andric int unsafeLldMain(llvm::ArrayRef<const char *> args,
15906c3fb27SDimitry Andric                   llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,
16006c3fb27SDimitry Andric                   llvm::ArrayRef<DriverDef> drivers, bool exitEarly) {
16106c3fb27SDimitry Andric   SmallVector<const char *, 256> argsV(args);
16206c3fb27SDimitry Andric   Driver d = whichDriver(argsV, drivers);
16306c3fb27SDimitry Andric   // Run the driver. If an error occurs, false will be returned.
16406c3fb27SDimitry Andric   int r = !d(argsV, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled);
16506c3fb27SDimitry Andric   // At this point 'r' is either 1 for error, and 0 for no error.
16606c3fb27SDimitry Andric 
16706c3fb27SDimitry Andric   // Call exit() if we can to avoid calling destructors.
16806c3fb27SDimitry Andric   if (exitEarly)
16906c3fb27SDimitry Andric     exitLld(r);
17006c3fb27SDimitry Andric 
17106c3fb27SDimitry Andric   // Delete the global context and clear the global context pointer, so that it
17206c3fb27SDimitry Andric   // cannot be accessed anymore.
17306c3fb27SDimitry Andric   CommonLinkerContext::destroy();
17406c3fb27SDimitry Andric 
17506c3fb27SDimitry Andric   return r;
17606c3fb27SDimitry Andric }
17706c3fb27SDimitry Andric } // namespace lld
17806c3fb27SDimitry Andric 
17906c3fb27SDimitry Andric Result lld::lldMain(llvm::ArrayRef<const char *> args,
18006c3fb27SDimitry Andric                     llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,
18106c3fb27SDimitry Andric                     llvm::ArrayRef<DriverDef> drivers) {
18206c3fb27SDimitry Andric   int r = 0;
18306c3fb27SDimitry Andric   {
18406c3fb27SDimitry Andric     // The crash recovery is here only to be able to recover from arbitrary
18506c3fb27SDimitry Andric     // control flow when fatal() is called (through setjmp/longjmp or
18606c3fb27SDimitry Andric     // __try/__except).
18706c3fb27SDimitry Andric     llvm::CrashRecoveryContext crc;
18806c3fb27SDimitry Andric     if (!crc.RunSafely([&]() {
18906c3fb27SDimitry Andric           r = unsafeLldMain(args, stdoutOS, stderrOS, drivers,
19006c3fb27SDimitry Andric                             /*exitEarly=*/false);
19106c3fb27SDimitry Andric         }))
19206c3fb27SDimitry Andric       return {crc.RetCode, /*canRunAgain=*/false};
19306c3fb27SDimitry Andric   }
19406c3fb27SDimitry Andric 
19506c3fb27SDimitry Andric   // Cleanup memory and reset everything back in pristine condition. This path
19606c3fb27SDimitry Andric   // is only taken when LLD is in test, or when it is used as a library.
19706c3fb27SDimitry Andric   llvm::CrashRecoveryContext crc;
19806c3fb27SDimitry Andric   if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) {
19906c3fb27SDimitry Andric     // The memory is corrupted beyond any possible recovery.
20006c3fb27SDimitry Andric     return {r, /*canRunAgain=*/false};
20106c3fb27SDimitry Andric   }
20206c3fb27SDimitry Andric   return {r, /*canRunAgain=*/true};
20306c3fb27SDimitry Andric }
204