1 //===- PDBTypeServerHandler.cpp ---------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 // Handles CodeView LF_TYPESERVER2 records by attempting to locate a matching
10 // PDB file, then loading the PDB file and visiting all types from the
11 // referenced PDB using the original supplied visitor.
13 // The net effect of this is that when visiting a PDB containing a TypeServer
14 // record, the TypeServer record is "replaced" with all of the records in
15 // the referenced PDB file. If a single instance of PDBTypeServerHandler
16 // encounters the same TypeServer multiple times (for example reusing one
17 // PDBTypeServerHandler across multiple visitations of distinct object files or
18 // PDB files), PDBTypeServerHandler will optionally revisit all the records
19 // again, or simply consume the record and do nothing.
20 //===----------------------------------------------------------------------===//
22 #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
24 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
25 #include "llvm/DebugInfo/PDB/GenericError.h"
26 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
27 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
28 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
29 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
30 #include "llvm/DebugInfo/PDB/PDB.h"
31 #include "llvm/Support/FileSystem.h"
32 #include "llvm/Support/Path.h"
35 using namespace llvm::codeview;
36 using namespace llvm::pdb;
38 static void ignoreErrors(Error EC) {
39 llvm::handleAllErrors(std::move(EC), [&](ErrorInfoBase &EIB) {});
42 PDBTypeServerHandler::PDBTypeServerHandler(bool RevisitAlways)
43 : RevisitAlways(RevisitAlways) {}
45 void PDBTypeServerHandler::addSearchPath(StringRef Path) {
46 if (Path.empty() || !sys::fs::is_directory(Path))
49 SearchPaths.push_back(Path);
53 PDBTypeServerHandler::handleInternal(PDBFile &File,
54 TypeVisitorCallbacks &Callbacks) {
55 auto ExpectedTpi = File.getPDBTpiStream();
57 return ExpectedTpi.takeError();
58 CVTypeVisitor Visitor(Callbacks);
60 if (auto EC = Visitor.visitTypeStream(ExpectedTpi->types(nullptr)))
66 Expected<bool> PDBTypeServerHandler::handle(TypeServer2Record &TS,
67 TypeVisitorCallbacks &Callbacks) {
69 // If we've already handled this TypeServer and we only want to handle each
70 // TypeServer once, consume the record without doing anything.
74 return handleInternal(Session->getPDBFile(), Callbacks);
77 StringRef File = sys::path::filename(TS.Name);
79 return make_error<CodeViewError>(
80 cv_error_code::corrupt_record,
81 "TypeServer2Record does not contain filename!");
83 for (auto Path : SearchPaths) {
84 sys::path::append(Path, File);
85 if (!sys::fs::exists(Path))
88 std::unique_ptr<IPDBSession> ThisSession;
89 if (auto EC = loadDataForPDB(PDB_ReaderType::Native, Path, ThisSession)) {
90 // It is not an error if this PDB fails to load, it just means that it
91 // doesn't match and we should continue searching.
92 ignoreErrors(std::move(EC));
96 std::unique_ptr<NativeSession> NS(
97 static_cast<NativeSession *>(ThisSession.release()));
98 PDBFile &File = NS->getPDBFile();
99 auto ExpectedInfo = File.getPDBInfoStream();
100 // All PDB Files should have an Info stream.
102 return ExpectedInfo.takeError();
104 // Just because a file with a matching name was found and it was an actual
105 // PDB file doesn't mean it matches. For it to match the InfoStream's GUID
106 // must match the GUID specified in the TypeServer2 record.
107 ArrayRef<uint8_t> GuidBytes(ExpectedInfo->getGuid().Guid);
108 StringRef GuidStr(reinterpret_cast<const char *>(GuidBytes.begin()),
110 if (GuidStr != TS.Guid)
113 Session = std::move(NS);
114 return handleInternal(File, Callbacks);
117 // We couldn't find a matching PDB, so let it be handled by someone else.