Reorganize the cpio archiver as CpioFile class. NFC.

This code separates the code to create cpio archive from the driver.

llvm-svn: 269593
This commit is contained in:
Rui Ueyama 2016-05-15 17:10:23 +00:00
parent 6c7bddb28b
commit fe65877c76
5 changed files with 80 additions and 66 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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();
CpioFile::CpioFile(std::unique_ptr<llvm::raw_fd_ostream> OS, StringRef S)
: OS(std::move(OS)), Basename(S) {}
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 maybePrintCpioMemberAux(raw_fd_ostream &OS, StringRef Path,
StringRef Data) {
OS << "070707"; // c_magic
// 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
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())
void CpioFile::append(StringRef Path, StringRef Data) {
if (!Seen.insert(Path).second)
return;
if (!Driver->IncludedFiles.insert(Path).second)
return;
raw_fd_ostream &OS = *Driver->ReproduceArchive;
maybePrintCpioMemberAux(OS, Path, 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.
// 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);
// 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) {

View File

@ -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;
}