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