summaryrefslogtreecommitdiffstats
path: root/lld/ELF/DriverUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/DriverUtils.cpp')
-rw-r--r--lld/ELF/DriverUtils.cpp94
1 files changed, 78 insertions, 16 deletions
diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp
index 3953d5f2a16..57dfea357a3 100644
--- a/lld/ELF/DriverUtils.cpp
+++ b/lld/ELF/DriverUtils.cpp
@@ -87,31 +87,93 @@ void elf::printVersion() {
outs() << "\n";
}
-// Concatenates S and T so that the resulting path becomes S/T.
-// There are a few exceptions:
-//
-// 1. The result will never escape from S. Therefore, all ".."
-// are removed from T before concatenatig them.
-// 2. Windows drive letters are removed from T before concatenation.
-std::string elf::concat_paths(StringRef S, StringRef T) {
- // Remove leading '/' or a drive letter, and then remove "..".
- SmallString<128> T2(path::relative_path(T));
- path::remove_dots(T2, /*remove_dot_dot=*/true);
-
+// 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 relative_to_root(StringRef Path) {
+ SmallString<128> Abs = Path;
+ if (std::error_code EC = fs::make_absolute(Abs))
+ fatal("make_absolute failed: " + EC.message());
+ 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;
- path::append(Res, S, T2);
+ StringRef Root = path::root_name(Path);
+ if (Path.endswith(":"))
+ Res = Root.drop_back();
+ else if (Path.startswith("//"))
+ Res = Root.substr(2);
+
+ path::append(Res, path::relative_path(Abs));
return Res.str();
}
-void elf::copyFile(StringRef Src, StringRef Dest) {
+// Copies file Src to {Config->Reproduce}/Src.
+// Returns the new path relative to Config->Reproduce.
+static std::string copyFile(StringRef Src) {
+ std::string Relpath = relative_to_root(Src);
+ SmallString<128> Dest;
+ path::append(Dest, Config->Reproduce, Relpath);
+
SmallString<128> Dir(Dest);
path::remove_filename(Dir);
- if (std::error_code EC = sys::fs::create_directories(Dir)) {
+ if (std::error_code EC = sys::fs::create_directories(Dir))
error(EC, Dir + ": can't create directory");
- return;
- }
if (std::error_code EC = sys::fs::copy_file(Src, Dest))
error(EC, "failed to copy file: " + Dest);
+ return Relpath;
+}
+
+// Quote a given string if it contains a space character.
+static std::string quote(StringRef S) {
+ if (S.find(' ') == StringRef::npos)
+ return S;
+ return ("\"" + S + "\"").str();
+}
+
+// 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::saveLinkerInputs(const llvm::opt::InputArgList &Args) {
+ // Create the output directory.
+ if (std::error_code EC = sys::fs::create_directories(
+ Config->Reproduce, /*IgnoreExisting=*/false)) {
+ error(EC, Config->Reproduce + ": can't create directory");
+ return;
+ }
+
+ // Open "response.txt".
+ SmallString<128> Path;
+ path::append(Path, Config->Reproduce, "response.txt");
+ std::error_code EC;
+ raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
+ check(EC);
+
+ // Dump the command line to response.txt while copying files
+ // and rewriting paths.
+ for (auto *Arg : Args) {
+ switch (Arg->getOption().getID()) {
+ case OPT_reproduce:
+ break;
+ case OPT_script:
+ OS << "--script ";
+ // fallthrough
+ case OPT_INPUT: {
+ StringRef Path = Arg->getValue();
+ if (fs::exists(Path))
+ OS << quote(copyFile(Path)) << "\n";
+ else
+ OS << quote(Path) << "\n";
+ break;
+ }
+ default:
+ OS << Arg->getAsString(Args) << "\n";
+ }
+ }
}
std::string elf::findFromSearchPaths(StringRef Path) {
OpenPOWER on IntegriCloud