1 //===- DebugTypes.cpp -----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "DebugTypes.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"
22 using namespace llvm::codeview
;
24 using namespace lld::coff
;
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
{
36 explicit TypeServerSource(MemoryBufferRef m
, llvm::pdb::NativeSession
*s
)
37 : TpiSource(PDB
, nullptr), session(s
), mb(m
) {}
39 // Queue a PDB type server for loading in the COFF Driver
40 static void enqueue(const ObjFile
*dependentFile
,
41 const TypeServer2Record
&ts
);
44 static Expected
<TypeServerSource
*> getInstance(MemoryBufferRef m
);
46 // Fetch the PDB instance loaded for a corresponding dependent OBJ.
47 static Expected
<TypeServerSource
*>
48 findFromFile(const ObjFile
*dependentFile
);
50 static std::map
<std::string
, std::pair
<std::string
, TypeServerSource
*>>
53 // The interface to the PDB (if it was opened successfully)
54 std::unique_ptr
<llvm::pdb::NativeSession
> session
;
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
{
64 UseTypeServerSource(const ObjFile
*f
, const TypeServer2Record
*ts
)
65 : TpiSource(UsingPDB
, f
), typeServerDependency(*ts
) {}
67 // Information about the PDB type server dependency, that needs to be loaded
68 // in before merging this OBJ.
69 TypeServer2Record typeServerDependency
;
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
{
78 PrecompSource(const ObjFile
*f
) : TpiSource(PCH
, f
) {}
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
{
85 UsePrecompSource(const ObjFile
*f
, const PrecompRecord
*precomp
)
86 : TpiSource(UsingPCH
, f
), precompDependency(*precomp
) {}
88 // Information about the Precomp OBJ dependency, that needs to be loaded in
89 // before merging this OBJ.
90 PrecompRecord precompDependency
;
94 TpiSource::TpiSource(TpiKind k
, const ObjFile
*f
) : kind(k
), file(f
) {}
96 TpiSource
*lld::coff::makeTpiSource(const ObjFile
*f
) {
97 return make
<TpiSource
>(TpiSource::Regular
, f
);
100 TpiSource
*lld::coff::makeUseTypeServerSource(const ObjFile
*f
,
101 const TypeServer2Record
*ts
) {
102 TypeServerSource::enqueue(f
, *ts
);
103 return make
<UseTypeServerSource
>(f
, ts
);
106 TpiSource
*lld::coff::makePrecompSource(const ObjFile
*f
) {
107 return make
<PrecompSource
>(f
);
110 TpiSource
*lld::coff::makeUsePrecompSource(const ObjFile
*f
,
111 const PrecompRecord
*precomp
) {
112 return make
<UsePrecompSource
>(f
, precomp
);
118 const PrecompRecord
&retrieveDependencyInfo(const TpiSource
*source
) {
119 assert(source
->kind
== TpiSource::UsingPCH
);
120 return ((const UsePrecompSource
*)source
)->precompDependency
;
124 const TypeServer2Record
&retrieveDependencyInfo(const TpiSource
*source
) {
125 assert(source
->kind
== TpiSource::UsingPDB
);
126 return ((const UseTypeServerSource
*)source
)->typeServerDependency
;
131 std::map
<std::string
, std::pair
<std::string
, TypeServerSource
*>>
132 TypeServerSource::instances
;
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
);
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());
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
) {
153 return std::string(path
);
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
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
);
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
);
178 Optional
<std::string
> p
= findPdbPath(ts
.Name
, dependentFile
);
180 return createFileError(ts
.Name
, errorCodeToError(std::error_code(
181 ENOENT
, std::generic_category())));
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());
188 std::pair
<std::string
, TypeServerSource
*> &pdb
= it
->second
;
191 return createFileError(
192 *p
, createStringError(inconvertibleErrorCode(), pdb
.first
.c_str()));
194 pdb::PDBFile
&pdbFile
= (pdb
.second
)->session
->getPDBFile();
195 pdb::InfoStream
&info
= cantFail(pdbFile
.getPDBInfoStream());
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(
203 make_error
<pdb::PDBError
>(pdb::pdb_error_code::signature_out_of_date
));
208 // FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is
210 Expected
<llvm::pdb::NativeSession
*>
211 lld::coff::findTypeServerSource(const ObjFile
*f
) {
212 Expected
<TypeServerSource
*> ts
= TypeServerSource::findFromFile(f
);
214 return ts
.takeError();
215 return ts
.get()->session
.get();
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
223 Optional
<std::string
> p
= findPdbPath(ts
.Name
, dependentFile
);
226 auto it
= TypeServerSource::instances
.emplace(
227 *p
, std::pair
<std::string
, TypeServerSource
*>{});
229 return; // another OBJ already scheduled this PDB for load
231 driver
->enqueuePath(*p
, false, false);
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());
242 Expected
<TypeServerSource
*> ts
= TypeServerSource::getInstance(m
);
244 TypeServerSource::instances
[path
] = {toString(ts
.takeError()), nullptr};
246 TypeServerSource::instances
[path
] = {{}, *ts
};
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
);
254 return std::move(err
);
256 std::unique_ptr
<llvm::pdb::NativeSession
> session(
257 static_cast<pdb::NativeSession
*>(iSession
.release()));
259 pdb::PDBFile
&pdbFile
= session
->getPDBFile();
260 Expected
<pdb::InfoStream
&> info
= pdbFile
.getPDBInfoStream();
261 // All PDB Files should have an Info stream.
263 return info
.takeError();
264 return make
<TypeServerSource
>(m
, session
.release());