summaryrefslogtreecommitdiff
path: root/lib/Core/Reproduce.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:19:15 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:19:15 +0000
commitd93e1dfac8711cfed1a9d9cd1876a788b83945cd (patch)
tree5896fa6c02a262a6148b215487e545d937de58b7 /lib/Core/Reproduce.cpp
parent8d43286d630f9224de07809ea253e83ebb9cdee6 (diff)
Notes
Diffstat (limited to 'lib/Core/Reproduce.cpp')
-rw-r--r--lib/Core/Reproduce.cpp128
1 files changed, 128 insertions, 0 deletions
diff --git a/lib/Core/Reproduce.cpp b/lib/Core/Reproduce.cpp
new file mode 100644
index 000000000000..39b0e41c44e5
--- /dev/null
+++ b/lib/Core/Reproduce.cpp
@@ -0,0 +1,128 @@
+//===- Reproduce.cpp - Utilities for creating reproducers -----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/Reproduce.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+
+using namespace lld;
+using namespace llvm;
+using namespace sys;
+
+CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S)
+ : OS(std::move(OS)), Basename(S) {}
+
+ErrorOr<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, sys::fs::F_None);
+ if (EC)
+ return EC;
+ 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
+ OS << "000001"; // c_nlink
+ OS << "000000"; // c_rdev
+ OS << "00000000000"; // c_mtime
+ OS << format("%06o", Path.size() + 1); // c_namesize
+ OS << format("%011o", Data.size()); // c_filesize
+ OS << Path << '\0'; // c_name
+ OS << Data; // c_filedata
+}
+
+void CpioFile::append(StringRef Path, StringRef Data) {
+ if (!Seen.insert(Path).second)
+ return;
+
+ // 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, convertToUnixPathSeparator(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);
+}
+
+// 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".
+// Returned string is a forward slash separated path even on Windows to avoid
+// a mess with backslash-as-escape and backslash-as-path-separator.
+std::string lld::relativeToRoot(StringRef Path) {
+ SmallString<128> Abs = Path;
+ if (sys::fs::make_absolute(Abs))
+ return Path;
+ path::remove_dots(Abs, /*remove_dot_dot=*/true);
+
+ // This is Windows specific. root_name() returns a drive letter
+ // (e.g. "c:") or a UNC name (//net). We want to keep it as part
+ // of the result.
+ SmallString<128> Res;
+ StringRef Root = path::root_name(Abs);
+ if (Root.endswith(":"))
+ Res = Root.drop_back();
+ else if (Root.startswith("//"))
+ Res = Root.substr(2);
+
+ path::append(Res, path::relative_path(Abs));
+ return convertToUnixPathSeparator(Res);
+}
+
+// Quote a given string if it contains a space character.
+std::string lld::quote(StringRef S) {
+ if (S.find(' ') == StringRef::npos)
+ return S;
+ return ("\"" + S + "\"").str();
+}
+
+std::string lld::rewritePath(StringRef S) {
+ if (fs::exists(S))
+ return relativeToRoot(S);
+ return S;
+}
+
+std::string lld::stringize(opt::Arg *Arg) {
+ std::string K = Arg->getSpelling();
+ if (Arg->getNumValues() == 0)
+ return K;
+ std::string V = quote(Arg->getValue());
+ if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
+ return K + V;
+ return K + " " + V;
+}
+
+std::string lld::convertToUnixPathSeparator(StringRef S) {
+#ifdef LLVM_ON_WIN32
+ std::string Ret = S.str();
+ std::replace(Ret.begin(), Ret.end(), '\\', '/');
+ return Ret;
+#else
+ return S;
+#endif
+}