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