xref: /freebsd/contrib/llvm-project/lld/Common/DriverDispatcher.cpp (revision e1e636193db45630c7881246d25902e57c43d24e)
1 //===- DriverDispatcher.cpp - Support using LLD as a library --------------===//
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 #include "lld/Common/CommonLinkerContext.h"
10 #include "lld/Common/Driver.h"
11 #include "lld/Common/ErrorHandler.h"
12 #include "lld/Common/Memory.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/ADT/Twine.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/CrashRecoveryContext.h"
19 #include "llvm/Support/Path.h"
20 #include "llvm/Support/Process.h"
21 #include "llvm/TargetParser/Host.h"
22 #include "llvm/TargetParser/Triple.h"
23 #include <cstdlib>
24 
25 using namespace lld;
26 using namespace llvm;
27 using namespace llvm::sys;
28 
29 static void err(const Twine &s) { llvm::errs() << s << "\n"; }
30 
31 static Flavor getFlavor(StringRef s) {
32   return StringSwitch<Flavor>(s)
33       .CasesLower("ld", "ld.lld", "gnu", Gnu)
34       .CasesLower("wasm", "ld-wasm", Wasm)
35       .CaseLower("link", WinLink)
36       .CasesLower("ld64", "ld64.lld", "darwin", Darwin)
37       .Default(Invalid);
38 }
39 
40 static cl::TokenizerCallback getDefaultQuotingStyle() {
41   if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
42     return cl::TokenizeWindowsCommandLine;
43   return cl::TokenizeGNUCommandLine;
44 }
45 
46 static bool isPETargetName(StringRef s) {
47   return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe";
48 }
49 
50 static std::optional<bool> isPETarget(llvm::ArrayRef<const char *> args) {
51   for (auto it = args.begin(); it + 1 != args.end(); ++it) {
52     if (StringRef(*it) != "-m")
53       continue;
54     return isPETargetName(*(it + 1));
55   }
56 
57   // Expand response files (arguments in the form of @<filename>)
58   // to allow detecting the -m argument from arguments in them.
59   SmallVector<const char *, 256> expandedArgs(args.data(),
60                                               args.data() + args.size());
61   BumpPtrAllocator a;
62   StringSaver saver(a);
63   cl::ExpansionContext ectx(saver.getAllocator(), getDefaultQuotingStyle());
64   if (Error e = ectx.expandResponseFiles(expandedArgs)) {
65     err(toString(std::move(e)));
66     return std::nullopt;
67   }
68 
69   for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) {
70     if (StringRef(*it) != "-m")
71       continue;
72     return isPETargetName(*(it + 1));
73   }
74 
75 #ifdef LLD_DEFAULT_LD_LLD_IS_MINGW
76   return true;
77 #else
78   return false;
79 #endif
80 }
81 
82 static Flavor parseProgname(StringRef progname) {
83   // Use GNU driver for "ld" by default.
84   if (progname == "ld")
85     return Gnu;
86 
87   // Progname may be something like "lld-gnu". Parse it.
88   SmallVector<StringRef, 3> v;
89   progname.split(v, "-");
90   for (StringRef s : v)
91     if (Flavor f = getFlavor(s))
92       return f;
93   return Invalid;
94 }
95 
96 static Flavor
97 parseFlavorWithoutMinGW(llvm::SmallVectorImpl<const char *> &argsV) {
98   // Parse -flavor option.
99   if (argsV.size() > 1 && argsV[1] == StringRef("-flavor")) {
100     if (argsV.size() <= 2) {
101       err("missing arg value for '-flavor'");
102       return Invalid;
103     }
104     Flavor f = getFlavor(argsV[2]);
105     if (f == Invalid) {
106       err("Unknown flavor: " + StringRef(argsV[2]));
107       return Invalid;
108     }
109     argsV.erase(argsV.begin() + 1, argsV.begin() + 3);
110     return f;
111   }
112 
113   // Deduct the flavor from argv[0].
114   StringRef arg0 = path::filename(argsV[0]);
115   if (arg0.ends_with_insensitive(".exe"))
116     arg0 = arg0.drop_back(4);
117   Flavor f = parseProgname(arg0);
118   if (f == Invalid) {
119     err("lld is a generic driver.\n"
120         "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"
121         " (WebAssembly) instead");
122     return Invalid;
123   }
124   return f;
125 }
126 
127 static Flavor parseFlavor(llvm::SmallVectorImpl<const char *> &argsV) {
128   Flavor f = parseFlavorWithoutMinGW(argsV);
129   if (f == Gnu) {
130     auto isPE = isPETarget(argsV);
131     if (!isPE)
132       return Invalid;
133     if (*isPE)
134       return MinGW;
135   }
136   return f;
137 }
138 
139 static Driver whichDriver(llvm::SmallVectorImpl<const char *> &argsV,
140                           llvm::ArrayRef<DriverDef> drivers) {
141   Flavor f = parseFlavor(argsV);
142   auto it =
143       llvm::find_if(drivers, [=](auto &driverdef) { return driverdef.f == f; });
144   if (it == drivers.end()) {
145     // Driver is invalid or not available in this build.
146     return [](llvm::ArrayRef<const char *>, llvm::raw_ostream &,
147               llvm::raw_ostream &, bool, bool) { return false; };
148   }
149   return it->d;
150 }
151 
152 namespace lld {
153 bool inTestOutputDisabled = false;
154 
155 /// Universal linker main(). This linker emulates the gnu, darwin, or
156 /// windows linker based on the argv[0] or -flavor option.
157 int unsafeLldMain(llvm::ArrayRef<const char *> args,
158                   llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,
159                   llvm::ArrayRef<DriverDef> drivers, bool exitEarly) {
160   SmallVector<const char *, 256> argsV(args);
161   Driver d = whichDriver(argsV, drivers);
162   // Run the driver. If an error occurs, false will be returned.
163   int r = !d(argsV, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled);
164   // At this point 'r' is either 1 for error, and 0 for no error.
165 
166   // Call exit() if we can to avoid calling destructors.
167   if (exitEarly)
168     exitLld(r);
169 
170   // Delete the global context and clear the global context pointer, so that it
171   // cannot be accessed anymore.
172   CommonLinkerContext::destroy();
173 
174   return r;
175 }
176 } // namespace lld
177 
178 Result lld::lldMain(llvm::ArrayRef<const char *> args,
179                     llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS,
180                     llvm::ArrayRef<DriverDef> drivers) {
181   int r = 0;
182   {
183     // The crash recovery is here only to be able to recover from arbitrary
184     // control flow when fatal() is called (through setjmp/longjmp or
185     // __try/__except).
186     llvm::CrashRecoveryContext crc;
187     if (!crc.RunSafely([&]() {
188           r = unsafeLldMain(args, stdoutOS, stderrOS, drivers,
189                             /*exitEarly=*/false);
190         }))
191       return {crc.RetCode, /*canRunAgain=*/false};
192   }
193 
194   // Cleanup memory and reset everything back in pristine condition. This path
195   // is only taken when LLD is in test, or when it is used as a library.
196   llvm::CrashRecoveryContext crc;
197   if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) {
198     // The memory is corrupted beyond any possible recovery.
199     return {r, /*canRunAgain=*/false};
200   }
201   return {r, /*canRunAgain=*/true};
202 }
203