forked from OSchip/llvm-project
Revert r361842 as it breaks LLDB :: tools/lldb-mi/exec/exec-finish.test
llvm-svn: 361876
This commit is contained in:
parent
6d7bf5e8df
commit
ccc1fa5e1d
|
@ -7,15 +7,8 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "DebugTypes.h"
|
#include "DebugTypes.h"
|
||||||
#include "Driver.h"
|
|
||||||
#include "InputFiles.h"
|
#include "InputFiles.h"
|
||||||
#include "lld/Common/ErrorHandler.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/PDB/GenericError.h"
|
|
||||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
|
||||||
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
|
|
||||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
|
||||||
#include "llvm/Support/Path.h"
|
|
||||||
|
|
||||||
using namespace lld;
|
using namespace lld;
|
||||||
using namespace lld::coff;
|
using namespace lld::coff;
|
||||||
|
@ -23,44 +16,14 @@ using namespace llvm;
|
||||||
using namespace llvm::codeview;
|
using namespace llvm::codeview;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// The TypeServerSource class represents a PDB type server, a file referenced by
|
|
||||||
// OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ
|
|
||||||
// files, therefore there must be only once instance per OBJ lot. The file path
|
|
||||||
// is discovered from the dependent OBJ's debug type stream. The
|
|
||||||
// TypeServerSource object is then queued and loaded by the COFF Driver. The
|
|
||||||
// debug type stream for such PDB files will be merged first in the final PDB,
|
|
||||||
// before any dependent OBJ.
|
|
||||||
class TypeServerSource : public TpiSource {
|
class TypeServerSource : public TpiSource {
|
||||||
public:
|
public:
|
||||||
explicit TypeServerSource(MemoryBufferRef M, llvm::pdb::NativeSession *S)
|
TypeServerSource(ObjFile *F) : TpiSource(PDB, F) {}
|
||||||
: TpiSource(PDB, nullptr), Session(S), MB(M) {}
|
|
||||||
|
|
||||||
// Queue a PDB type server for loading in the COFF Driver
|
|
||||||
static void enqueue(const ObjFile *DependentFile,
|
|
||||||
const TypeServer2Record &TS);
|
|
||||||
|
|
||||||
// Create an instance
|
|
||||||
static Expected<TypeServerSource *> getInstance(MemoryBufferRef M);
|
|
||||||
|
|
||||||
// Fetch the PDB instance loaded for a corresponding dependent OBJ.
|
|
||||||
static Expected<TypeServerSource *>
|
|
||||||
findFromFile(const ObjFile *DependentFile);
|
|
||||||
|
|
||||||
static std::map<std::string, std::pair<std::string, TypeServerSource *>>
|
|
||||||
Instances;
|
|
||||||
|
|
||||||
// The interface to the PDB (if it was opened successfully)
|
|
||||||
std::unique_ptr<llvm::pdb::NativeSession> Session;
|
|
||||||
|
|
||||||
private:
|
|
||||||
MemoryBufferRef MB;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class represents the debug type stream of an OBJ file that depends on a
|
|
||||||
// PDB type server (see TypeServerSource).
|
|
||||||
class UseTypeServerSource : public TpiSource {
|
class UseTypeServerSource : public TpiSource {
|
||||||
public:
|
public:
|
||||||
UseTypeServerSource(const ObjFile *F, const TypeServer2Record *TS)
|
UseTypeServerSource(ObjFile *F, TypeServer2Record *TS)
|
||||||
: TpiSource(UsingPDB, F), TypeServerDependency(*TS) {}
|
: TpiSource(UsingPDB, F), TypeServerDependency(*TS) {}
|
||||||
|
|
||||||
// Information about the PDB type server dependency, that needs to be loaded
|
// Information about the PDB type server dependency, that needs to be loaded
|
||||||
|
@ -68,20 +31,14 @@ public:
|
||||||
TypeServer2Record TypeServerDependency;
|
TypeServer2Record TypeServerDependency;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class represents the debug type stream of a Microsoft precompiled
|
|
||||||
// headers OBJ (PCH OBJ). This OBJ kind needs to be merged first in the output
|
|
||||||
// PDB, before any other OBJs that depend on this. Note that only MSVC generate
|
|
||||||
// such files, clang does not.
|
|
||||||
class PrecompSource : public TpiSource {
|
class PrecompSource : public TpiSource {
|
||||||
public:
|
public:
|
||||||
PrecompSource(const ObjFile *F) : TpiSource(PCH, F) {}
|
PrecompSource(ObjFile *F) : TpiSource(PCH, F) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class represents the debug type stream of an OBJ file that depends on a
|
|
||||||
// Microsoft precompiled headers OBJ (see PrecompSource).
|
|
||||||
class UsePrecompSource : public TpiSource {
|
class UsePrecompSource : public TpiSource {
|
||||||
public:
|
public:
|
||||||
UsePrecompSource(const ObjFile *F, const PrecompRecord *Precomp)
|
UsePrecompSource(ObjFile *F, PrecompRecord *Precomp)
|
||||||
: TpiSource(UsingPCH, F), PrecompDependency(*Precomp) {}
|
: TpiSource(UsingPCH, F), PrecompDependency(*Precomp) {}
|
||||||
|
|
||||||
// Information about the Precomp OBJ dependency, that needs to be loaded in
|
// Information about the Precomp OBJ dependency, that needs to be loaded in
|
||||||
|
@ -92,176 +49,40 @@ public:
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<TpiSource>> GC;
|
static std::vector<std::unique_ptr<TpiSource>> GC;
|
||||||
|
|
||||||
TpiSource::TpiSource(TpiKind K, const ObjFile *F) : Kind(K), File(F) {
|
TpiSource::TpiSource(TpiKind K, ObjFile *F) : Kind(K), File(F) {
|
||||||
GC.push_back(std::unique_ptr<TpiSource>(this));
|
GC.push_back(std::unique_ptr<TpiSource>(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
TpiSource *lld::coff::makeTpiSource(const ObjFile *F) {
|
TpiSource *coff::makeTpiSource(ObjFile *F) {
|
||||||
return new TpiSource(TpiSource::Regular, F);
|
return new TpiSource(TpiSource::Regular, F);
|
||||||
}
|
}
|
||||||
|
|
||||||
TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *F,
|
TpiSource *coff::makeTypeServerSource(ObjFile *F) {
|
||||||
const TypeServer2Record *TS) {
|
return new TypeServerSource(F);
|
||||||
TypeServerSource::enqueue(F, *TS);
|
}
|
||||||
|
|
||||||
|
TpiSource *coff::makeUseTypeServerSource(ObjFile *F, TypeServer2Record *TS) {
|
||||||
return new UseTypeServerSource(F, TS);
|
return new UseTypeServerSource(F, TS);
|
||||||
}
|
}
|
||||||
|
|
||||||
TpiSource *lld::coff::makePrecompSource(const ObjFile *F) {
|
TpiSource *coff::makePrecompSource(ObjFile *F) { return new PrecompSource(F); }
|
||||||
return new PrecompSource(F);
|
|
||||||
}
|
|
||||||
|
|
||||||
TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *F,
|
TpiSource *coff::makeUsePrecompSource(ObjFile *F, PrecompRecord *Precomp) {
|
||||||
const PrecompRecord *Precomp) {
|
|
||||||
return new UsePrecompSource(F, Precomp);
|
return new UsePrecompSource(F, Precomp);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
namespace coff {
|
namespace coff {
|
||||||
template <>
|
template <>
|
||||||
const PrecompRecord &retrieveDependencyInfo(const TpiSource *Source) {
|
const PrecompRecord &retrieveDependencyInfo(TpiSource *Source) {
|
||||||
assert(Source->Kind == TpiSource::UsingPCH);
|
assert(Source->Kind == TpiSource::UsingPCH);
|
||||||
return ((const UsePrecompSource *)Source)->PrecompDependency;
|
return ((UsePrecompSource *)Source)->PrecompDependency;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
const TypeServer2Record &retrieveDependencyInfo(const TpiSource *Source) {
|
const TypeServer2Record &retrieveDependencyInfo(TpiSource *Source) {
|
||||||
assert(Source->Kind == TpiSource::UsingPDB);
|
assert(Source->Kind == TpiSource::UsingPDB);
|
||||||
return ((const UseTypeServerSource *)Source)->TypeServerDependency;
|
return ((UseTypeServerSource *)Source)->TypeServerDependency;
|
||||||
}
|
}
|
||||||
} // namespace coff
|
} // namespace coff
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
||||||
std::map<std::string, std::pair<std::string, TypeServerSource *>>
|
|
||||||
TypeServerSource::Instances;
|
|
||||||
|
|
||||||
// Make a PDB path assuming the PDB is in the same folder as the OBJ
|
|
||||||
static std::string getPdbBaseName(const ObjFile *File, StringRef TSPath) {
|
|
||||||
StringRef LocalPath =
|
|
||||||
!File->ParentName.empty() ? File->ParentName : File->getName();
|
|
||||||
std::string Path = sys::path::parent_path(LocalPath);
|
|
||||||
|
|
||||||
// Currently, type server PDBs are only created by MSVC cl, which only runs
|
|
||||||
// on Windows, so we can assume type server paths are Windows style.
|
|
||||||
return Path + sys::path::filename(TSPath, sys::path::Style::windows).str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The casing of the PDB path stamped in the OBJ can differ from the actual path
|
|
||||||
// on disk. With this, we ensure to always use lowercase as a key for the
|
|
||||||
// PDBInputFile::Instances map, at least on Windows.
|
|
||||||
static std::string normalizePdbPath(StringRef path) {
|
|
||||||
#if defined(_WIN32)
|
|
||||||
return path.lower();
|
|
||||||
#else // LINUX
|
|
||||||
return path;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// If existing, return the actual PDB path on disk.
|
|
||||||
static Optional<std::string> findPdbPath(StringRef PDBPath,
|
|
||||||
const ObjFile *DependentFile) {
|
|
||||||
// Ensure the file exists before anything else. In some cases, if the path
|
|
||||||
// points to a removable device, Driver::enqueuePath() would fail with an
|
|
||||||
// error (EAGAIN, "resource unavailable try again") which we want to skip
|
|
||||||
// silently.
|
|
||||||
if (llvm::sys::fs::exists(PDBPath))
|
|
||||||
return normalizePdbPath(PDBPath);
|
|
||||||
std::string Ret = getPdbBaseName(DependentFile, PDBPath);
|
|
||||||
if (llvm::sys::fs::exists(Ret))
|
|
||||||
return normalizePdbPath(Ret);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the PDB instance that was already loaded by the COFF Driver.
|
|
||||||
Expected<TypeServerSource *>
|
|
||||||
TypeServerSource::findFromFile(const ObjFile *DependentFile) {
|
|
||||||
const TypeServer2Record &TS =
|
|
||||||
retrieveDependencyInfo<TypeServer2Record>(DependentFile->DebugTypesObj);
|
|
||||||
|
|
||||||
Optional<std::string> P = findPdbPath(TS.Name, DependentFile);
|
|
||||||
if (!P)
|
|
||||||
return createFileError(TS.Name, errorCodeToError(std::error_code(
|
|
||||||
ENOENT, std::generic_category())));
|
|
||||||
|
|
||||||
auto It = TypeServerSource::Instances.find(*P);
|
|
||||||
// The PDB file exists on disk, at this point we expect it to have been
|
|
||||||
// inserted in the map by TypeServerSource::loadPDB()
|
|
||||||
assert(It != TypeServerSource::Instances.end());
|
|
||||||
|
|
||||||
std::pair<std::string, TypeServerSource *> &PDB = It->second;
|
|
||||||
|
|
||||||
if (!PDB.second)
|
|
||||||
return createFileError(
|
|
||||||
*P, createStringError(inconvertibleErrorCode(), PDB.first.c_str()));
|
|
||||||
|
|
||||||
pdb::PDBFile &PDBFile = (PDB.second)->Session->getPDBFile();
|
|
||||||
pdb::InfoStream &Info = cantFail(PDBFile.getPDBInfoStream());
|
|
||||||
|
|
||||||
// Just because a file with a matching name was found doesn't mean it can be
|
|
||||||
// used. The GUID and Age must match between the PDB header and the OBJ
|
|
||||||
// TypeServer2 record. The 'Age' is used by MSVC incremental compilation.
|
|
||||||
if (Info.getGuid() != TS.getGuid() || Info.getAge() != TS.getAge())
|
|
||||||
return createFileError(
|
|
||||||
TS.Name,
|
|
||||||
make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
|
|
||||||
|
|
||||||
return PDB.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is
|
|
||||||
// moved here.
|
|
||||||
Expected<llvm::pdb::NativeSession *>
|
|
||||||
lld::coff::findTypeServerSource(const ObjFile *F) {
|
|
||||||
Expected<TypeServerSource *> TS = TypeServerSource::findFromFile(F);
|
|
||||||
if (!TS)
|
|
||||||
return TS.takeError();
|
|
||||||
return TS.get()->Session.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Queue a PDB type server for loading in the COFF Driver
|
|
||||||
void TypeServerSource::enqueue(const ObjFile *DependentFile,
|
|
||||||
const TypeServer2Record &TS) {
|
|
||||||
// Start by finding where the PDB is located (either the record path or next
|
|
||||||
// to the OBJ file)
|
|
||||||
Optional<std::string> P = findPdbPath(TS.Name, DependentFile);
|
|
||||||
if (!P)
|
|
||||||
return;
|
|
||||||
auto It = TypeServerSource::Instances.emplace(
|
|
||||||
*P, std::pair<std::string, TypeServerSource *>{});
|
|
||||||
if (!It.second)
|
|
||||||
return; // another OBJ already scheduled this PDB for load
|
|
||||||
|
|
||||||
Driver->enqueuePath(*P, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an instance of TypeServerSource or an error string if the PDB couldn't
|
|
||||||
// be loaded. The error message will be displayed later, when the referring OBJ
|
|
||||||
// will be merged in. NOTE - a PDB load failure is not a link error: some
|
|
||||||
// debug info will simply be missing from the final PDB - that is the default
|
|
||||||
// accepted behavior.
|
|
||||||
void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef M) {
|
|
||||||
std::string Path = normalizePdbPath(M.getBufferIdentifier());
|
|
||||||
|
|
||||||
Expected<TypeServerSource *> TS = TypeServerSource::getInstance(M);
|
|
||||||
if (!TS)
|
|
||||||
TypeServerSource::Instances[Path] = {toString(TS.takeError()), nullptr};
|
|
||||||
else
|
|
||||||
TypeServerSource::Instances[Path] = {{}, *TS};
|
|
||||||
}
|
|
||||||
|
|
||||||
Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef M) {
|
|
||||||
std::unique_ptr<llvm::pdb::IPDBSession> ISession;
|
|
||||||
Error Err = pdb::NativeSession::createFromPdb(
|
|
||||||
MemoryBuffer::getMemBuffer(M, false), ISession);
|
|
||||||
if (Err)
|
|
||||||
return std::move(Err);
|
|
||||||
|
|
||||||
std::unique_ptr<llvm::pdb::NativeSession> Session(
|
|
||||||
static_cast<pdb::NativeSession *>(ISession.release()));
|
|
||||||
|
|
||||||
pdb::PDBFile &PDBFile = Session->getPDBFile();
|
|
||||||
Expected<pdb::InfoStream &> Info = PDBFile.getPDBInfoStream();
|
|
||||||
// All PDB Files should have an Info stream.
|
|
||||||
if (!Info)
|
|
||||||
return Info.takeError();
|
|
||||||
return new TypeServerSource(M, Session.release());
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,16 +10,12 @@
|
||||||
#define LLD_COFF_DEBUGTYPES_H
|
#define LLD_COFF_DEBUGTYPES_H
|
||||||
|
|
||||||
#include "llvm/Support/Error.h"
|
#include "llvm/Support/Error.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
class PrecompRecord;
|
class PrecompRecord;
|
||||||
class TypeServer2Record;
|
class TypeServer2Record;
|
||||||
} // namespace codeview
|
} // namespace codeview
|
||||||
namespace pdb {
|
|
||||||
class NativeSession;
|
|
||||||
}
|
|
||||||
} // namespace llvm
|
} // namespace llvm
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
|
@ -31,28 +27,23 @@ class TpiSource {
|
||||||
public:
|
public:
|
||||||
enum TpiKind { Regular, PCH, UsingPCH, PDB, UsingPDB };
|
enum TpiKind { Regular, PCH, UsingPCH, PDB, UsingPDB };
|
||||||
|
|
||||||
TpiSource(TpiKind K, const ObjFile *F);
|
TpiSource(TpiKind K, ObjFile *F);
|
||||||
virtual ~TpiSource() {}
|
virtual ~TpiSource() {}
|
||||||
|
|
||||||
const TpiKind Kind;
|
const TpiKind Kind;
|
||||||
const ObjFile *File;
|
ObjFile *File;
|
||||||
};
|
};
|
||||||
|
|
||||||
TpiSource *makeTpiSource(const ObjFile *F);
|
TpiSource *makeTpiSource(ObjFile *F);
|
||||||
TpiSource *makeUseTypeServerSource(const ObjFile *F,
|
TpiSource *makeTypeServerSource(ObjFile *F);
|
||||||
const llvm::codeview::TypeServer2Record *TS);
|
TpiSource *makeUseTypeServerSource(ObjFile *F,
|
||||||
TpiSource *makePrecompSource(const ObjFile *F);
|
llvm::codeview::TypeServer2Record *TS);
|
||||||
TpiSource *makeUsePrecompSource(const ObjFile *F,
|
TpiSource *makePrecompSource(ObjFile *F);
|
||||||
const llvm::codeview::PrecompRecord *Precomp);
|
TpiSource *makeUsePrecompSource(ObjFile *F,
|
||||||
|
llvm::codeview::PrecompRecord *Precomp);
|
||||||
void loadTypeServerSource(llvm::MemoryBufferRef M);
|
|
||||||
|
|
||||||
// Temporary interface to get the dependency
|
// Temporary interface to get the dependency
|
||||||
template <typename T> const T &retrieveDependencyInfo(const TpiSource *Source);
|
template <typename T> const T &retrieveDependencyInfo(TpiSource *Source);
|
||||||
|
|
||||||
// Temporary interface until we move PDBLinker::maybeMergeTypeServerPDB here
|
|
||||||
llvm::Expected<llvm::pdb::NativeSession *>
|
|
||||||
findTypeServerSource(const ObjFile *F);
|
|
||||||
|
|
||||||
} // namespace coff
|
} // namespace coff
|
||||||
} // namespace lld
|
} // namespace lld
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "DebugTypes.h"
|
|
||||||
#include "Driver.h"
|
#include "Driver.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "ICF.h"
|
#include "ICF.h"
|
||||||
|
@ -182,9 +181,6 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB,
|
||||||
case file_magic::coff_import_library:
|
case file_magic::coff_import_library:
|
||||||
Symtab->addFile(make<ObjFile>(MBRef));
|
Symtab->addFile(make<ObjFile>(MBRef));
|
||||||
break;
|
break;
|
||||||
case file_magic::pdb:
|
|
||||||
loadTypeServerSource(MBRef);
|
|
||||||
break;
|
|
||||||
case file_magic::coff_cl_gl_object:
|
case file_magic::coff_cl_gl_object:
|
||||||
error(Filename + ": is not a native COFF file. Recompile without /GL");
|
error(Filename + ": is not a native COFF file. Recompile without /GL");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -77,8 +77,6 @@ public:
|
||||||
|
|
||||||
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
|
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
|
||||||
|
|
||||||
void enqueuePath(StringRef Path, bool WholeArchive);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<llvm::TarWriter> Tar; // for /linkrepro
|
std::unique_ptr<llvm::TarWriter> Tar; // for /linkrepro
|
||||||
|
|
||||||
|
@ -122,6 +120,8 @@ private:
|
||||||
void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
|
void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
|
||||||
StringRef ParentName, uint64_t OffsetInArchive);
|
StringRef ParentName, uint64_t OffsetInArchive);
|
||||||
|
|
||||||
|
void enqueuePath(StringRef Path, bool WholeArchive);
|
||||||
|
|
||||||
void enqueueTask(std::function<void()> Task);
|
void enqueueTask(std::function<void()> Task);
|
||||||
bool run();
|
bool run();
|
||||||
|
|
||||||
|
|
120
lld/COFF/PDB.cpp
120
lld/COFF/PDB.cpp
|
@ -175,6 +175,11 @@ private:
|
||||||
|
|
||||||
llvm::SmallString<128> NativePath;
|
llvm::SmallString<128> NativePath;
|
||||||
|
|
||||||
|
/// A list of other PDBs which are loaded during the linking process and which
|
||||||
|
/// we need to keep around since the linking operation may reference pointers
|
||||||
|
/// inside of these PDBs.
|
||||||
|
llvm::SmallVector<std::unique_ptr<pdb::NativeSession>, 2> LoadedPDBs;
|
||||||
|
|
||||||
std::vector<pdb::SecMapEntry> SectionMap;
|
std::vector<pdb::SecMapEntry> SectionMap;
|
||||||
|
|
||||||
/// Type index mappings of type server PDBs that we've loaded so far.
|
/// Type index mappings of type server PDBs that we've loaded so far.
|
||||||
|
@ -184,6 +189,10 @@ private:
|
||||||
/// far.
|
/// far.
|
||||||
std::map<uint32_t, CVIndexMap> PrecompTypeIndexMappings;
|
std::map<uint32_t, CVIndexMap> PrecompTypeIndexMappings;
|
||||||
|
|
||||||
|
/// List of TypeServer PDBs which cannot be loaded.
|
||||||
|
/// Cached to prevent repeated load attempts.
|
||||||
|
std::map<codeview::GUID, std::string> MissingTypeServerPDBs;
|
||||||
|
|
||||||
// For statistics
|
// For statistics
|
||||||
uint64_t GlobalSymbols = 0;
|
uint64_t GlobalSymbols = 0;
|
||||||
uint64_t ModuleSymbols = 0;
|
uint64_t ModuleSymbols = 0;
|
||||||
|
@ -407,26 +416,115 @@ PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) {
|
||||||
return *ObjectIndexMap;
|
return *ObjectIndexMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Expected<std::unique_ptr<pdb::NativeSession>>
|
||||||
|
tryToLoadPDB(const codeview::GUID &GuidFromObj, StringRef TSPath) {
|
||||||
|
// Ensure the file exists before anything else. We want to return ENOENT,
|
||||||
|
// "file not found", even if the path points to a removable device (in which
|
||||||
|
// case the return message would be EAGAIN, "resource unavailable try again")
|
||||||
|
if (!llvm::sys::fs::exists(TSPath))
|
||||||
|
return errorCodeToError(std::error_code(ENOENT, std::generic_category()));
|
||||||
|
|
||||||
|
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFile(
|
||||||
|
TSPath, /*FileSize=*/-1, /*RequiresNullTerminator=*/false);
|
||||||
|
if (!MBOrErr)
|
||||||
|
return errorCodeToError(MBOrErr.getError());
|
||||||
|
|
||||||
|
std::unique_ptr<pdb::IPDBSession> ThisSession;
|
||||||
|
if (auto EC = pdb::NativeSession::createFromPdb(
|
||||||
|
MemoryBuffer::getMemBuffer(Driver->takeBuffer(std::move(*MBOrErr)),
|
||||||
|
/*RequiresNullTerminator=*/false),
|
||||||
|
ThisSession))
|
||||||
|
return std::move(EC);
|
||||||
|
|
||||||
|
std::unique_ptr<pdb::NativeSession> NS(
|
||||||
|
static_cast<pdb::NativeSession *>(ThisSession.release()));
|
||||||
|
pdb::PDBFile &File = NS->getPDBFile();
|
||||||
|
auto ExpectedInfo = File.getPDBInfoStream();
|
||||||
|
// All PDB Files should have an Info stream.
|
||||||
|
if (!ExpectedInfo)
|
||||||
|
return ExpectedInfo.takeError();
|
||||||
|
|
||||||
|
// Just because a file with a matching name was found and it was an actual
|
||||||
|
// PDB file doesn't mean it matches. For it to match the InfoStream's GUID
|
||||||
|
// must match the GUID specified in the TypeServer2 record.
|
||||||
|
if (ExpectedInfo->getGuid() != GuidFromObj)
|
||||||
|
return make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date);
|
||||||
|
|
||||||
|
return std::move(NS);
|
||||||
|
}
|
||||||
|
|
||||||
Expected<const CVIndexMap &> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File) {
|
Expected<const CVIndexMap &> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File) {
|
||||||
Expected<llvm::pdb::NativeSession *> PDBSession = findTypeServerSource(File);
|
const TypeServer2Record &TS =
|
||||||
if (!PDBSession)
|
retrieveDependencyInfo<TypeServer2Record>(File->DebugTypesObj);
|
||||||
return PDBSession.takeError();
|
|
||||||
|
|
||||||
pdb::PDBFile &PDBFile = PDBSession.get()->getPDBFile();
|
const codeview::GUID &TSId = TS.getGuid();
|
||||||
pdb::InfoStream &Info = cantFail(PDBFile.getPDBInfoStream());
|
StringRef TSPath = TS.getName();
|
||||||
|
|
||||||
auto It = TypeServerIndexMappings.emplace(Info.getGuid(), CVIndexMap());
|
// First, check if the PDB has previously failed to load.
|
||||||
CVIndexMap &IndexMap = It.first->second;
|
auto PrevErr = MissingTypeServerPDBs.find(TSId);
|
||||||
if (!It.second)
|
if (PrevErr != MissingTypeServerPDBs.end())
|
||||||
return IndexMap; // already merged
|
return createFileError(
|
||||||
|
TSPath,
|
||||||
|
make_error<StringError>(PrevErr->second, inconvertibleErrorCode()));
|
||||||
|
|
||||||
|
// Second, check if we already loaded a PDB with this GUID. Return the type
|
||||||
|
// index mapping if we have it.
|
||||||
|
auto Insertion = TypeServerIndexMappings.insert({TSId, CVIndexMap()});
|
||||||
|
CVIndexMap &IndexMap = Insertion.first->second;
|
||||||
|
if (!Insertion.second)
|
||||||
|
return IndexMap;
|
||||||
|
|
||||||
// Mark this map as a type server map.
|
// Mark this map as a type server map.
|
||||||
IndexMap.IsTypeServerMap = true;
|
IndexMap.IsTypeServerMap = true;
|
||||||
|
|
||||||
Expected<pdb::TpiStream &> ExpectedTpi = PDBFile.getPDBTpiStream();
|
// Check for a PDB at:
|
||||||
|
// 1. The given file path
|
||||||
|
// 2. Next to the object file or archive file
|
||||||
|
auto ExpectedSession = handleExpected(
|
||||||
|
tryToLoadPDB(TSId, TSPath),
|
||||||
|
[&]() {
|
||||||
|
StringRef LocalPath =
|
||||||
|
!File->ParentName.empty() ? File->ParentName : File->getName();
|
||||||
|
SmallString<128> Path = sys::path::parent_path(LocalPath);
|
||||||
|
// Currently, type server PDBs are only created by cl, which only runs
|
||||||
|
// on Windows, so we can assume type server paths are Windows style.
|
||||||
|
sys::path::append(
|
||||||
|
Path, sys::path::filename(TSPath, sys::path::Style::windows));
|
||||||
|
return tryToLoadPDB(TSId, Path);
|
||||||
|
},
|
||||||
|
[&](std::unique_ptr<ECError> EC) -> Error {
|
||||||
|
auto SysErr = EC->convertToErrorCode();
|
||||||
|
// Only re-try loading if the previous error was "No such file or
|
||||||
|
// directory"
|
||||||
|
if (SysErr.category() == std::generic_category() &&
|
||||||
|
SysErr.value() == ENOENT)
|
||||||
|
return Error::success();
|
||||||
|
return Error(std::move(EC));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (auto E = ExpectedSession.takeError()) {
|
||||||
|
TypeServerIndexMappings.erase(TSId);
|
||||||
|
|
||||||
|
// Flatten the error to a string, for later display, if the error occurs
|
||||||
|
// again on the same PDB.
|
||||||
|
std::string ErrMsg;
|
||||||
|
raw_string_ostream S(ErrMsg);
|
||||||
|
S << E;
|
||||||
|
MissingTypeServerPDBs.emplace(TSId, S.str());
|
||||||
|
|
||||||
|
return createFileError(TSPath, std::move(E));
|
||||||
|
}
|
||||||
|
|
||||||
|
pdb::NativeSession *Session = ExpectedSession->get();
|
||||||
|
|
||||||
|
// Keep a strong reference to this PDB, so that it's safe to hold pointers
|
||||||
|
// into the file.
|
||||||
|
LoadedPDBs.push_back(std::move(*ExpectedSession));
|
||||||
|
|
||||||
|
auto ExpectedTpi = Session->getPDBFile().getPDBTpiStream();
|
||||||
if (auto E = ExpectedTpi.takeError())
|
if (auto E = ExpectedTpi.takeError())
|
||||||
fatal("Type server does not have TPI stream: " + toString(std::move(E)));
|
fatal("Type server does not have TPI stream: " + toString(std::move(E)));
|
||||||
Expected<pdb::TpiStream &> ExpectedIpi = PDBFile.getPDBIpiStream();
|
auto ExpectedIpi = Session->getPDBFile().getPDBIpiStream();
|
||||||
if (auto E = ExpectedIpi.takeError())
|
if (auto E = ExpectedIpi.takeError())
|
||||||
fatal("Type server does not have TPI stream: " + toString(std::move(E)));
|
fatal("Type server does not have TPI stream: " + toString(std::move(E)));
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ sections:
|
||||||
- Kind: LF_TYPESERVER2
|
- Kind: LF_TYPESERVER2
|
||||||
TypeServer2:
|
TypeServer2:
|
||||||
Guid: '{8DABD2A0-28FF-CB43-9BAF-175B77B76414}'
|
Guid: '{8DABD2A0-28FF-CB43-9BAF-175B77B76414}'
|
||||||
Age: 1
|
Age: 18
|
||||||
Name: 'pdb-diff-cl.pdb'
|
Name: 'pdb-diff-cl.pdb'
|
||||||
- Name: '.text$mn'
|
- Name: '.text$mn'
|
||||||
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s
|
# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s
|
||||||
# RUN: cd %S
|
# RUN: cd %S
|
||||||
|
|
||||||
# CHECK: warning: Cannot use debug info for '{{.*}}.obj'
|
# CHECK: warning: Cannot use debug info for {{.*}}.obj
|
||||||
# CHECK-NEXT: The signature does not match; the file(s) might be out of date
|
# CHECK-NEXT: The signature does not match; the file(s) might be out of date
|
||||||
|
|
||||||
# Also test a valid match
|
# Also test a valid match
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
# RUN: lld-link %t2.obj -out:%t2.exe -debug -pdb:%t2.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s -check-prefix=VALID-SIGNATURE -allow-empty
|
# RUN: lld-link %t2.obj -out:%t2.exe -debug -pdb:%t2.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s -check-prefix=VALID-SIGNATURE -allow-empty
|
||||||
# RUN: cd %S
|
# RUN: cd %S
|
||||||
|
|
||||||
# VALID-SIGNATURE-NOT: warning: Cannot use debug info for '{{.*}}.obj'
|
# VALID-SIGNATURE-NOT: warning: Cannot use debug info for {{.*}}.obj
|
||||||
# VALID-SIGNATURE-NOT: The signature does not match; the file(s) might be out of date
|
# VALID-SIGNATURE-NOT: The signature does not match; the file(s) might be out of date
|
||||||
|
|
||||||
--- !COFF
|
--- !COFF
|
||||||
|
|
Loading…
Reference in New Issue