Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp
35294 views
//===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7#include "llvm/DebugInfo/PDB/DIA/DIASession.h"8#include "llvm/ADT/STLExtras.h"9#include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"10#include "llvm/DebugInfo/PDB/DIA/DIAEnumFrameData.h"11#include "llvm/DebugInfo/PDB/DIA/DIAEnumInjectedSources.h"12#include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h"13#include "llvm/DebugInfo/PDB/DIA/DIAEnumSectionContribs.h"14#include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h"15#include "llvm/DebugInfo/PDB/DIA/DIAEnumTables.h"16#include "llvm/DebugInfo/PDB/DIA/DIAError.h"17#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"18#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"19#include "llvm/DebugInfo/PDB/DIA/DIASupport.h"20#include "llvm/DebugInfo/PDB/GenericError.h"21#include "llvm/DebugInfo/PDB/PDB.h"22#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"23#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"24#include "llvm/Support/ConvertUTF.h"25#include "llvm/Support/Format.h"26#include "llvm/Support/FormatVariadic.h"27#include "llvm/Support/raw_ostream.h"2829using namespace llvm;30using namespace llvm::pdb;3132template <typename... Ts>33static Error ErrorFromHResult(HRESULT Result, const char *Str, Ts &&... Args) {34SmallString<64> MessageStorage;35StringRef Context;36if (sizeof...(Args) > 0) {37MessageStorage = formatv(Str, std::forward<Ts>(Args)...).str();38Context = MessageStorage;39} else40Context = Str;4142switch (Result) {43case E_PDB_NOT_FOUND:44return errorCodeToError(std::error_code(ENOENT, std::generic_category()));45case E_PDB_FORMAT:46return make_error<DIAError>(dia_error_code::invalid_file_format, Context);47case E_INVALIDARG:48return make_error<DIAError>(dia_error_code::invalid_parameter, Context);49case E_UNEXPECTED:50return make_error<DIAError>(dia_error_code::already_loaded, Context);51case E_PDB_INVALID_SIG:52case E_PDB_INVALID_AGE:53return make_error<DIAError>(dia_error_code::debug_info_mismatch, Context);54default: {55std::string S;56raw_string_ostream OS(S);57OS << "HRESULT: " << format_hex(static_cast<DWORD>(Result), 10, true)58<< ": " << Context;59return make_error<DIAError>(dia_error_code::unspecified, OS.str());60}61}62}6364static Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) {65if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER,66IID_IDiaDataSource,67reinterpret_cast<LPVOID *>(&DiaDataSource))))68return Error::success();6970// If the CoCreateInstance call above failed, msdia*.dll is not registered.71// Try loading the DLL corresponding to the #included DIA SDK.72#if !defined(_MSC_VER)73return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading);74#else75const wchar_t *msdia_dll = L"msdia140.dll";76HRESULT HR;77if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,78reinterpret_cast<LPVOID *>(&DiaDataSource))))79return ErrorFromHResult(HR, "Calling NoRegCoCreate");80return Error::success();81#endif82}8384DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {}8586Error DIASession::createFromPdb(StringRef Path,87std::unique_ptr<IPDBSession> &Session) {88CComPtr<IDiaDataSource> DiaDataSource;89CComPtr<IDiaSession> DiaSession;9091// We assume that CoInitializeEx has already been called by the executable.92if (auto E = LoadDIA(DiaDataSource))93return E;9495llvm::SmallVector<UTF16, 128> Path16;96if (!llvm::convertUTF8ToUTF16String(Path, Path16))97return make_error<PDBError>(pdb_error_code::invalid_utf8_path, Path);9899const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());100HRESULT HR;101if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) {102return ErrorFromHResult(HR, "Calling loadDataFromPdb {0}", Path);103}104105if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))106return ErrorFromHResult(HR, "Calling openSession");107108Session.reset(new DIASession(DiaSession));109return Error::success();110}111112Error DIASession::createFromExe(StringRef Path,113std::unique_ptr<IPDBSession> &Session) {114CComPtr<IDiaDataSource> DiaDataSource;115CComPtr<IDiaSession> DiaSession;116117// We assume that CoInitializeEx has already been called by the executable.118if (auto EC = LoadDIA(DiaDataSource))119return EC;120121llvm::SmallVector<UTF16, 128> Path16;122if (!llvm::convertUTF8ToUTF16String(Path, Path16))123return make_error<PDBError>(pdb_error_code::invalid_utf8_path, Path);124125const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());126HRESULT HR;127if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr)))128return ErrorFromHResult(HR, "Calling loadDataForExe");129130if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))131return ErrorFromHResult(HR, "Calling openSession");132133Session.reset(new DIASession(DiaSession));134return Error::success();135}136137uint64_t DIASession::getLoadAddress() const {138uint64_t LoadAddress;139bool success = (S_OK == Session->get_loadAddress(&LoadAddress));140return (success) ? LoadAddress : 0;141}142143bool DIASession::setLoadAddress(uint64_t Address) {144return (S_OK == Session->put_loadAddress(Address));145}146147std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() {148CComPtr<IDiaSymbol> GlobalScope;149if (S_OK != Session->get_globalScope(&GlobalScope))150return nullptr;151152auto RawSymbol = std::make_unique<DIARawSymbol>(*this, GlobalScope);153auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol)));154std::unique_ptr<PDBSymbolExe> ExeSymbol(155static_cast<PDBSymbolExe *>(PdbSymbol.release()));156return ExeSymbol;157}158159bool DIASession::addressForVA(uint64_t VA, uint32_t &Section,160uint32_t &Offset) const {161DWORD ArgSection, ArgOffset = 0;162if (S_OK == Session->addressForVA(VA, &ArgSection, &ArgOffset)) {163Section = static_cast<uint32_t>(ArgSection);164Offset = static_cast<uint32_t>(ArgOffset);165return true;166}167return false;168}169170bool DIASession::addressForRVA(uint32_t RVA, uint32_t &Section,171uint32_t &Offset) const {172DWORD ArgSection, ArgOffset = 0;173if (S_OK == Session->addressForRVA(RVA, &ArgSection, &ArgOffset)) {174Section = static_cast<uint32_t>(ArgSection);175Offset = static_cast<uint32_t>(ArgOffset);176return true;177}178return false;179}180181std::unique_ptr<PDBSymbol>182DIASession::getSymbolById(SymIndexId SymbolId) const {183CComPtr<IDiaSymbol> LocatedSymbol;184if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol))185return nullptr;186187auto RawSymbol = std::make_unique<DIARawSymbol>(*this, LocatedSymbol);188return PDBSymbol::create(*this, std::move(RawSymbol));189}190191std::unique_ptr<PDBSymbol> DIASession::findSymbolByAddress(uint64_t Address,192PDB_SymType Type) {193enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);194195CComPtr<IDiaSymbol> Symbol;196if (S_OK != Session->findSymbolByVA(Address, EnumVal, &Symbol)) {197ULONGLONG LoadAddr = 0;198if (S_OK != Session->get_loadAddress(&LoadAddr))199return nullptr;200DWORD RVA = static_cast<DWORD>(Address - LoadAddr);201if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol))202return nullptr;203}204auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol);205return PDBSymbol::create(*this, std::move(RawSymbol));206}207208std::unique_ptr<PDBSymbol> DIASession::findSymbolByRVA(uint32_t RVA,209PDB_SymType Type) {210enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);211212CComPtr<IDiaSymbol> Symbol;213if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol))214return nullptr;215216auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol);217return PDBSymbol::create(*this, std::move(RawSymbol));218}219220std::unique_ptr<PDBSymbol>221DIASession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,222PDB_SymType Type) {223enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);224225CComPtr<IDiaSymbol> Symbol;226if (S_OK != Session->findSymbolByAddr(Sect, Offset, EnumVal, &Symbol))227return nullptr;228229auto RawSymbol = std::make_unique<DIARawSymbol>(*this, Symbol);230return PDBSymbol::create(*this, std::move(RawSymbol));231}232233std::unique_ptr<IPDBEnumLineNumbers>234DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland,235const IPDBSourceFile &File) const {236const DIARawSymbol &RawCompiland =237static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());238const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File);239240CComPtr<IDiaEnumLineNumbers> LineNumbers;241if (S_OK != Session->findLines(RawCompiland.getDiaSymbol(),242RawFile.getDiaFile(), &LineNumbers))243return nullptr;244245return std::make_unique<DIAEnumLineNumbers>(LineNumbers);246}247248std::unique_ptr<IPDBEnumLineNumbers>249DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {250CComPtr<IDiaEnumLineNumbers> LineNumbers;251if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers)) {252ULONGLONG LoadAddr = 0;253if (S_OK != Session->get_loadAddress(&LoadAddr))254return nullptr;255DWORD RVA = static_cast<DWORD>(Address - LoadAddr);256if (S_OK != Session->findLinesByRVA(RVA, Length, &LineNumbers))257return nullptr;258}259return std::make_unique<DIAEnumLineNumbers>(LineNumbers);260}261262std::unique_ptr<IPDBEnumLineNumbers>263DIASession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {264CComPtr<IDiaEnumLineNumbers> LineNumbers;265if (S_OK != Session->findLinesByRVA(RVA, Length, &LineNumbers))266return nullptr;267268return std::make_unique<DIAEnumLineNumbers>(LineNumbers);269}270271std::unique_ptr<IPDBEnumLineNumbers>272DIASession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset,273uint32_t Length) const {274CComPtr<IDiaEnumLineNumbers> LineNumbers;275if (S_OK != Session->findLinesByAddr(Section, Offset, Length, &LineNumbers))276return nullptr;277278return std::make_unique<DIAEnumLineNumbers>(LineNumbers);279}280281std::unique_ptr<IPDBEnumSourceFiles>282DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland,283llvm::StringRef Pattern,284PDB_NameSearchFlags Flags) const {285IDiaSymbol *DiaCompiland = nullptr;286CComBSTR Utf16Pattern;287if (!Pattern.empty())288Utf16Pattern = CComBSTR(Pattern.data());289290if (Compiland)291DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol())292.getDiaSymbol();293294Flags = static_cast<PDB_NameSearchFlags>(295Flags | PDB_NameSearchFlags::NS_FileNameExtMatch);296CComPtr<IDiaEnumSourceFiles> SourceFiles;297if (S_OK !=298Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles))299return nullptr;300return std::make_unique<DIAEnumSourceFiles>(*this, SourceFiles);301}302303std::unique_ptr<IPDBSourceFile>304DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland,305llvm::StringRef Pattern,306PDB_NameSearchFlags Flags) const {307auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags);308if (!SourceFiles || SourceFiles->getChildCount() == 0)309return nullptr;310return SourceFiles->getNext();311}312313std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>314DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern,315PDB_NameSearchFlags Flags) const {316auto File = findOneSourceFile(nullptr, Pattern, Flags);317if (!File)318return nullptr;319return File->getCompilands();320}321322std::unique_ptr<PDBSymbolCompiland>323DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern,324PDB_NameSearchFlags Flags) const {325auto Compilands = findCompilandsForSourceFile(Pattern, Flags);326if (!Compilands || Compilands->getChildCount() == 0)327return nullptr;328return Compilands->getNext();329}330331std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const {332CComPtr<IDiaEnumSourceFiles> Files;333if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files))334return nullptr;335336return std::make_unique<DIAEnumSourceFiles>(*this, Files);337}338339std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland(340const PDBSymbolCompiland &Compiland) const {341CComPtr<IDiaEnumSourceFiles> Files;342343const DIARawSymbol &RawSymbol =344static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());345if (S_OK !=346Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files))347return nullptr;348349return std::make_unique<DIAEnumSourceFiles>(*this, Files);350}351352std::unique_ptr<IPDBSourceFile>353DIASession::getSourceFileById(uint32_t FileId) const {354CComPtr<IDiaSourceFile> LocatedFile;355if (S_OK != Session->findFileById(FileId, &LocatedFile))356return nullptr;357358return std::make_unique<DIASourceFile>(*this, LocatedFile);359}360361std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const {362CComPtr<IDiaEnumDebugStreams> DiaEnumerator;363if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator))364return nullptr;365366return std::make_unique<DIAEnumDebugStreams>(DiaEnumerator);367}368369std::unique_ptr<IPDBEnumTables> DIASession::getEnumTables() const {370CComPtr<IDiaEnumTables> DiaEnumerator;371if (S_OK != Session->getEnumTables(&DiaEnumerator))372return nullptr;373374return std::make_unique<DIAEnumTables>(DiaEnumerator);375}376377template <class T> static CComPtr<T> getTableEnumerator(IDiaSession &Session) {378CComPtr<T> Enumerator;379CComPtr<IDiaEnumTables> ET;380CComPtr<IDiaTable> Table;381ULONG Count = 0;382383if (Session.getEnumTables(&ET) != S_OK)384return nullptr;385386while (ET->Next(1, &Table, &Count) == S_OK && Count == 1) {387// There is only one table that matches the given iid388if (S_OK == Table->QueryInterface(__uuidof(T), (void **)&Enumerator))389break;390Table.Release();391}392return Enumerator;393}394std::unique_ptr<IPDBEnumInjectedSources>395DIASession::getInjectedSources() const {396CComPtr<IDiaEnumInjectedSources> Files =397getTableEnumerator<IDiaEnumInjectedSources>(*Session);398if (!Files)399return nullptr;400401return std::make_unique<DIAEnumInjectedSources>(Files);402}403404std::unique_ptr<IPDBEnumSectionContribs>405DIASession::getSectionContribs() const {406CComPtr<IDiaEnumSectionContribs> Sections =407getTableEnumerator<IDiaEnumSectionContribs>(*Session);408if (!Sections)409return nullptr;410411return std::make_unique<DIAEnumSectionContribs>(*this, Sections);412}413414std::unique_ptr<IPDBEnumFrameData>415DIASession::getFrameData() const {416CComPtr<IDiaEnumFrameData> FD =417getTableEnumerator<IDiaEnumFrameData>(*Session);418if (!FD)419return nullptr;420421return std::make_unique<DIAEnumFrameData>(FD);422}423424425