1cffff26bSZachary Turner //===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===// 2cffff26bSZachary Turner // 3cffff26bSZachary Turner // The LLVM Compiler Infrastructure 4cffff26bSZachary Turner // 5cffff26bSZachary Turner // This file is distributed under the University of Illinois Open Source 6cffff26bSZachary Turner // License. See LICENSE.TXT for details. 7cffff26bSZachary Turner // 8cffff26bSZachary Turner //===----------------------------------------------------------------------===// 9819e77d1SZachary Turner #include "llvm/DebugInfo/PDB/DIA/DIASession.h" 10be6d1e49SZachary Turner #include "llvm/ADT/STLExtras.h" 11cffff26bSZachary Turner #include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h" 124b08354bSZachary Turner #include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h" 13a5549178SZachary Turner #include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h" 14819e77d1SZachary Turner #include "llvm/DebugInfo/PDB/DIA/DIAError.h" 15cffff26bSZachary Turner #include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h" 16cffff26bSZachary Turner #include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h" 17819e77d1SZachary Turner #include "llvm/DebugInfo/PDB/DIA/DIASupport.h" 18819e77d1SZachary Turner #include "llvm/DebugInfo/PDB/GenericError.h" 19819e77d1SZachary Turner #include "llvm/DebugInfo/PDB/PDB.h" 2071f308adSChandler Carruth #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" 2171f308adSChandler Carruth #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" 22cffff26bSZachary Turner #include "llvm/Support/ConvertUTF.h" 23*38380323SZachary Turner #include "llvm/Support/Format.h" 24*38380323SZachary Turner #include "llvm/Support/raw_ostream.h" 25cffff26bSZachary Turner 26cffff26bSZachary Turner using namespace llvm; 27ec28fc34SZachary Turner using namespace llvm::pdb; 28cffff26bSZachary Turner 29*38380323SZachary Turner static Error ErrorFromHResult(HRESULT Result, StringRef Context) { 30819e77d1SZachary Turner switch (Result) { 31819e77d1SZachary Turner case E_PDB_NOT_FOUND: 32*38380323SZachary Turner return make_error<GenericError>(generic_error_code::invalid_path, Context); 33819e77d1SZachary Turner case E_PDB_FORMAT: 34*38380323SZachary Turner return make_error<DIAError>(dia_error_code::invalid_file_format, Context); 35819e77d1SZachary Turner case E_INVALIDARG: 36*38380323SZachary Turner return make_error<DIAError>(dia_error_code::invalid_parameter, Context); 37819e77d1SZachary Turner case E_UNEXPECTED: 38*38380323SZachary Turner return make_error<DIAError>(dia_error_code::already_loaded, Context); 39819e77d1SZachary Turner case E_PDB_INVALID_SIG: 40819e77d1SZachary Turner case E_PDB_INVALID_AGE: 41*38380323SZachary Turner return make_error<DIAError>(dia_error_code::debug_info_mismatch, Context); 42*38380323SZachary Turner default: { 43*38380323SZachary Turner std::string S; 44*38380323SZachary Turner raw_string_ostream OS(S); 45*38380323SZachary Turner OS << "HRESULT: " << format_hex(static_cast<DWORD>(Result), 10, true) 46*38380323SZachary Turner << ": " << Context; 47*38380323SZachary Turner return make_error<DIAError>(dia_error_code::unspecified, OS.str()); 48*38380323SZachary Turner } 49819e77d1SZachary Turner } 50819e77d1SZachary Turner } 51819e77d1SZachary Turner 52fb58be86SReid Kleckner static Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) { 5373853ab4SNico Weber if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, 5473853ab4SNico Weber IID_IDiaDataSource, 5573853ab4SNico Weber reinterpret_cast<LPVOID *>(&DiaDataSource)))) 56819e77d1SZachary Turner return Error::success(); 5773853ab4SNico Weber 5873853ab4SNico Weber // If the CoCreateInstance call above failed, msdia*.dll is not registered. 5973853ab4SNico Weber // Try loading the DLL corresponding to the #included DIA SDK. 6073853ab4SNico Weber #if !defined(_MSC_VER) 61819e77d1SZachary Turner return llvm::make_error<GenericError>( 62819e77d1SZachary Turner "DIA is only supported when using MSVC."); 63fb58be86SReid Kleckner #else 6473853ab4SNico Weber const wchar_t *msdia_dll = nullptr; 65fb58be86SReid Kleckner #if _MSC_VER >= 1900 && _MSC_VER < 2000 6673853ab4SNico Weber msdia_dll = L"msdia140.dll"; // VS2015 67fb58be86SReid Kleckner #elif _MSC_VER >= 1800 6873853ab4SNico Weber msdia_dll = L"msdia120.dll"; // VS2013 6973853ab4SNico Weber #else 7073853ab4SNico Weber #error "Unknown Visual Studio version." 7173853ab4SNico Weber #endif 7223ee87bdSZachary Turner 73819e77d1SZachary Turner HRESULT HR; 74819e77d1SZachary Turner if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, 7523ee87bdSZachary Turner reinterpret_cast<LPVOID *>(&DiaDataSource)))) 76*38380323SZachary Turner return ErrorFromHResult(HR, "Calling NoRegCoCreate"); 77819e77d1SZachary Turner return Error::success(); 78fb58be86SReid Kleckner #endif 7973853ab4SNico Weber } 80cffff26bSZachary Turner 81cffff26bSZachary Turner DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {} 82cffff26bSZachary Turner 83819e77d1SZachary Turner Error DIASession::createFromPdb(StringRef Path, 84ccf04159SZachary Turner std::unique_ptr<IPDBSession> &Session) { 85ccf04159SZachary Turner CComPtr<IDiaDataSource> DiaDataSource; 86ccf04159SZachary Turner CComPtr<IDiaSession> DiaSession; 87cffff26bSZachary Turner 88cffff26bSZachary Turner // We assume that CoInitializeEx has already been called by the executable. 89819e77d1SZachary Turner if (auto E = LoadDIA(DiaDataSource)) 90819e77d1SZachary Turner return E; 91cffff26bSZachary Turner 92cffff26bSZachary Turner llvm::SmallVector<UTF16, 128> Path16; 93cffff26bSZachary Turner if (!llvm::convertUTF8ToUTF16String(Path, Path16)) 94819e77d1SZachary Turner return make_error<GenericError>(generic_error_code::invalid_path); 95cffff26bSZachary Turner 96cffff26bSZachary Turner const wchar_t *Path16Str = reinterpret_cast<const wchar_t*>(Path16.data()); 97819e77d1SZachary Turner HRESULT HR; 98819e77d1SZachary Turner if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) 99*38380323SZachary Turner return ErrorFromHResult(HR, "Calling loadDataFromPdb"); 100cffff26bSZachary Turner 101819e77d1SZachary Turner if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) 102*38380323SZachary Turner return ErrorFromHResult(HR, "Calling openSession"); 103ccf04159SZachary Turner 104ccf04159SZachary Turner Session.reset(new DIASession(DiaSession)); 105819e77d1SZachary Turner return Error::success(); 106cffff26bSZachary Turner } 107cffff26bSZachary Turner 108819e77d1SZachary Turner Error DIASession::createFromExe(StringRef Path, 1094b08354bSZachary Turner std::unique_ptr<IPDBSession> &Session) { 1104b08354bSZachary Turner CComPtr<IDiaDataSource> DiaDataSource; 1114b08354bSZachary Turner CComPtr<IDiaSession> DiaSession; 1124b08354bSZachary Turner 1134b08354bSZachary Turner // We assume that CoInitializeEx has already been called by the executable. 114819e77d1SZachary Turner if (auto EC = LoadDIA(DiaDataSource)) 115819e77d1SZachary Turner return EC; 1164b08354bSZachary Turner 1174b08354bSZachary Turner llvm::SmallVector<UTF16, 128> Path16; 1184b08354bSZachary Turner if (!llvm::convertUTF8ToUTF16String(Path, Path16)) 119819e77d1SZachary Turner return make_error<GenericError>(generic_error_code::invalid_path, Path); 1204b08354bSZachary Turner 1214b08354bSZachary Turner const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data()); 122819e77d1SZachary Turner HRESULT HR; 123819e77d1SZachary Turner if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr))) 124*38380323SZachary Turner return ErrorFromHResult(HR, "Calling loadDataForExe"); 1254b08354bSZachary Turner 126819e77d1SZachary Turner if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) 127*38380323SZachary Turner return ErrorFromHResult(HR, "Calling openSession"); 1284b08354bSZachary Turner 1294b08354bSZachary Turner Session.reset(new DIASession(DiaSession)); 130819e77d1SZachary Turner return Error::success(); 1314b08354bSZachary Turner } 1324b08354bSZachary Turner 133cffff26bSZachary Turner uint64_t DIASession::getLoadAddress() const { 134cffff26bSZachary Turner uint64_t LoadAddress; 135cffff26bSZachary Turner bool success = (S_OK == Session->get_loadAddress(&LoadAddress)); 136cffff26bSZachary Turner return (success) ? LoadAddress : 0; 137cffff26bSZachary Turner } 138cffff26bSZachary Turner 139cffff26bSZachary Turner void DIASession::setLoadAddress(uint64_t Address) { 140cffff26bSZachary Turner Session->put_loadAddress(Address); 141cffff26bSZachary Turner } 142cffff26bSZachary Turner 143cffff26bSZachary Turner std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() const { 144cffff26bSZachary Turner CComPtr<IDiaSymbol> GlobalScope; 145cffff26bSZachary Turner if (S_OK != Session->get_globalScope(&GlobalScope)) 146cffff26bSZachary Turner return nullptr; 147cffff26bSZachary Turner 148be6d1e49SZachary Turner auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, GlobalScope); 149cffff26bSZachary Turner auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol))); 150cffff26bSZachary Turner std::unique_ptr<PDBSymbolExe> ExeSymbol( 151cffff26bSZachary Turner static_cast<PDBSymbolExe *>(PdbSymbol.release())); 152cffff26bSZachary Turner return ExeSymbol; 153cffff26bSZachary Turner } 154cffff26bSZachary Turner 155cffff26bSZachary Turner std::unique_ptr<PDBSymbol> DIASession::getSymbolById(uint32_t SymbolId) const { 156cffff26bSZachary Turner CComPtr<IDiaSymbol> LocatedSymbol; 157cffff26bSZachary Turner if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol)) 158cffff26bSZachary Turner return nullptr; 159cffff26bSZachary Turner 160be6d1e49SZachary Turner auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, LocatedSymbol); 161cffff26bSZachary Turner return PDBSymbol::create(*this, std::move(RawSymbol)); 162cffff26bSZachary Turner } 163cffff26bSZachary Turner 1644b08354bSZachary Turner std::unique_ptr<PDBSymbol> 165e5cb2693SZachary Turner DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const { 166e5cb2693SZachary Turner enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); 167e5cb2693SZachary Turner 1684b08354bSZachary Turner CComPtr<IDiaSymbol> Symbol; 169e5cb2693SZachary Turner if (S_OK != Session->findSymbolByVA(Address, EnumVal, &Symbol)) { 170e5cb2693SZachary Turner ULONGLONG LoadAddr = 0; 171e5cb2693SZachary Turner if (S_OK != Session->get_loadAddress(&LoadAddr)) 1724b08354bSZachary Turner return nullptr; 173e5cb2693SZachary Turner DWORD RVA = static_cast<DWORD>(Address - LoadAddr); 174e5cb2693SZachary Turner if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol)) 175e5cb2693SZachary Turner return nullptr; 176e5cb2693SZachary Turner } 1774b08354bSZachary Turner auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, Symbol); 1784b08354bSZachary Turner return PDBSymbol::create(*this, std::move(RawSymbol)); 1794b08354bSZachary Turner } 1804b08354bSZachary Turner 1814b08354bSZachary Turner std::unique_ptr<IPDBEnumLineNumbers> 18243ec3af9SZachary Turner DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland, 18343ec3af9SZachary Turner const IPDBSourceFile &File) const { 18443ec3af9SZachary Turner const DIARawSymbol &RawCompiland = 18543ec3af9SZachary Turner static_cast<const DIARawSymbol &>(Compiland.getRawSymbol()); 18643ec3af9SZachary Turner const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File); 18743ec3af9SZachary Turner 18843ec3af9SZachary Turner CComPtr<IDiaEnumLineNumbers> LineNumbers; 18943ec3af9SZachary Turner if (S_OK != 19043ec3af9SZachary Turner Session->findLines(RawCompiland.getDiaSymbol(), RawFile.getDiaFile(), 19143ec3af9SZachary Turner &LineNumbers)) 19243ec3af9SZachary Turner return nullptr; 19343ec3af9SZachary Turner 19443ec3af9SZachary Turner return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers); 19543ec3af9SZachary Turner } 19643ec3af9SZachary Turner 19743ec3af9SZachary Turner std::unique_ptr<IPDBEnumLineNumbers> 1984b08354bSZachary Turner DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const { 1994b08354bSZachary Turner CComPtr<IDiaEnumLineNumbers> LineNumbers; 2004b08354bSZachary Turner if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers)) 2014b08354bSZachary Turner return nullptr; 2024b08354bSZachary Turner 2034b08354bSZachary Turner return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers); 2044b08354bSZachary Turner } 2054b08354bSZachary Turner 20643ec3af9SZachary Turner std::unique_ptr<IPDBEnumSourceFiles> 20743ec3af9SZachary Turner DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland, 20843ec3af9SZachary Turner llvm::StringRef Pattern, 20943ec3af9SZachary Turner PDB_NameSearchFlags Flags) const { 21043ec3af9SZachary Turner IDiaSymbol *DiaCompiland = nullptr; 21143ec3af9SZachary Turner CComBSTR Utf16Pattern; 21243ec3af9SZachary Turner if (!Pattern.empty()) 21343ec3af9SZachary Turner Utf16Pattern = CComBSTR(Pattern.data()); 21443ec3af9SZachary Turner 21543ec3af9SZachary Turner if (Compiland) 21643ec3af9SZachary Turner DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol()) 21743ec3af9SZachary Turner .getDiaSymbol(); 21843ec3af9SZachary Turner 21943ec3af9SZachary Turner Flags = static_cast<PDB_NameSearchFlags>( 22043ec3af9SZachary Turner Flags | PDB_NameSearchFlags::NS_FileNameExtMatch); 22143ec3af9SZachary Turner CComPtr<IDiaEnumSourceFiles> SourceFiles; 22243ec3af9SZachary Turner if (S_OK != 22343ec3af9SZachary Turner Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles)) 22443ec3af9SZachary Turner return nullptr; 22543ec3af9SZachary Turner return llvm::make_unique<DIAEnumSourceFiles>(*this, SourceFiles); 22643ec3af9SZachary Turner } 22743ec3af9SZachary Turner 22843ec3af9SZachary Turner std::unique_ptr<IPDBSourceFile> 22943ec3af9SZachary Turner DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland, 23043ec3af9SZachary Turner llvm::StringRef Pattern, 23143ec3af9SZachary Turner PDB_NameSearchFlags Flags) const { 23243ec3af9SZachary Turner auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags); 23343ec3af9SZachary Turner if (!SourceFiles || SourceFiles->getChildCount() == 0) 23443ec3af9SZachary Turner return nullptr; 23543ec3af9SZachary Turner return SourceFiles->getNext(); 23643ec3af9SZachary Turner } 23743ec3af9SZachary Turner 23843ec3af9SZachary Turner std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> 23943ec3af9SZachary Turner DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern, 24043ec3af9SZachary Turner PDB_NameSearchFlags Flags) const { 24143ec3af9SZachary Turner auto File = findOneSourceFile(nullptr, Pattern, Flags); 24243ec3af9SZachary Turner if (!File) 24343ec3af9SZachary Turner return nullptr; 24443ec3af9SZachary Turner return File->getCompilands(); 24543ec3af9SZachary Turner } 24643ec3af9SZachary Turner 24743ec3af9SZachary Turner std::unique_ptr<PDBSymbolCompiland> 24843ec3af9SZachary Turner DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern, 24943ec3af9SZachary Turner PDB_NameSearchFlags Flags) const { 25043ec3af9SZachary Turner auto Compilands = findCompilandsForSourceFile(Pattern, Flags); 25143ec3af9SZachary Turner if (!Compilands || Compilands->getChildCount() == 0) 25243ec3af9SZachary Turner return nullptr; 25343ec3af9SZachary Turner return Compilands->getNext(); 25443ec3af9SZachary Turner } 25543ec3af9SZachary Turner 256a5549178SZachary Turner std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const { 257a5549178SZachary Turner CComPtr<IDiaEnumSourceFiles> Files; 258a5549178SZachary Turner if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files)) 259a5549178SZachary Turner return nullptr; 260a5549178SZachary Turner 261be6d1e49SZachary Turner return llvm::make_unique<DIAEnumSourceFiles>(*this, Files); 262a5549178SZachary Turner } 263a5549178SZachary Turner 264a5549178SZachary Turner std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland( 265a5549178SZachary Turner const PDBSymbolCompiland &Compiland) const { 266a5549178SZachary Turner CComPtr<IDiaEnumSourceFiles> Files; 267a5549178SZachary Turner 268a5549178SZachary Turner const DIARawSymbol &RawSymbol = 269a5549178SZachary Turner static_cast<const DIARawSymbol &>(Compiland.getRawSymbol()); 270a5549178SZachary Turner if (S_OK != 271a5549178SZachary Turner Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files)) 272a5549178SZachary Turner return nullptr; 273a5549178SZachary Turner 274be6d1e49SZachary Turner return llvm::make_unique<DIAEnumSourceFiles>(*this, Files); 275a5549178SZachary Turner } 276a5549178SZachary Turner 277cffff26bSZachary Turner std::unique_ptr<IPDBSourceFile> 278cffff26bSZachary Turner DIASession::getSourceFileById(uint32_t FileId) const { 279cffff26bSZachary Turner CComPtr<IDiaSourceFile> LocatedFile; 280cffff26bSZachary Turner if (S_OK != Session->findFileById(FileId, &LocatedFile)) 281cffff26bSZachary Turner return nullptr; 282cffff26bSZachary Turner 283be6d1e49SZachary Turner return llvm::make_unique<DIASourceFile>(*this, LocatedFile); 284cffff26bSZachary Turner } 285cffff26bSZachary Turner 286cffff26bSZachary Turner std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const { 287cffff26bSZachary Turner CComPtr<IDiaEnumDebugStreams> DiaEnumerator; 288cffff26bSZachary Turner if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator)) 289cffff26bSZachary Turner return nullptr; 290cffff26bSZachary Turner 291be6d1e49SZachary Turner return llvm::make_unique<DIAEnumDebugStreams>(DiaEnumerator); 292cffff26bSZachary Turner } 293