]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r302418, and update
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / DebugInfo / PDB / Native / PDBTypeServerHandler.cpp
1 //===- PDBTypeServerHandler.cpp ---------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
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.
12 //
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 //===----------------------------------------------------------------------===//
21
22 #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
23
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"
33
34 using namespace llvm;
35 using namespace llvm::codeview;
36 using namespace llvm::pdb;
37
38 static void ignoreErrors(Error EC) {
39   llvm::handleAllErrors(std::move(EC), [&](ErrorInfoBase &EIB) {});
40 }
41
42 PDBTypeServerHandler::PDBTypeServerHandler(bool RevisitAlways)
43     : RevisitAlways(RevisitAlways) {}
44
45 void PDBTypeServerHandler::addSearchPath(StringRef Path) {
46   if (Path.empty() || !sys::fs::is_directory(Path))
47     return;
48
49   SearchPaths.push_back(Path);
50 }
51
52 Expected<bool>
53 PDBTypeServerHandler::handleInternal(PDBFile &File,
54                                      TypeVisitorCallbacks &Callbacks) {
55   auto ExpectedTpi = File.getPDBTpiStream();
56   if (!ExpectedTpi)
57     return ExpectedTpi.takeError();
58   CVTypeVisitor Visitor(Callbacks);
59
60   if (auto EC = Visitor.visitTypeStream(ExpectedTpi->types(nullptr)))
61     return std::move(EC);
62
63   return true;
64 }
65
66 Expected<bool> PDBTypeServerHandler::handle(TypeServer2Record &TS,
67                                             TypeVisitorCallbacks &Callbacks) {
68   if (Session) {
69     // If we've already handled this TypeServer and we only want to handle each
70     // TypeServer once, consume the record without doing anything.
71     if (!RevisitAlways)
72       return true;
73
74     return handleInternal(Session->getPDBFile(), Callbacks);
75   }
76
77   StringRef File = sys::path::filename(TS.Name);
78   if (File.empty())
79     return make_error<CodeViewError>(
80         cv_error_code::corrupt_record,
81         "TypeServer2Record does not contain filename!");
82
83   for (auto Path : SearchPaths) {
84     sys::path::append(Path, File);
85     if (!sys::fs::exists(Path))
86       continue;
87
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));
93       continue;
94     }
95
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.
101     if (!ExpectedInfo)
102       return ExpectedInfo.takeError();
103
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()),
109                       GuidBytes.size());
110     if (GuidStr != TS.Guid)
111       continue;
112
113     Session = std::move(NS);
114     return handleInternal(File, Callbacks);
115   }
116
117   // We couldn't find a matching PDB, so let it be handled by someone else.
118   return false;
119 }