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