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 
DIASession(CComPtr<IDiaSession> DiaSession)25 DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {}
26 
createFromPdb(StringRef Path,std::unique_ptr<IPDBSession> & Session)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 
createFromExe(StringRef Path,std::unique_ptr<IPDBSession> & Session)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 
getLoadAddress() const112 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 
setLoadAddress(uint64_t Address)118 void DIASession::setLoadAddress(uint64_t Address) {
119   Session->put_loadAddress(Address);
120 }
121 
getGlobalScope() const122 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 
getSymbolById(uint32_t SymbolId) const134 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>
findSymbolByAddress(uint64_t Address,PDB_SymType Type) const144 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>
findLineNumbersByAddress(uint64_t Address,uint32_t Length) const161 DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {
162   CComPtr<IDiaEnumLineNumbers> LineNumbers;
163   if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers))
164     return nullptr;
165 
166   return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
167 }
168 
getAllSourceFiles() const169 std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const {
170   CComPtr<IDiaEnumSourceFiles> Files;
171   if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files))
172     return nullptr;
173 
174   return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
175 }
176 
getSourceFilesForCompiland(const PDBSymbolCompiland & Compiland) const177 std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland(
178     const PDBSymbolCompiland &Compiland) const {
179   CComPtr<IDiaEnumSourceFiles> Files;
180 
181   const DIARawSymbol &RawSymbol =
182       static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
183   if (S_OK !=
184       Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files))
185     return nullptr;
186 
187   return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
188 }
189 
190 std::unique_ptr<IPDBSourceFile>
getSourceFileById(uint32_t FileId) const191 DIASession::getSourceFileById(uint32_t FileId) const {
192   CComPtr<IDiaSourceFile> LocatedFile;
193   if (S_OK != Session->findFileById(FileId, &LocatedFile))
194     return nullptr;
195 
196   return llvm::make_unique<DIASourceFile>(*this, LocatedFile);
197 }
198 
getDebugStreams() const199 std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const {
200   CComPtr<IDiaEnumDebugStreams> DiaEnumerator;
201   if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator))
202     return nullptr;
203 
204   return llvm::make_unique<DIAEnumDebugStreams>(DiaEnumerator);
205 }
206