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