]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lld/COFF/DebugTypes.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lld / COFF / DebugTypes.cpp
1 //===- DebugTypes.cpp -----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "DebugTypes.h"
10 #include "Driver.h"
11 #include "InputFiles.h"
12 #include "lld/Common/ErrorHandler.h"
13 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
14 #include "llvm/DebugInfo/PDB/GenericError.h"
15 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
16 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
17 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
18 #include "llvm/Support/Path.h"
19
20 using namespace lld;
21 using namespace lld::coff;
22 using namespace llvm;
23 using namespace llvm::codeview;
24
25 namespace {
26 // The TypeServerSource class represents a PDB type server, a file referenced by
27 // OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ
28 // files, therefore there must be only once instance per OBJ lot. The file path
29 // is discovered from the dependent OBJ's debug type stream. The
30 // TypeServerSource object is then queued and loaded by the COFF Driver. The
31 // debug type stream for such PDB files will be merged first in the final PDB,
32 // before any dependent OBJ.
33 class TypeServerSource : public TpiSource {
34 public:
35   explicit TypeServerSource(MemoryBufferRef m, llvm::pdb::NativeSession *s)
36       : TpiSource(PDB, nullptr), session(s), mb(m) {}
37
38   // Queue a PDB type server for loading in the COFF Driver
39   static void enqueue(const ObjFile *dependentFile,
40                       const TypeServer2Record &ts);
41
42   // Create an instance
43   static Expected<TypeServerSource *> getInstance(MemoryBufferRef m);
44
45   // Fetch the PDB instance loaded for a corresponding dependent OBJ.
46   static Expected<TypeServerSource *>
47   findFromFile(const ObjFile *dependentFile);
48
49   static std::map<std::string, std::pair<std::string, TypeServerSource *>>
50       instances;
51
52   // The interface to the PDB (if it was opened successfully)
53   std::unique_ptr<llvm::pdb::NativeSession> session;
54
55 private:
56   MemoryBufferRef mb;
57 };
58
59 // This class represents the debug type stream of an OBJ file that depends on a
60 // PDB type server (see TypeServerSource).
61 class UseTypeServerSource : public TpiSource {
62 public:
63   UseTypeServerSource(const ObjFile *f, const TypeServer2Record *ts)
64       : TpiSource(UsingPDB, f), typeServerDependency(*ts) {}
65
66   // Information about the PDB type server dependency, that needs to be loaded
67   // in before merging this OBJ.
68   TypeServer2Record typeServerDependency;
69 };
70
71 // This class represents the debug type stream of a Microsoft precompiled
72 // headers OBJ (PCH OBJ). This OBJ kind needs to be merged first in the output
73 // PDB, before any other OBJs that depend on this. Note that only MSVC generate
74 // such files, clang does not.
75 class PrecompSource : public TpiSource {
76 public:
77   PrecompSource(const ObjFile *f) : TpiSource(PCH, f) {}
78 };
79
80 // This class represents the debug type stream of an OBJ file that depends on a
81 // Microsoft precompiled headers OBJ (see PrecompSource).
82 class UsePrecompSource : public TpiSource {
83 public:
84   UsePrecompSource(const ObjFile *f, const PrecompRecord *precomp)
85       : TpiSource(UsingPCH, f), precompDependency(*precomp) {}
86
87   // Information about the Precomp OBJ dependency, that needs to be loaded in
88   // before merging this OBJ.
89   PrecompRecord precompDependency;
90 };
91 } // namespace
92
93 static std::vector<std::unique_ptr<TpiSource>> GC;
94
95 TpiSource::TpiSource(TpiKind k, const ObjFile *f) : kind(k), file(f) {
96   GC.push_back(std::unique_ptr<TpiSource>(this));
97 }
98
99 TpiSource *lld::coff::makeTpiSource(const ObjFile *f) {
100   return new TpiSource(TpiSource::Regular, f);
101 }
102
103 TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *f,
104                                               const TypeServer2Record *ts) {
105   TypeServerSource::enqueue(f, *ts);
106   return new UseTypeServerSource(f, ts);
107 }
108
109 TpiSource *lld::coff::makePrecompSource(const ObjFile *f) {
110   return new PrecompSource(f);
111 }
112
113 TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *f,
114                                            const PrecompRecord *precomp) {
115   return new UsePrecompSource(f, precomp);
116 }
117
118 namespace lld {
119 namespace coff {
120 template <>
121 const PrecompRecord &retrieveDependencyInfo(const TpiSource *source) {
122   assert(source->kind == TpiSource::UsingPCH);
123   return ((const UsePrecompSource *)source)->precompDependency;
124 }
125
126 template <>
127 const TypeServer2Record &retrieveDependencyInfo(const TpiSource *source) {
128   assert(source->kind == TpiSource::UsingPDB);
129   return ((const UseTypeServerSource *)source)->typeServerDependency;
130 }
131 } // namespace coff
132 } // namespace lld
133
134 std::map<std::string, std::pair<std::string, TypeServerSource *>>
135     TypeServerSource::instances;
136
137 // Make a PDB path assuming the PDB is in the same folder as the OBJ
138 static std::string getPdbBaseName(const ObjFile *file, StringRef tSPath) {
139   StringRef localPath =
140       !file->parentName.empty() ? file->parentName : file->getName();
141   SmallString<128> path = sys::path::parent_path(localPath);
142
143   // Currently, type server PDBs are only created by MSVC cl, which only runs
144   // on Windows, so we can assume type server paths are Windows style.
145   sys::path::append(path, sys::path::filename(tSPath, sys::path::Style::windows));
146   return path.str();
147 }
148
149 // The casing of the PDB path stamped in the OBJ can differ from the actual path
150 // on disk. With this, we ensure to always use lowercase as a key for the
151 // PDBInputFile::Instances map, at least on Windows.
152 static std::string normalizePdbPath(StringRef path) {
153 #if defined(_WIN32)
154   return path.lower();
155 #else // LINUX
156   return path;
157 #endif
158 }
159
160 // If existing, return the actual PDB path on disk.
161 static Optional<std::string> findPdbPath(StringRef pdbPath,
162                                          const ObjFile *dependentFile) {
163   // Ensure the file exists before anything else. In some cases, if the path
164   // points to a removable device, Driver::enqueuePath() would fail with an
165   // error (EAGAIN, "resource unavailable try again") which we want to skip
166   // silently.
167   if (llvm::sys::fs::exists(pdbPath))
168     return normalizePdbPath(pdbPath);
169   std::string ret = getPdbBaseName(dependentFile, pdbPath);
170   if (llvm::sys::fs::exists(ret))
171     return normalizePdbPath(ret);
172   return None;
173 }
174
175 // Fetch the PDB instance that was already loaded by the COFF Driver.
176 Expected<TypeServerSource *>
177 TypeServerSource::findFromFile(const ObjFile *dependentFile) {
178   const TypeServer2Record &ts =
179       retrieveDependencyInfo<TypeServer2Record>(dependentFile->debugTypesObj);
180
181   Optional<std::string> p = findPdbPath(ts.Name, dependentFile);
182   if (!p)
183     return createFileError(ts.Name, errorCodeToError(std::error_code(
184                                         ENOENT, std::generic_category())));
185
186   auto it = TypeServerSource::instances.find(*p);
187   // The PDB file exists on disk, at this point we expect it to have been
188   // inserted in the map by TypeServerSource::loadPDB()
189   assert(it != TypeServerSource::instances.end());
190
191   std::pair<std::string, TypeServerSource *> &pdb = it->second;
192
193   if (!pdb.second)
194     return createFileError(
195         *p, createStringError(inconvertibleErrorCode(), pdb.first.c_str()));
196
197   pdb::PDBFile &pdbFile = (pdb.second)->session->getPDBFile();
198   pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream());
199
200   // Just because a file with a matching name was found doesn't mean it can be
201   // used. The GUID must match between the PDB header and the OBJ
202   // TypeServer2 record. The 'Age' is used by MSVC incremental compilation.
203   if (info.getGuid() != ts.getGuid())
204     return createFileError(
205         ts.Name,
206         make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
207
208   return pdb.second;
209 }
210
211 // FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is
212 // moved here.
213 Expected<llvm::pdb::NativeSession *>
214 lld::coff::findTypeServerSource(const ObjFile *f) {
215   Expected<TypeServerSource *> ts = TypeServerSource::findFromFile(f);
216   if (!ts)
217     return ts.takeError();
218   return ts.get()->session.get();
219 }
220
221 // Queue a PDB type server for loading in the COFF Driver
222 void TypeServerSource::enqueue(const ObjFile *dependentFile,
223                                const TypeServer2Record &ts) {
224   // Start by finding where the PDB is located (either the record path or next
225   // to the OBJ file)
226   Optional<std::string> p = findPdbPath(ts.Name, dependentFile);
227   if (!p)
228     return;
229   auto it = TypeServerSource::instances.emplace(
230       *p, std::pair<std::string, TypeServerSource *>{});
231   if (!it.second)
232     return; // another OBJ already scheduled this PDB for load
233
234   driver->enqueuePath(*p, false);
235 }
236
237 // Create an instance of TypeServerSource or an error string if the PDB couldn't
238 // be loaded. The error message will be displayed later, when the referring OBJ
239 // will be merged in. NOTE - a PDB load failure is not a link error: some
240 // debug info will simply be missing from the final PDB - that is the default
241 // accepted behavior.
242 void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef m) {
243   std::string path = normalizePdbPath(m.getBufferIdentifier());
244
245   Expected<TypeServerSource *> ts = TypeServerSource::getInstance(m);
246   if (!ts)
247     TypeServerSource::instances[path] = {toString(ts.takeError()), nullptr};
248   else
249     TypeServerSource::instances[path] = {{}, *ts};
250 }
251
252 Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef m) {
253   std::unique_ptr<llvm::pdb::IPDBSession> iSession;
254   Error err = pdb::NativeSession::createFromPdb(
255       MemoryBuffer::getMemBuffer(m, false), iSession);
256   if (err)
257     return std::move(err);
258
259   std::unique_ptr<llvm::pdb::NativeSession> session(
260       static_cast<pdb::NativeSession *>(iSession.release()));
261
262   pdb::PDBFile &pdbFile = session->getPDBFile();
263   Expected<pdb::InfoStream &> info = pdbFile.getPDBInfoStream();
264   // All PDB Files should have an Info stream.
265   if (!info)
266     return info.takeError();
267   return new TypeServerSource(m, session.release());
268 }