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