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 "Driver.h" 17 #include "Error.h" 18 #include "lld/Config/Version.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/Option/Option.h" 21 #include "llvm/Support/CommandLine.h" 22 #include "llvm/Support/FileSystem.h" 23 #include "llvm/Support/Path.h" 24 #include "llvm/Support/StringSaver.h" 25 26 using namespace llvm; 27 using namespace llvm::sys; 28 29 using namespace lld; 30 using namespace lld::elf; 31 32 // Create OptTable 33 34 // Create prefix string literals used in Options.td 35 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; 36 #include "Options.inc" 37 #undef PREFIX 38 39 // Create table mapping all options defined in Options.td 40 static const opt::OptTable::Info OptInfo[] = { 41 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ 42 { \ 43 X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, X8, X7, OPT_##GROUP, \ 44 OPT_##ALIAS, X6 \ 45 }, 46 #include "Options.inc" 47 #undef OPTION 48 }; 49 50 ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} 51 52 // Parses a given list of options. 53 opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { 54 // Make InputArgList from string vectors. 55 unsigned MissingIndex; 56 unsigned MissingCount; 57 58 // Expand response files. '@<filename>' is replaced by the file's contents. 59 SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); 60 StringSaver Saver(Alloc); 61 cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Vec); 62 63 // Parse options and then do error checking. 64 opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); 65 if (MissingCount) 66 error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + 67 "\", expected " + Twine(MissingCount) + 68 (MissingCount == 1 ? " argument.\n" : " arguments")); 69 70 iterator_range<opt::arg_iterator> Unknowns = Args.filtered(OPT_UNKNOWN); 71 for (auto *Arg : Unknowns) 72 warning("warning: unknown argument: " + Arg->getSpelling()); 73 if (Unknowns.begin() != Unknowns.end()) 74 error("unknown argument(s) found"); 75 return Args; 76 } 77 78 void elf::printHelp(const char *Argv0) { 79 ELFOptTable Table; 80 Table.PrintHelp(outs(), Argv0, "lld", false); 81 } 82 83 std::string elf::getVersionString() { 84 std::string Version = getLLDVersion(); 85 std::string Repo = getLLDRepositoryVersion(); 86 if (Repo.empty()) 87 return "LLD " + Version + "\n"; 88 return "LLD " + Version + " " + Repo + "\n"; 89 } 90 91 // Converts a hex string (e.g. "0x123456") to a vector. 92 std::vector<uint8_t> elf::parseHexstring(StringRef S) { 93 if (S.find_first_not_of("0123456789abcdefABCDEF") != StringRef::npos || 94 S.size() % 2) { 95 error("malformed hexstring: " + S); 96 return {}; 97 } 98 std::vector<uint8_t> V; 99 for (; !S.empty(); S = S.substr(2)) { 100 int I; 101 S.substr(0, 2).getAsInteger(16, I); 102 V.push_back(I); 103 } 104 return V; 105 } 106 107 // Makes a given pathname an absolute path first, and then remove 108 // beginning /. For example, "../foo.o" is converted to "home/john/foo.o", 109 // assuming that the current directory is "/home/john/bar". 110 std::string elf::relativeToRoot(StringRef Path) { 111 SmallString<128> Abs = Path; 112 if (std::error_code EC = fs::make_absolute(Abs)) 113 fatal("make_absolute failed: " + EC.message()); 114 path::remove_dots(Abs, /*remove_dot_dot=*/true); 115 116 // This is Windows specific. root_name() returns a drive letter 117 // (e.g. "c:") or a UNC name (//net). We want to keep it as part 118 // of the result. 119 SmallString<128> Res; 120 StringRef Root = path::root_name(Abs); 121 if (Root.endswith(":")) 122 Res = Root.drop_back(); 123 else if (Root.startswith("//")) 124 Res = Root.substr(2); 125 126 path::append(Res, path::relative_path(Abs)); 127 return Res.str(); 128 } 129 130 CpioFile::CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef S) 131 : OS(std::move(OS)), Basename(S) {} 132 133 CpioFile *CpioFile::create(StringRef OutputPath) { 134 std::string Path = (OutputPath + ".cpio").str(); 135 std::error_code EC; 136 auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, fs::F_None); 137 if (EC) { 138 error(EC, "--reproduce: failed to open " + Path); 139 return nullptr; 140 } 141 return new CpioFile(std::move(OS), path::filename(OutputPath)); 142 } 143 144 static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) { 145 // The c_dev/c_ino pair should be unique according to the spec, 146 // but no one seems to care. 147 OS << "070707"; // c_magic 148 OS << "000000"; // c_dev 149 OS << "000000"; // c_ino 150 OS << "100664"; // c_mode: C_ISREG | rw-rw-r-- 151 OS << "000000"; // c_uid 152 OS << "000000"; // c_gid 153 OS << "000001"; // c_nlink 154 OS << "000000"; // c_rdev 155 OS << "00000000000"; // c_mtime 156 OS << format("%06o", Path.size() + 1); // c_namesize 157 OS << format("%011o", Data.size()); // c_filesize 158 OS << Path << '\0'; // c_name 159 OS << Data; // c_filedata 160 } 161 162 void CpioFile::append(StringRef Path, StringRef Data) { 163 if (!Seen.insert(Path).second) 164 return; 165 166 // Construct an in-archive filename so that /home/foo/bar is stored 167 // as baz/home/foo/bar where baz is the basename of the output file. 168 // (i.e. in that case we are creating baz.cpio.) 169 SmallString<128> Fullpath; 170 path::append(Fullpath, Basename, Path); 171 writeMember(*OS, Fullpath, Data); 172 173 // Print the trailer and seek back. 174 // This way we have a valid archive if we crash. 175 uint64_t Pos = OS->tell(); 176 writeMember(*OS, "TRAILER!!!", ""); 177 OS->seek(Pos); 178 } 179 180 // Quote a given string if it contains a space character. 181 static std::string quote(StringRef S) { 182 if (S.find(' ') == StringRef::npos) 183 return S; 184 return ("\"" + S + "\"").str(); 185 } 186 187 static std::string rewritePath(StringRef S) { 188 if (fs::exists(S)) 189 return relativeToRoot(S); 190 return S; 191 } 192 193 static std::string stringize(opt::Arg *Arg) { 194 std::string K = Arg->getSpelling(); 195 if (Arg->getNumValues() == 0) 196 return K; 197 std::string V = quote(Arg->getValue()); 198 if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle) 199 return K + V; 200 return K + " " + V; 201 } 202 203 // Reconstructs command line arguments so that so that you can re-run 204 // the same command with the same inputs. This is for --reproduce. 205 std::string elf::createResponseFile(const opt::InputArgList &Args) { 206 SmallString<0> Data; 207 raw_svector_ostream OS(Data); 208 209 // Copy the command line to the output while rewriting paths. 210 for (auto *Arg : Args) { 211 switch (Arg->getOption().getID()) { 212 case OPT_reproduce: 213 break; 214 case OPT_INPUT: 215 OS << quote(rewritePath(Arg->getValue())) << "\n"; 216 break; 217 case OPT_L: 218 case OPT_dynamic_list: 219 case OPT_rpath: 220 case OPT_alias_script_T: 221 case OPT_script: 222 case OPT_version_script: 223 OS << Arg->getSpelling() << " " 224 << quote(rewritePath(Arg->getValue())) << "\n"; 225 break; 226 default: 227 OS << stringize(Arg) << "\n"; 228 } 229 } 230 return Data.str(); 231 } 232 233 std::string elf::findFromSearchPaths(StringRef Path) { 234 for (StringRef Dir : Config->SearchPaths) { 235 std::string FullPath = buildSysrootedPath(Dir, Path); 236 if (fs::exists(FullPath)) 237 return FullPath; 238 } 239 return ""; 240 } 241 242 // Searches a given library from input search paths, which are filled 243 // from -L command line switches. Returns a path to an existent library file. 244 std::string elf::searchLibrary(StringRef Path) { 245 if (Path.startswith(":")) 246 return findFromSearchPaths(Path.substr(1)); 247 if (!Config->Static) { 248 std::string S = findFromSearchPaths(("lib" + Path + ".so").str()); 249 if (!S.empty()) 250 return S; 251 } 252 return findFromSearchPaths(("lib" + Path + ".a").str()); 253 } 254 255 // Makes a path by concatenating Dir and File. 256 // If Dir starts with '=' the result will be preceded by Sysroot, 257 // which can be set with --sysroot command line switch. 258 std::string elf::buildSysrootedPath(StringRef Dir, StringRef File) { 259 SmallString<128> Path; 260 if (Dir.startswith("=")) 261 path::append(Path, Config->Sysroot, Dir.substr(1), File); 262 else 263 path::append(Path, Dir, File); 264 return Path.str(); 265 } 266