1 //===- DIASession.cpp - DIA implementation of IPDBSession -------*- 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 
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"
12 #include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h"
13 #include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h"
14 #include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"
15 #include "llvm/DebugInfo/PDB/DIA/DIASession.h"
16 #include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
17 #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
18 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
19 #include "llvm/Support/ConvertUTF.h"
20 
21 #include <diacreate.h>
22 
23 using namespace llvm;
24 
25 namespace {
26 
27 PDB_ErrorCode LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) {
28   if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER,
29                                  IID_IDiaDataSource,
30                                  reinterpret_cast<LPVOID *>(&DiaDataSource))))
31     return PDB_ErrorCode::Success;
32 
33   // If the CoCreateInstance call above failed, msdia*.dll is not registered.
34   // Try loading the DLL corresponding to the #included DIA SDK.
35 #if !defined(_MSC_VER)
36   return PDB_ErrorCode::NoDiaSupport;
37 #endif
38 
39   const wchar_t *msdia_dll = nullptr;
40 #if _MSC_VER == 1900
41   msdia_dll = L"msdia140.dll"; // VS2015
42 #elif _MSC_VER == 1800
43   msdia_dll = L"msdia120.dll"; // VS2013
44 #else
45 #error "Unknown Visual Studio version."
46 #endif
47 
48   if (SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,
49                               reinterpret_cast<LPVOID *>(&DiaDataSource))))
50     return PDB_ErrorCode::Success;
51   else
52     return PDB_ErrorCode::CouldNotCreateImpl;
53 }
54 
55 }
56 
57 DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {}
58 
59 PDB_ErrorCode DIASession::createFromPdb(StringRef Path,
60                                         std::unique_ptr<IPDBSession> &Session) {
61   CComPtr<IDiaDataSource> DiaDataSource;
62   CComPtr<IDiaSession> DiaSession;
63 
64   // We assume that CoInitializeEx has already been called by the executable.
65   PDB_ErrorCode result = LoadDIA(DiaDataSource);
66   if (result != PDB_ErrorCode::Success)
67     return result;
68 
69   llvm::SmallVector<UTF16, 128> Path16;
70   if (!llvm::convertUTF8ToUTF16String(Path, Path16))
71     return PDB_ErrorCode::InvalidPath;
72 
73   const wchar_t *Path16Str = reinterpret_cast<const wchar_t*>(Path16.data());
74   HRESULT Result;
75   if (FAILED(Result = DiaDataSource->loadDataFromPdb(Path16Str))) {
76     if (Result == E_PDB_NOT_FOUND)
77       return PDB_ErrorCode::InvalidPath;
78     else if (Result == E_PDB_FORMAT)
79       return PDB_ErrorCode::InvalidFileFormat;
80     else if (Result == E_INVALIDARG)
81       return PDB_ErrorCode::InvalidParameter;
82     else if (Result == E_UNEXPECTED)
83       return PDB_ErrorCode::AlreadyLoaded;
84     else
85       return PDB_ErrorCode::UnknownError;
86   }
87 
88   if (FAILED(Result = DiaDataSource->openSession(&DiaSession))) {
89     if (Result == E_OUTOFMEMORY)
90       return PDB_ErrorCode::NoMemory;
91     else
92       return PDB_ErrorCode::UnknownError;
93   }
94 
95   Session.reset(new DIASession(DiaSession));
96   return PDB_ErrorCode::Success;
97 }
98 
99 PDB_ErrorCode DIASession::createFromExe(StringRef Path,
100                                         std::unique_ptr<IPDBSession> &Session) {
101   CComPtr<IDiaDataSource> DiaDataSource;
102   CComPtr<IDiaSession> DiaSession;
103 
104   // We assume that CoInitializeEx has already been called by the executable.
105   PDB_ErrorCode result = LoadDIA(DiaDataSource);
106   if (result != PDB_ErrorCode::Success)
107     return result;
108 
109   llvm::SmallVector<UTF16, 128> Path16;
110   if (!llvm::convertUTF8ToUTF16String(Path, Path16))
111     return PDB_ErrorCode::InvalidPath;
112 
113   const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());
114   HRESULT Result;
115   if (FAILED(Result =
116                  DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr))) {
117     if (Result == E_PDB_NOT_FOUND)
118       return PDB_ErrorCode::InvalidPath;
119     else if (Result == E_PDB_FORMAT)
120       return PDB_ErrorCode::InvalidFileFormat;
121     else if (Result == E_PDB_INVALID_SIG || Result == E_PDB_INVALID_AGE)
122       return PDB_ErrorCode::DebugInfoMismatch;
123     else if (Result == E_INVALIDARG)
124       return PDB_ErrorCode::InvalidParameter;
125     else if (Result == E_UNEXPECTED)
126       return PDB_ErrorCode::AlreadyLoaded;
127     else
128       return PDB_ErrorCode::UnknownError;
129   }
130 
131   if (FAILED(Result = DiaDataSource->openSession(&DiaSession))) {
132     if (Result == E_OUTOFMEMORY)
133       return PDB_ErrorCode::NoMemory;
134     else
135       return PDB_ErrorCode::UnknownError;
136   }
137 
138   Session.reset(new DIASession(DiaSession));
139   return PDB_ErrorCode::Success;
140 }
141 
142 uint64_t DIASession::getLoadAddress() const {
143   uint64_t LoadAddress;
144   bool success = (S_OK == Session->get_loadAddress(&LoadAddress));
145   return (success) ? LoadAddress : 0;
146 }
147 
148 void DIASession::setLoadAddress(uint64_t Address) {
149   Session->put_loadAddress(Address);
150 }
151 
152 std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() const {
153   CComPtr<IDiaSymbol> GlobalScope;
154   if (S_OK != Session->get_globalScope(&GlobalScope))
155     return nullptr;
156 
157   auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, GlobalScope);
158   auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol)));
159   std::unique_ptr<PDBSymbolExe> ExeSymbol(
160       static_cast<PDBSymbolExe *>(PdbSymbol.release()));
161   return ExeSymbol;
162 }
163 
164 std::unique_ptr<PDBSymbol> DIASession::getSymbolById(uint32_t SymbolId) const {
165   CComPtr<IDiaSymbol> LocatedSymbol;
166   if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol))
167     return nullptr;
168 
169   auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, LocatedSymbol);
170   return PDBSymbol::create(*this, std::move(RawSymbol));
171 }
172 
173 std::unique_ptr<PDBSymbol>
174 DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const {
175   enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);
176 
177   CComPtr<IDiaSymbol> Symbol;
178   if (S_OK != Session->findSymbolByVA(Address, EnumVal, &Symbol)) {
179     ULONGLONG LoadAddr = 0;
180     if (S_OK != Session->get_loadAddress(&LoadAddr))
181       return nullptr;
182     DWORD RVA = static_cast<DWORD>(Address - LoadAddr);
183     if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol))
184       return nullptr;
185   }
186   auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, Symbol);
187   return PDBSymbol::create(*this, std::move(RawSymbol));
188 }
189 
190 std::unique_ptr<IPDBEnumLineNumbers>
191 DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland,
192                             const IPDBSourceFile &File) const {
193   const DIARawSymbol &RawCompiland =
194       static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
195   const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File);
196 
197   CComPtr<IDiaEnumLineNumbers> LineNumbers;
198   if (S_OK !=
199       Session->findLines(RawCompiland.getDiaSymbol(), RawFile.getDiaFile(),
200                          &LineNumbers))
201     return nullptr;
202 
203   return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
204 }
205 
206 std::unique_ptr<IPDBEnumLineNumbers>
207 DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {
208   CComPtr<IDiaEnumLineNumbers> LineNumbers;
209   if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers))
210     return nullptr;
211 
212   return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
213 }
214 
215 std::unique_ptr<IPDBEnumSourceFiles>
216 DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland,
217                             llvm::StringRef Pattern,
218                             PDB_NameSearchFlags Flags) const {
219   IDiaSymbol *DiaCompiland = nullptr;
220   CComBSTR Utf16Pattern;
221   if (!Pattern.empty())
222     Utf16Pattern = CComBSTR(Pattern.data());
223 
224   if (Compiland)
225     DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol())
226                        .getDiaSymbol();
227 
228   Flags = static_cast<PDB_NameSearchFlags>(
229       Flags | PDB_NameSearchFlags::NS_FileNameExtMatch);
230   CComPtr<IDiaEnumSourceFiles> SourceFiles;
231   if (S_OK !=
232       Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles))
233     return nullptr;
234   return llvm::make_unique<DIAEnumSourceFiles>(*this, SourceFiles);
235 }
236 
237 std::unique_ptr<IPDBSourceFile>
238 DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
239                               llvm::StringRef Pattern,
240                               PDB_NameSearchFlags Flags) const {
241   auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags);
242   if (!SourceFiles || SourceFiles->getChildCount() == 0)
243     return nullptr;
244   return SourceFiles->getNext();
245 }
246 
247 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
248 DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern,
249                                         PDB_NameSearchFlags Flags) const {
250   auto File = findOneSourceFile(nullptr, Pattern, Flags);
251   if (!File)
252     return nullptr;
253   return File->getCompilands();
254 }
255 
256 std::unique_ptr<PDBSymbolCompiland>
257 DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern,
258                                           PDB_NameSearchFlags Flags) const {
259   auto Compilands = findCompilandsForSourceFile(Pattern, Flags);
260   if (!Compilands || Compilands->getChildCount() == 0)
261     return nullptr;
262   return Compilands->getNext();
263 }
264 
265 std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const {
266   CComPtr<IDiaEnumSourceFiles> Files;
267   if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files))
268     return nullptr;
269 
270   return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
271 }
272 
273 std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland(
274     const PDBSymbolCompiland &Compiland) const {
275   CComPtr<IDiaEnumSourceFiles> Files;
276 
277   const DIARawSymbol &RawSymbol =
278       static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
279   if (S_OK !=
280       Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files))
281     return nullptr;
282 
283   return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
284 }
285 
286 std::unique_ptr<IPDBSourceFile>
287 DIASession::getSourceFileById(uint32_t FileId) const {
288   CComPtr<IDiaSourceFile> LocatedFile;
289   if (S_OK != Session->findFileById(FileId, &LocatedFile))
290     return nullptr;
291 
292   return llvm::make_unique<DIASourceFile>(*this, LocatedFile);
293 }
294 
295 std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const {
296   CComPtr<IDiaEnumDebugStreams> DiaEnumerator;
297   if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator))
298     return nullptr;
299 
300   return llvm::make_unique<DIAEnumDebugStreams>(DiaEnumerator);
301 }
302