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