diff options
-rw-r--r-- | lld/ELF/Config.h | 1 | ||||
-rw-r--r-- | lld/ELF/Driver.cpp | 19 | ||||
-rw-r--r-- | lld/ELF/Driver.h | 38 | ||||
-rw-r--r-- | lld/ELF/DriverUtils.cpp | 85 | ||||
-rw-r--r-- | lld/ELF/InputFiles.cpp | 5 |
5 files changed, 81 insertions, 67 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 2261cfee343..7866bc2ad8c 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -48,7 +48,6 @@ struct Configuration { llvm::StringRef SoName; llvm::StringRef Sysroot; std::string RPath; - std::string Reproduce; std::vector<llvm::StringRef> DynamicList; std::vector<llvm::StringRef> SearchPaths; std::vector<llvm::StringRef> Undefined; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index c73f280dc09..45799c9c319 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -114,7 +114,8 @@ void LinkerDriver::addFile(StringRef Path) { return; MemoryBufferRef MBRef = *Buffer; - maybeCopyInputFile(Path, MBRef.getBuffer()); + if (Cpio) + Cpio->append(relativeToRoot(Path), MBRef.getBuffer()); switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: @@ -252,15 +253,12 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { readConfigs(Args); initLLVM(Args); - if (!Config->Reproduce.empty()) { - std::error_code EC; - std::string File = Config->Reproduce + ".cpio"; - ReproduceArchive = llvm::make_unique<raw_fd_ostream>(File, EC, fs::F_None); - if (EC) { - error(EC, "--reproduce: failed to open " + File); - return; - } - createResponseFile(Args); + if (auto *Arg = Args.getLastArg(OPT_reproduce)) { + // Note that --reproduce is a debug option so you can ignore it + // if you are trying to understand the whole picture of the code. + Cpio.reset(CpioFile::create(Arg->getValue())); + if (Cpio) + Cpio->append("response.txt", createResponseFile(Args)); } createFiles(Args); @@ -340,7 +338,6 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Fini = getString(Args, OPT_fini, "_fini"); Config->Init = getString(Args, OPT_init, "_init"); Config->OutputFile = getString(Args, OPT_o); - Config->Reproduce = getString(Args, OPT_reproduce); Config->SoName = getString(Args, OPT_soname); Config->Sysroot = getString(Args, OPT_sysroot); diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h index 1412ec9a302..00f8e05601a 100644 --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -23,16 +23,15 @@ namespace elf { extern class LinkerDriver *Driver; +class CpioFile; + class LinkerDriver { public: void main(ArrayRef<const char *> Args); void addFile(StringRef Path); void addLibrary(StringRef Name); - llvm::LLVMContext Context; - - // for --reproduce - std::unique_ptr<llvm::raw_fd_ostream> ReproduceArchive; - llvm::StringSet<> IncludedFiles; + llvm::LLVMContext Context; // to parse bitcode ifles + std::unique_ptr<CpioFile> Cpio; // for reproduce private: std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB); @@ -70,12 +69,37 @@ enum { #undef OPTION }; +// This is the class to create a .cpio file for --reproduce. +// +// If "--reproduce foo" is given, we create a file "foo.cpio" and +// copy all input files to the archive, along with a response file +// to re-run the same command with the same inputs. +// It is useful for reporting issues to LLD developers. +// +// Cpio as a file format is a deliberate choice. It's standardized in +// POSIX and very easy to create. cpio command is available virtually +// on all Unix systems. See +// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_07 +// for the format details. +class CpioFile { +public: + static CpioFile *create(StringRef OutputPath); + void append(StringRef Path, StringRef Data); + +private: + CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef Basename); + + std::unique_ptr<llvm::raw_fd_ostream> OS; + llvm::StringSet<> Seen; + std::string Basename; +}; + void printHelp(const char *Argv0); void printVersion(); std::vector<uint8_t> parseHexstring(StringRef S); -void createResponseFile(const llvm::opt::InputArgList &Args); -void maybeCopyInputFile(StringRef Path, StringRef Buffer); +std::string createResponseFile(const llvm::opt::InputArgList &Args); +std::string relativeToRoot(StringRef Path); std::string findFromSearchPaths(StringRef Path); std::string searchLibrary(StringRef Path); diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp index 801a906848d..b1184620ead 100644 --- a/lld/ELF/DriverUtils.cpp +++ b/lld/ELF/DriverUtils.cpp @@ -107,7 +107,7 @@ std::vector<uint8_t> elf::parseHexstring(StringRef S) { // Makes a given pathname an absolute path first, and then remove // beginning /. For example, "../foo.o" is converted to "home/john/foo.o", // assuming that the current directory is "/home/john/bar". -static std::string relativeToRoot(StringRef Path) { +std::string elf::relativeToRoot(StringRef Path) { SmallString<128> Abs = Path; if (std::error_code EC = fs::make_absolute(Abs)) fatal("make_absolute failed: " + EC.message()); @@ -127,22 +127,26 @@ static std::string relativeToRoot(StringRef Path) { return Res.str(); } -static std::string getDestPath(StringRef Path) { - std::string Relpath = relativeToRoot(Path); - SmallString<128> Dest; - path::append(Dest, path::filename(Config->Reproduce), Relpath); - return Dest.str(); -} - -static void maybePrintCpioMemberAux(raw_fd_ostream &OS, StringRef Path, - StringRef Data) { - OS << "070707"; // c_magic +CpioFile::CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef S) + : OS(std::move(OS)), Basename(S) {} - // The c_dev/c_ino pair should be unique according to the spec, but no one - // seems to care. - OS << "000000"; // c_dev - OS << "000000"; // c_ino +CpioFile *CpioFile::create(StringRef OutputPath) { + std::string Path = (OutputPath + ".cpio").str(); + std::error_code EC; + auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, fs::F_None); + if (EC) { + error(EC, "--reproduce: failed to open " + Path); + return nullptr; + } + return new CpioFile(std::move(OS), path::filename(OutputPath)); +} +static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) { + // The c_dev/c_ino pair should be unique according to the spec, + // but no one seems to care. + OS << "070707"; // c_magic + OS << "000000"; // c_dev + OS << "000000"; // c_ino OS << "100664"; // c_mode: C_ISREG | rw-rw-r-- OS << "000000"; // c_uid OS << "000000"; // c_gid @@ -155,28 +159,22 @@ static void maybePrintCpioMemberAux(raw_fd_ostream &OS, StringRef Path, OS << Data; // c_filedata } -static void maybePrintCpioMember(StringRef Path, StringRef Data) { - if (Config->Reproduce.empty()) - return; - - if (!Driver->IncludedFiles.insert(Path).second) +void CpioFile::append(StringRef Path, StringRef Data) { + if (!Seen.insert(Path).second) return; - raw_fd_ostream &OS = *Driver->ReproduceArchive; - maybePrintCpioMemberAux(OS, Path, Data); - - // Print the trailer and seek back. This way we have a valid archive if we - // crash. - // See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_11 - // for the format details. - uint64_t Pos = OS.tell(); - maybePrintCpioMemberAux(OS, "TRAILER!!!", ""); - OS.seek(Pos); -} -// Write file Src with content Data to the archive. -void elf::maybeCopyInputFile(StringRef Src, StringRef Data) { - std::string Dest = getDestPath(Src); - maybePrintCpioMember(Dest, Data); + // Construct an in-archive filename so that /home/foo/bar is stored + // as baz/home/foo/bar where baz is the basename of the output file. + // (i.e. in that case we are creating baz.cpio.) + SmallString<128> Fullpath; + path::append(Fullpath, Basename, Path); + writeMember(*OS, Fullpath, Data); + + // Print the trailer and seek back. + // This way we have a valid archive if we crash. + uint64_t Pos = OS->tell(); + writeMember(*OS, "TRAILER!!!", ""); + OS->seek(Pos); } // Quote a given string if it contains a space character. @@ -202,15 +200,13 @@ static std::string stringize(opt::Arg *Arg) { return K + " " + V; } -// Copies all input files to Config->Reproduce directory and -// create a response file as "response.txt", so that you can re-run -// the same command with the same inputs just by executing -// "ld.lld @response.txt". Used by --reproduce. This feature is -// supposed to be used by users to report an issue to LLD developers. -void elf::createResponseFile(const opt::InputArgList &Args) { +// Reconstructs command line arguments so that so that you can re-run +// the same command with the same inputs. This is for --reproduce. +std::string elf::createResponseFile(const opt::InputArgList &Args) { SmallString<0> Data; raw_svector_ostream OS(Data); - // Copy the command line to response.txt while rewriting paths. + + // Copy the command line to the output while rewriting paths. for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_reproduce: @@ -230,10 +226,7 @@ void elf::createResponseFile(const opt::InputArgList &Args) { OS << stringize(Arg) << "\n"; } } - - SmallString<128> Dest; - path::append(Dest, path::filename(Config->Reproduce), "response.txt"); - maybePrintCpioMember(Dest, Data); + return Data.str(); } std::string elf::findFromSearchPaths(StringRef Path) { diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 47e4b33c22a..f1c0bb993a8 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -394,8 +394,9 @@ MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { "could not get the buffer for the member defining symbol " + Sym->getName()); - if (C.getParent()->isThin()) - maybeCopyInputFile(check(C.getFullName()), Ret.getBuffer()); + if (C.getParent()->isThin() && Driver->Cpio) + Driver->Cpio->append(relativeToRoot(check(C.getFullName())), + Ret.getBuffer()); return Ret; } |