1 //===- DriverUtils.cpp ----------------------------------------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains utility functions for the driver. Because there
11 // are so many small functions, we created this separate file to make
12 // Driver.cpp less cluttered.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "Config.h"
17 #include "Driver.h"
18 #include "Error.h"
19 #include "Memory.h"
20 #include "llvm/ADT/Optional.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/ADT/StringSwitch.h"
23 #include "llvm/Object/COFF.h"
24 #include "llvm/Option/Arg.h"
25 #include "llvm/Option/ArgList.h"
26 #include "llvm/Option/Option.h"
27 #include "llvm/Support/CommandLine.h"
28 #include "llvm/Support/Path.h"
29 #include "llvm/Support/Process.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <memory>
32 
33 using namespace llvm::COFF;
34 using namespace llvm;
35 using llvm::cl::ExpandResponseFiles;
36 using llvm::cl::TokenizeWindowsCommandLine;
37 using llvm::sys::Process;
38 
39 namespace lld {
40 namespace coff {
41 
42 // Returns /machine's value.
43 ErrorOr<MachineTypes> getMachineType(llvm::opt::InputArgList *Args) {
44   if (auto *Arg = Args->getLastArg(OPT_machine)) {
45     StringRef S(Arg->getValue());
46     MachineTypes MT = StringSwitch<MachineTypes>(S.lower())
47                           .Case("arm", IMAGE_FILE_MACHINE_ARMNT)
48                           .Case("x64", IMAGE_FILE_MACHINE_AMD64)
49                           .Case("x86", IMAGE_FILE_MACHINE_I386)
50                           .Default(IMAGE_FILE_MACHINE_UNKNOWN);
51     if (MT == IMAGE_FILE_MACHINE_UNKNOWN) {
52       llvm::errs() << "unknown /machine argument" << S << "\n";
53       return make_error_code(LLDError::InvalidOption);
54     }
55     return MT;
56   }
57   return IMAGE_FILE_MACHINE_UNKNOWN;
58 }
59 
60 // Parses a string in the form of "<integer>[,<integer>]".
61 std::error_code parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
62   StringRef S1, S2;
63   std::tie(S1, S2) = Arg.split(',');
64   if (S1.getAsInteger(0, *Addr)) {
65     llvm::errs() << "invalid number: " << S1 << "\n";
66     return make_error_code(LLDError::InvalidOption);
67   }
68   if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) {
69     llvm::errs() << "invalid number: " << S2 << "\n";
70     return make_error_code(LLDError::InvalidOption);
71   }
72   return std::error_code();
73 }
74 
75 // Parses a string in the form of "<integer>[.<integer>]".
76 // If second number is not present, Minor is set to 0.
77 std::error_code parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
78   StringRef S1, S2;
79   std::tie(S1, S2) = Arg.split('.');
80   if (S1.getAsInteger(0, *Major)) {
81     llvm::errs() << "invalid number: " << S1 << "\n";
82     return make_error_code(LLDError::InvalidOption);
83   }
84   *Minor = 0;
85   if (!S2.empty() && S2.getAsInteger(0, *Minor)) {
86     llvm::errs() << "invalid number: " << S2 << "\n";
87     return make_error_code(LLDError::InvalidOption);
88   }
89   return std::error_code();
90 }
91 
92 // Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
93 std::error_code parseSubsystem(StringRef Arg, WindowsSubsystem *Sys,
94                                uint32_t *Major, uint32_t *Minor) {
95   StringRef SysStr, Ver;
96   std::tie(SysStr, Ver) = Arg.split(',');
97   *Sys = StringSwitch<WindowsSubsystem>(SysStr.lower())
98     .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
99     .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
100     .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION)
101     .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
102     .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM)
103     .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
104     .Case("native", IMAGE_SUBSYSTEM_NATIVE)
105     .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
106     .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
107     .Default(IMAGE_SUBSYSTEM_UNKNOWN);
108   if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN) {
109     llvm::errs() << "unknown subsystem: " << SysStr << "\n";
110     return make_error_code(LLDError::InvalidOption);
111   }
112   if (!Ver.empty())
113     if (auto EC = parseVersion(Ver, Major, Minor))
114       return EC;
115   return std::error_code();
116 }
117 
118 // Parses a string in the form of "key=value" and check
119 // if value matches previous values for the same key.
120 std::error_code checkFailIfMismatch(llvm::opt::InputArgList *Args) {
121   for (auto *Arg : Args->filtered(OPT_failifmismatch)) {
122     StringRef K, V;
123     std::tie(K, V) = StringRef(Arg->getValue()).split('=');
124     if (K.empty() || V.empty()) {
125       llvm::errs() << "/failifmismatch: invalid argument: "
126                    << Arg->getValue() << "\n";
127       return make_error_code(LLDError::InvalidOption);
128     }
129     StringRef Existing = Config->MustMatch[K];
130     if (!Existing.empty() && V != Existing) {
131       llvm::errs() << "/failifmismatch: mismatch detected: "
132                    << Existing << " and " << V
133                    << " for key " << K << "\n";
134       return make_error_code(LLDError::InvalidOption);
135     }
136     Config->MustMatch[K] = V;
137   }
138   return std::error_code();
139 }
140 
141 // Create OptTable
142 
143 // Create prefix string literals used in Options.td
144 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
145 #include "Options.inc"
146 #undef PREFIX
147 
148 // Create table mapping all options defined in Options.td
149 static const llvm::opt::OptTable::Info infoTable[] = {
150 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10)    \
151   {                                                                    \
152     X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \
153     OPT_##GROUP, OPT_##ALIAS, X6                                       \
154   },
155 #include "Options.inc"
156 #undef OPTION
157 };
158 
159 class COFFOptTable : public llvm::opt::OptTable {
160 public:
161   COFFOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable), true) {}
162 };
163 
164 // Parses a given list of options.
165 ErrorOr<std::unique_ptr<llvm::opt::InputArgList>>
166 ArgParser::parse(std::vector<const char *> Argv) {
167   // First, replace respnose files (@<file>-style options).
168   auto ArgvOrErr = replaceResponseFiles(Argv);
169   if (auto EC = ArgvOrErr.getError()) {
170     llvm::errs() << "error while reading response file: " << EC.message()
171                  << "\n";
172     return EC;
173   }
174   Argv = std::move(ArgvOrErr.get());
175 
176   // Make InputArgList from string vectors.
177   COFFOptTable Table;
178   unsigned MissingIndex;
179   unsigned MissingCount;
180   std::unique_ptr<llvm::opt::InputArgList> Args(Table.ParseArgs(
181       &Argv[0], &Argv[0] + Argv.size(), MissingIndex, MissingCount));
182   if (MissingCount) {
183     llvm::errs() << "missing arg value for \""
184                  << Args->getArgString(MissingIndex)
185                  << "\", expected " << MissingCount
186                  << (MissingCount == 1 ? " argument.\n" : " arguments.\n");
187     return make_error_code(LLDError::InvalidOption);
188   }
189   for (auto *Arg : Args->filtered(OPT_UNKNOWN))
190     llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
191   return std::move(Args);
192 }
193 
194 ErrorOr<std::unique_ptr<llvm::opt::InputArgList>>
195 ArgParser::parse(int Argc, const char *Argv[]) {
196   std::vector<const char *> V(Argv + 1, Argv + Argc);
197   return parse(V);
198 }
199 
200 namespace {
201 class BumpPtrStringSaver : public llvm::cl::StringSaver {
202 public:
203   BumpPtrStringSaver(lld::coff::StringAllocator *A) : Alloc(A) {}
204   const char *SaveString(const char *S) override {
205     return Alloc->save(S).data();
206   }
207   lld::coff::StringAllocator *Alloc;
208 };
209 }
210 
211 std::vector<const char *> ArgParser::tokenize(StringRef S) {
212   SmallVector<const char *, 16> Tokens;
213   BumpPtrStringSaver Saver(&Alloc);
214   llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens);
215   return std::vector<const char *>(Tokens.begin(), Tokens.end());
216 }
217 
218 // Creates a new command line by replacing options starting with '@'
219 // character. '@<filename>' is replaced by the file's contents.
220 ErrorOr<std::vector<const char *>>
221 ArgParser::replaceResponseFiles(std::vector<const char *> Argv) {
222   SmallVector<const char *, 256> Tokens(&Argv[0], &Argv[0] + Argv.size());
223   BumpPtrStringSaver Saver(&Alloc);
224   ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens);
225   return std::vector<const char *>(Tokens.begin(), Tokens.end());
226 }
227 
228 void printHelp(const char *Argv0) {
229   COFFOptTable Table;
230   Table.PrintHelp(llvm::outs(), Argv0, "LLVM Linker", false);
231 }
232 
233 } // namespace coff
234 } // namespace lld
235