1 //===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #include "llvm/DebugInfo/PDB/DIA/DIASession.h" 9 #include "llvm/ADT/STLExtras.h" 10 #include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h" 11 #include "llvm/DebugInfo/PDB/DIA/DIAEnumFrameData.h" 12 #include "llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h" 13 #include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h" 14 #include "llvm/DebugInfo/PDB/DIA/DIAEnumSectionContribs.h" 15 #include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h" 16 #include "llvm/DebugInfo/PDB/DIA/DIAEnumTables.h" 17 #include "llvm/DebugInfo/PDB/DIA/DIAError.h" 18 #include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h" 19 #include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h" 20 #include "llvm/DebugInfo/PDB/DIA/DIASupport.h" 21 #include "llvm/DebugInfo/PDB/GenericError.h" 22 #include "llvm/DebugInfo/PDB/PDB.h" 23 #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" 24 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" 25 #include "llvm/Support/ConvertUTF.h" 26 #include "llvm/Support/Format.h" 27 #include "llvm/Support/FormatVariadic.h" 28 #include "llvm/Support/raw_ostream.h" 29 30 using namespace llvm; 31 using namespace llvm::pdb; 32 33 template <typename... Ts> 34 static Error ErrorFromHResult(HRESULT Result, const char *Str, Ts &&... Args) { 35 SmallString<64> MessageStorage; 36 StringRef Context; 37 if (sizeof...(Args) > 0) { 38 MessageStorage = formatv(Str, std::forward<Ts>(Args)...).str(); 39 Context = MessageStorage; 40 } else 41 Context = Str; 42 43 switch (Result) { 44 case E_PDB_NOT_FOUND: 45 return errorCodeToError(std::error_code(ENOENT, std::generic_category())); 46 case E_PDB_FORMAT: 47 return make_error<DIAError>(dia_error_code::invalid_file_format, Context); 48 case E_INVALIDARG: 49 return make_error<DIAError>(dia_error_code::invalid_parameter, Context); 50 case E_UNEXPECTED: 51 return make_error<DIAError>(dia_error_code::already_loaded, Context); 52 case E_PDB_INVALID_SIG: 53 case E_PDB_INVALID_AGE: 54 return make_error<DIAError>(dia_error_code::debug_info_mismatch, Context); 55 default: { 56 std::string S; 57 raw_string_ostream OS(S); 58 OS << "HRESULT: " << format_hex(static_cast<DWORD>(Result), 10, true) 59 << ": " << Context; 60 return make_error<DIAError>(dia_error_code::unspecified, OS.str()); 61 } 62 } 63 } 64 65 static Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) { 66 if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, 67 IID_IDiaDataSource, 68 reinterpret_cast<LPVOID *>(&DiaDataSource)))) 69 return Error::success(); 70 71 // If the CoCreateInstance call above failed, msdia*.dll is not registered. 72 // Try loading the DLL corresponding to the #included DIA SDK. 73 #if !defined(_MSC_VER) 74 return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading); 75 #else 76 const wchar_t *msdia_dll = L"msdia140.dll"; 77 HRESULT HR; 78 if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, 79 reinterpret_cast<LPVOID *>(&DiaDataSource)))) 80 return ErrorFromHResult(HR, "Calling NoRegCoCreate"); 81 return Error::success(); 82 #endif 83 } 84 85 DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {} 86 87 Error DIASession::createFromPdb(StringRef Path, 88 std::unique_ptr<IPDBSession> &Session) { 89 CComPtr<IDiaDataSource> DiaDataSource; 90 CComPtr<IDiaSession> DiaSession; 91 92 // We assume that CoInitializeEx has already been called by the executable. 93 if (auto E = LoadDIA(DiaDataSource)) 94 return E; 95 96 llvm::SmallVector<UTF16, 128> Path16; 97 if (!llvm::convertUTF8ToUTF16String(Path, Path16)) 98 return make_error<PDBError>(pdb_error_code::invalid_utf8_path, Path); 99 100 const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data()); 101 HRESULT HR; 102 if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) { 103 return ErrorFromHResult(HR, "Calling loadDataFromPdb {0}", Path); 104 } 105 106 if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) 107 return ErrorFromHResult(HR, "Calling openSession"); 108 109 Session.reset(new DIASession(DiaSession)); 110 return Error::success(); 111 } 112 113 Error DIASession::createFromExe(StringRef Path, 114 std::unique_ptr<IPDBSession> &Session) { 115 CComPtr<IDiaDataSource> DiaDataSource; 116 CComPtr<IDiaSession> DiaSession; 117 118 // We assume that CoInitializeEx has already been called by the executable. 119 if (auto EC = LoadDIA(DiaDataSource)) 120 return EC; 121 122 llvm::SmallVector<UTF16, 128> Path16; 123 if (!llvm::convertUTF8ToUTF16String(Path, Path16)) 124 return make_error<PDBError>(pdb_error_code::invalid_utf8_path, Path); 125 126 const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data()); 127 HRESULT HR; 128 if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr))) 129 return ErrorFromHResult(HR, "Calling loadDataForExe"); 130 131 if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) 132 return ErrorFromHResult(HR, "Calling openSession"); 133 134 Session.reset(new DIASession(DiaSession)); 135 return Error::success(); 136 } 137 138 uint64_t DIASession::getLoadAddress() const { 139 uint64_t LoadAddress; 140 bool success = (S_OK == Session->get_loadAddress(&LoadAddress)); 141 return (success) ? LoadAddress : 0; 142 } 143 144 bool DIASession::setLoadAddress(uint64_t Address) { 145 return (S_OK == Session->put_loadAddress(Address)); 146 } 147 148 std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() { 149 CComPtr<IDiaSymbol> GlobalScope; 150 if (S_OK != Session->get_globalScope(&GlobalScope)) 151 return nullptr; 152 153 auto RawSymbol = std::make_unique<DIARawSymbol>(*this, GlobalScope); 154 auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol))); 155 std::unique_ptr<PDBSymbolExe> ExeSymbol( 156 static_cast<PDBSymbolExe *>(PdbSymbol.release())); 157 return ExeSymbol; 158 } 159 160 bool DIASession::addressForVA(uint64_t VA, uint32_t &Section, 161 uint32_t &Offset) const { 162 DWORD ArgSection, ArgOffset = 0; 163 if (S_OK == Session->addressForVA(VA, &ArgSection, &ArgOffset)) { 164 Section = static_cast<uint32_t>(ArgSection); 165 Offset = static_cast<uint32_t>(ArgOffset); 166 return true; 167 } 168 return false; 169 } 170 171 bool DIASession::addressForRVA(uint32_t RVA, uint32_t &Section, 172 uint32_t &Offset) const { 173 DWORD ArgSection, ArgOffset = 0; 174 if (S_OK == Session->addressForRVA(RVA, &ArgSection, &ArgOffset)) { 175 Section = static_cast<uint32_t>(ArgSection); 176 Offset = static_cast<uint32_t>(ArgOffset); 177 return true; 178 } 179 return false; 180 } 181 182 std::unique_ptr<PDBSymbol> 183 DIASession::getSymbolById(SymIndexId SymbolId) const { 184 CComPtr<IDiaSymbol> LocatedSymbol; 185 if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol)) 186 return nullptr; 187 188 auto RawSymbol = std::make_unique<DIARawSymbol>(*this, LocatedSymbol); 189 return PDBSymbol::create(*this, std::move(RawSymbol)); 190 } 191 192 std::unique_ptr<PDBSymbol> 193 DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const { 194 enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); 195 196 CComPtr<IDiaSymbol> Symbol; 197 if (S_OK != Session->findSymbolByVA(Address, EnumVal, &Symbol)) { 198 ULONGLONG LoadAddr = 0; 199 if (S_OK != Session->get_loadAddress(&LoadAddr)) 200 return nullptr; 201 DWORD RVA = static_cast<DWORD>(Address - LoadAddr); 202 if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol)) 203 return nullptr; 204 } 205 auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol); 206 return PDBSymbol::create(*this, std::move(RawSymbol)); 207 } 208 209 std::unique_ptr<PDBSymbol> DIASession::findSymbolByRVA(uint32_t RVA, 210 PDB_SymType Type) const { 211 enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); 212 213 CComPtr<IDiaSymbol> Symbol; 214 if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol)) 215 return nullptr; 216 217 auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol); 218 return PDBSymbol::create(*this, std::move(RawSymbol)); 219 } 220 221 std::unique_ptr<PDBSymbol> 222 DIASession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, 223 PDB_SymType Type) const { 224 enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type); 225 226 CComPtr<IDiaSymbol> Symbol; 227 if (S_OK != Session->findSymbolByAddr(Sect, Offset, EnumVal, &Symbol)) 228 return nullptr; 229 230 auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol); 231 return PDBSymbol::create(*this, std::move(RawSymbol)); 232 } 233 234 std::unique_ptr<IPDBEnumLineNumbers> 235 DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland, 236 const IPDBSourceFile &File) const { 237 const DIARawSymbol &RawCompiland = 238 static_cast<const DIARawSymbol &>(Compiland.getRawSymbol()); 239 const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File); 240 241 CComPtr<IDiaEnumLineNumbers> LineNumbers; 242 if (S_OK != Session->findLines(RawCompiland.getDiaSymbol(), 243 RawFile.getDiaFile(), &LineNumbers)) 244 return nullptr; 245 246 return std::make_unique<DIAEnumLineNumbers>(LineNumbers); 247 } 248 249 std::unique_ptr<IPDBEnumLineNumbers> 250 DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const { 251 CComPtr<IDiaEnumLineNumbers> LineNumbers; 252 if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers)) { 253 ULONGLONG LoadAddr = 0; 254 if (S_OK != Session->get_loadAddress(&LoadAddr)) 255 return nullptr; 256 DWORD RVA = static_cast<DWORD>(Address - LoadAddr); 257 if (S_OK != Session->findLinesByRVA(RVA, Length, &LineNumbers)) 258 return nullptr; 259 } 260 return std::make_unique<DIAEnumLineNumbers>(LineNumbers); 261 } 262 263 std::unique_ptr<IPDBEnumLineNumbers> 264 DIASession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const { 265 CComPtr<IDiaEnumLineNumbers> LineNumbers; 266 if (S_OK != Session->findLinesByRVA(RVA, Length, &LineNumbers)) 267 return nullptr; 268 269 return std::make_unique<DIAEnumLineNumbers>(LineNumbers); 270 } 271 272 std::unique_ptr<IPDBEnumLineNumbers> 273 DIASession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, 274 uint32_t Length) const { 275 CComPtr<IDiaEnumLineNumbers> LineNumbers; 276 if (S_OK != Session->findLinesByAddr(Section, Offset, Length, &LineNumbers)) 277 return nullptr; 278 279 return std::make_unique<DIAEnumLineNumbers>(LineNumbers); 280 } 281 282 std::unique_ptr<IPDBEnumSourceFiles> 283 DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland, 284 llvm::StringRef Pattern, 285 PDB_NameSearchFlags Flags) const { 286 IDiaSymbol *DiaCompiland = nullptr; 287 CComBSTR Utf16Pattern; 288 if (!Pattern.empty()) 289 Utf16Pattern = CComBSTR(Pattern.data()); 290 291 if (Compiland) 292 DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol()) 293 .getDiaSymbol(); 294 295 Flags = static_cast<PDB_NameSearchFlags>( 296 Flags | PDB_NameSearchFlags::NS_FileNameExtMatch); 297 CComPtr<IDiaEnumSourceFiles> SourceFiles; 298 if (S_OK != 299 Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles)) 300 return nullptr; 301 return std::make_unique<DIAEnumSourceFiles>(*this, SourceFiles); 302 } 303 304 std::unique_ptr<IPDBSourceFile> 305 DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland, 306 llvm::StringRef Pattern, 307 PDB_NameSearchFlags Flags) const { 308 auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags); 309 if (!SourceFiles || SourceFiles->getChildCount() == 0) 310 return nullptr; 311 return SourceFiles->getNext(); 312 } 313 314 std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> 315 DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern, 316 PDB_NameSearchFlags Flags) const { 317 auto File = findOneSourceFile(nullptr, Pattern, Flags); 318 if (!File) 319 return nullptr; 320 return File->getCompilands(); 321 } 322 323 std::unique_ptr<PDBSymbolCompiland> 324 DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern, 325 PDB_NameSearchFlags Flags) const { 326 auto Compilands = findCompilandsForSourceFile(Pattern, Flags); 327 if (!Compilands || Compilands->getChildCount() == 0) 328 return nullptr; 329 return Compilands->getNext(); 330 } 331 332 std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const { 333 CComPtr<IDiaEnumSourceFiles> Files; 334 if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files)) 335 return nullptr; 336 337 return std::make_unique<DIAEnumSourceFiles>(*this, Files); 338 } 339 340 std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland( 341 const PDBSymbolCompiland &Compiland) const { 342 CComPtr<IDiaEnumSourceFiles> Files; 343 344 const DIARawSymbol &RawSymbol = 345 static_cast<const DIARawSymbol &>(Compiland.getRawSymbol()); 346 if (S_OK != 347 Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files)) 348 return nullptr; 349 350 return std::make_unique<DIAEnumSourceFiles>(*this, Files); 351 } 352 353 std::unique_ptr<IPDBSourceFile> 354 DIASession::getSourceFileById(uint32_t FileId) const { 355 CComPtr<IDiaSourceFile> LocatedFile; 356 if (S_OK != Session->findFileById(FileId, &LocatedFile)) 357 return nullptr; 358 359 return std::make_unique<DIASourceFile>(*this, LocatedFile); 360 } 361 362 std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const { 363 CComPtr<IDiaEnumDebugStreams> DiaEnumerator; 364 if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator)) 365 return nullptr; 366 367 return std::make_unique<DIAEnumDebugStreams>(DiaEnumerator); 368 } 369 370 std::unique_ptr<IPDBEnumTables> DIASession::getEnumTables() const { 371 CComPtr<IDiaEnumTables> DiaEnumerator; 372 if (S_OK != Session->getEnumTables(&DiaEnumerator)) 373 return nullptr; 374 375 return std::make_unique<DIAEnumTables>(DiaEnumerator); 376 } 377 378 template <class T> static CComPtr<T> getTableEnumerator(IDiaSession &Session) { 379 CComPtr<T> Enumerator; 380 CComPtr<IDiaEnumTables> ET; 381 CComPtr<IDiaTable> Table; 382 ULONG Count = 0; 383 384 if (Session.getEnumTables(&ET) != S_OK) 385 return nullptr; 386 387 while (ET->Next(1, &Table, &Count) == S_OK && Count == 1) { 388 // There is only one table that matches the given iid 389 if (S_OK == Table->QueryInterface(__uuidof(T), (void **)&Enumerator)) 390 break; 391 Table.Release(); 392 } 393 return Enumerator; 394 } 395 std::unique_ptr<IPDBEnumInjectedSources> 396 DIASession::getInjectedSources() const { 397 CComPtr<IDiaEnumInjectedSources> Files = 398 getTableEnumerator<IDiaEnumInjectedSources>(*Session); 399 if (!Files) 400 return nullptr; 401 402 return std::make_unique<DIAEnumInjectedSources>(Files); 403 } 404 405 std::unique_ptr<IPDBEnumSectionContribs> 406 DIASession::getSectionContribs() const { 407 CComPtr<IDiaEnumSectionContribs> Sections = 408 getTableEnumerator<IDiaEnumSectionContribs>(*Session); 409 if (!Sections) 410 return nullptr; 411 412 return std::make_unique<DIAEnumSectionContribs>(*this, Sections); 413 } 414 415 std::unique_ptr<IPDBEnumFrameData> 416 DIASession::getFrameData() const { 417 CComPtr<IDiaEnumFrameData> FD = 418 getTableEnumerator<IDiaEnumFrameData>(*Session); 419 if (!FD) 420 return nullptr; 421 422 return std::make_unique<DIAEnumFrameData>(FD); 423 } 424