]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/Core/Reproduce.cpp
Vendor import of lld trunk r290819:
[FreeBSD/FreeBSD.git] / lib / Core / Reproduce.cpp
1 //===- Reproduce.cpp - Utilities for creating reproducers -----------------===//
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 #include "lld/Core/Reproduce.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/Option/Arg.h"
14 #include "llvm/Support/Error.h"
15 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/Format.h"
17 #include "llvm/Support/Path.h"
18
19 using namespace lld;
20 using namespace llvm;
21 using namespace sys;
22
23 CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S)
24     : OS(std::move(OS)), Basename(S) {}
25
26 ErrorOr<CpioFile *> CpioFile::create(StringRef OutputPath) {
27   std::string Path = (OutputPath + ".cpio").str();
28   std::error_code EC;
29   auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
30   if (EC)
31     return EC;
32   return new CpioFile(std::move(OS), path::filename(OutputPath));
33 }
34
35 static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) {
36   // The c_dev/c_ino pair should be unique according to the spec,
37   // but no one seems to care.
38   OS << "070707";                        // c_magic
39   OS << "000000";                        // c_dev
40   OS << "000000";                        // c_ino
41   OS << "100664";                        // c_mode: C_ISREG | rw-rw-r--
42   OS << "000000";                        // c_uid
43   OS << "000000";                        // c_gid
44   OS << "000001";                        // c_nlink
45   OS << "000000";                        // c_rdev
46   OS << "00000000000";                   // c_mtime
47   OS << format("%06o", Path.size() + 1); // c_namesize
48   OS << format("%011o", Data.size());    // c_filesize
49   OS << Path << '\0';                    // c_name
50   OS << Data;                            // c_filedata
51 }
52
53 void CpioFile::append(StringRef Path, StringRef Data) {
54   if (!Seen.insert(Path).second)
55     return;
56
57   // Construct an in-archive filename so that /home/foo/bar is stored
58   // as baz/home/foo/bar where baz is the basename of the output file.
59   // (i.e. in that case we are creating baz.cpio.)
60   SmallString<128> Fullpath;
61   path::append(Fullpath, Basename, Path);
62
63   writeMember(*OS, convertToUnixPathSeparator(Fullpath), Data);
64
65   // Print the trailer and seek back.
66   // This way we have a valid archive if we crash.
67   uint64_t Pos = OS->tell();
68   writeMember(*OS, "TRAILER!!!", "");
69   OS->seek(Pos);
70 }
71
72 // Makes a given pathname an absolute path first, and then remove
73 // beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
74 // assuming that the current directory is "/home/john/bar".
75 // Returned string is a forward slash separated path even on Windows to avoid
76 // a mess with backslash-as-escape and backslash-as-path-separator.
77 std::string lld::relativeToRoot(StringRef Path) {
78   SmallString<128> Abs = Path;
79   if (sys::fs::make_absolute(Abs))
80     return Path;
81   path::remove_dots(Abs, /*remove_dot_dot=*/true);
82
83   // This is Windows specific. root_name() returns a drive letter
84   // (e.g. "c:") or a UNC name (//net). We want to keep it as part
85   // of the result.
86   SmallString<128> Res;
87   StringRef Root = path::root_name(Abs);
88   if (Root.endswith(":"))
89     Res = Root.drop_back();
90   else if (Root.startswith("//"))
91     Res = Root.substr(2);
92
93   path::append(Res, path::relative_path(Abs));
94   return convertToUnixPathSeparator(Res);
95 }
96
97 // Quote a given string if it contains a space character.
98 std::string lld::quote(StringRef S) {
99   if (S.find(' ') == StringRef::npos)
100     return S;
101   return ("\"" + S + "\"").str();
102 }
103
104 std::string lld::rewritePath(StringRef S) {
105   if (fs::exists(S))
106     return relativeToRoot(S);
107   return S;
108 }
109
110 std::string lld::stringize(opt::Arg *Arg) {
111   std::string K = Arg->getSpelling();
112   if (Arg->getNumValues() == 0)
113     return K;
114   std::string V = quote(Arg->getValue());
115   if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
116     return K + V;
117   return K + " " + V;
118 }
119
120 std::string lld::convertToUnixPathSeparator(StringRef S) {
121 #ifdef LLVM_ON_WIN32
122   std::string Ret = S.str();
123   std::replace(Ret.begin(), Ret.end(), '\\', '/');
124   return Ret;
125 #else
126   return S;
127 #endif
128 }