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