Untitled diff

Created Diff never expires
1 removal
290 lines
2 additions
290 lines
//===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===//
//===- DIASession.cpp - DIA implementation of IPDBSession -------*- C++ -*-===//
//
//
// The LLVM Compiler Infrastructure
// The LLVM Compiler Infrastructure
//
//
// This file is distributed under the University of Illinois Open Source
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// License. See LICENSE.TXT for details.
//
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
#include "llvm/DebugInfo/PDB/DIA/DIASession.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h"
#include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h"
#include "llvm/DebugInfo/PDB/DIA/DIAError.h"
#include "llvm/DebugInfo/PDB/DIA/DIAError.h"
#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"
#include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h"
#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
#include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h"
#include "llvm/DebugInfo/PDB/DIA/DIASupport.h"
#include "llvm/DebugInfo/PDB/DIA/DIASupport.h"
#include "llvm/DebugInfo/PDB/GenericError.h"
#include "llvm/DebugInfo/PDB/GenericError.h"
#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ConvertUTF.h"


using namespace llvm;
using namespace llvm;
using namespace llvm::pdb;
using namespace llvm::pdb;


namespace {
namespace {


Error ErrorFromHResult(HRESULT Result) {
Error ErrorFromHResult(HRESULT Result) {
switch (Result) {
switch (Result) {
case E_PDB_NOT_FOUND:
case E_PDB_NOT_FOUND:
return make_error<GenericError>(generic_error_code::invalid_path);
return make_error<GenericError>(generic_error_code::invalid_path);
case E_PDB_FORMAT:
case E_PDB_FORMAT:
return make_error<DIAError>(dia_error_code::invalid_file_format);
return make_error<DIAError>(dia_error_code::invalid_file_format);
case E_INVALIDARG:
case E_INVALIDARG:
return make_error<DIAError>(dia_error_code::invalid_parameter);
return make_error<DIAError>(dia_error_code::invalid_parameter);
case E_UNEXPECTED:
case E_UNEXPECTED:
return make_error<DIAError>(dia_error_code::already_loaded);
return make_error<DIAError>(dia_error_code::already_loaded);
case E_PDB_INVALID_SIG:
case E_PDB_INVALID_SIG:
case E_PDB_INVALID_AGE:
case E_PDB_INVALID_AGE:
return make_error<DIAError>(dia_error_code::debug_info_mismatch);
return make_error<DIAError>(dia_error_code::debug_info_mismatch);
default:
default:
return make_error<DIAError>(dia_error_code::unspecified);
return make_error<DIAError>(dia_error_code::unspecified);
}
}
}
}


Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) {
Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) {
if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER,
if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER,
IID_IDiaDataSource,
IID_IDiaDataSource,
reinterpret_cast<LPVOID *>(&DiaDataSource))))
reinterpret_cast<LPVOID *>(&DiaDataSource))))
return Error::success();
return Error::success();


// If the CoCreateInstance call above failed, msdia*.dll is not registered.
// If the CoCreateInstance call above failed, msdia*.dll is not registered.
// Try loading the DLL corresponding to the #included DIA SDK.
// Try loading the DLL corresponding to the #included DIA SDK.
#if !defined(_MSC_VER)
#if !defined(_MSC_VER)
return llvm::make_error<GenericError>(
return llvm::make_error<GenericError>(
"DIA is only supported when using MSVC.");
"DIA is only supported when using MSVC.");
#endif
#endif


const wchar_t *msdia_dll = nullptr;
const wchar_t *msdia_dll = nullptr;
#if _MSC_VER == 1900
#if _MSC_VER >= 1900 && _MSC_VER < 2000
msdia_dll = L"msdia140.dll"; // VS2015
msdia_dll = L"msdia140.dll"; // VS2015
#elif _MSC_VER == 1800
#elif _MSC_VER == 1800
msdia_dll = L"msdia120.dll"; // VS2013
msdia_dll = L"msdia120.dll"; // VS2013
#else
#else
#error "Unknown Visual Studio version."
#error "Unknown Visual Studio version."
#endif
#endif


HRESULT HR;
HRESULT HR;
if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,
if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,
reinterpret_cast<LPVOID *>(&DiaDataSource))))
reinterpret_cast<LPVOID *>(&DiaDataSource))))
return ErrorFromHResult(HR);
return ErrorFromHResult(HR);
return Error::success();
return Error::success();
}
}


}
}


DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {}
DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {}


Error DIASession::createFromPdb(StringRef Path,
Error DIASession::createFromPdb(StringRef Path,
std::unique_ptr<IPDBSession> &Session) {
std::unique_ptr<IPDBSession> &Session) {
CComPtr<IDiaDataSource> DiaDataSource;
CComPtr<IDiaDataSource> DiaDataSource;
CComPtr<IDiaSession> DiaSession;
CComPtr<IDiaSession> DiaSession;


// We assume that CoInitializeEx has already been called by the executable.
// We assume that CoInitializeEx has already been called by the executable.
if (auto E = LoadDIA(DiaDataSource))
if (auto E = LoadDIA(DiaDataSource))
return E;
return E;


llvm::SmallVector<UTF16, 128> Path16;
llvm::SmallVector<UTF16, 128> Path16;
if (!llvm::convertUTF8ToUTF16String(Path, Path16))
if (!llvm::convertUTF8ToUTF16String(Path, Path16))
return make_error<GenericError>(generic_error_code::invalid_path);
return make_error<GenericError>(generic_error_code::invalid_path);


const wchar_t *Path16Str = reinterpret_cast<const wchar_t*>(Path16.data());
const wchar_t *Path16Str = reinterpret_cast<const wchar_t*>(Path16.data());
HRESULT HR;
HRESULT HR;
if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str)))
if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str)))
return ErrorFromHResult(HR);
return ErrorFromHResult(HR);


if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
return ErrorFromHResult(HR);
return ErrorFromHResult(HR);


Session.reset(new DIASession(DiaSession));
Session.reset(new DIASession(DiaSession));
return Error::success();
return Error::success();
}
}


Error DIASession::createFromExe(StringRef Path,
Error DIASession::createFromExe(StringRef Path,
std::unique_ptr<IPDBSession> &Session) {
std::unique_ptr<IPDBSession> &Session) {
CComPtr<IDiaDataSource> DiaDataSource;
CComPtr<IDiaDataSource> DiaDataSource;
CComPtr<IDiaSession> DiaSession;
CComPtr<IDiaSession> DiaSession;


// We assume that CoInitializeEx has already been called by the executable.
// We assume that CoInitializeEx has already been called by the executable.
if (auto EC = LoadDIA(DiaDataSource))
if (auto EC = LoadDIA(DiaDataSource))
return EC;
return EC;


llvm::SmallVector<UTF16, 128> Path16;
llvm::SmallVector<UTF16, 128> Path16;
if (!llvm::convertUTF8ToUTF16String(Path, Path16))
if (!llvm::convertUTF8ToUTF16String(Path, Path16))
return make_error<GenericError>(generic_error_code::invalid_path, Path);
return make_error<GenericError>(generic_error_code::invalid_path, Path);


const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());
const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data());
HRESULT HR;
HRESULT HR;
if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr)))
if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr)))
return ErrorFromHResult(HR);
return ErrorFromHResult(HR);


if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
if (FAILED(HR = DiaDataSource->openSession(&DiaSession)))
return ErrorFromHResult(HR);
return ErrorFromHResult(HR);


Session.reset(new DIASession(DiaSession));
Session.reset(new DIASession(DiaSession));
return Error::success();
return Error::success();
}
}


uint64_t DIASession::getLoadAddress() const {
uint64_t DIASession::getLoadAddress() const {
uint64_t LoadAddress;
uint64_t LoadAddress;
bool success = (S_OK == Session->get_loadAddress(&LoadAddress));
bool success = (S_OK == Session->get_loadAddress(&LoadAddress));
return (success) ? LoadAddress : 0;
return (success) ? LoadAddress : 0;
}
}


void DIASession::setLoadAddress(uint64_t Address) {
void DIASession::setLoadAddress(uint64_t Address) {
Session->put_loadAddress(Address);
Session->put_loadAddress(Address);
}
}


std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() const {
std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() const {
CComPtr<IDiaSymbol> GlobalScope;
CComPtr<IDiaSymbol> GlobalScope;
if (S_OK != Session->get_globalScope(&GlobalScope))
if (S_OK != Session->get_globalScope(&GlobalScope))
return nullptr;
return nullptr;


auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, GlobalScope);
auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, GlobalScope);
auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol)));
auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol)));
std::unique_ptr<PDBSymbolExe> ExeSymbol(
std::unique_ptr<PDBSymbolExe> ExeSymbol(
static_cast<PDBSymbolExe *>(PdbSymbol.release()));
static_cast<PDBSymbolExe *>(PdbSymbol.release()));
return ExeSymbol;
return ExeSymbol;
}
}


std::unique_ptr<PDBSymbol> DIASession::getSymbolById(uint32_t SymbolId) const {
std::unique_ptr<PDBSymbol> DIASession::getSymbolById(uint32_t SymbolId) const {
CComPtr<IDiaSymbol> LocatedSymbol;
CComPtr<IDiaSymbol> LocatedSymbol;
if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol))
if (S_OK != Session->symbolById(SymbolId, &LocatedSymbol))
return nullptr;
return nullptr;


auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, LocatedSymbol);
auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, LocatedSymbol);
return PDBSymbol::create(*this, std::move(RawSymbol));
return PDBSymbol::create(*this, std::move(RawSymbol));
}
}


std::unique_ptr<PDBSymbol>
std::unique_ptr<PDBSymbol>
DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const {
DIASession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const {
enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);
enum SymTagEnum EnumVal = static_cast<enum SymTagEnum>(Type);


CComPtr<IDiaSymbol> Symbol;
CComPtr<IDiaSymbol> Symbol;
if (S_OK != Session->findSymbolByVA(Address, EnumVal, &Symbol)) {
if (S_OK != Session->findSymbolByVA(Address, EnumVal, &Symbol)) {
ULONGLONG LoadAddr = 0;
ULONGLONG LoadAddr = 0;
if (S_OK != Session->get_loadAddress(&LoadAddr))
if (S_OK != Session->get_loadAddress(&LoadAddr))
return nullptr;
return nullptr;
DWORD RVA = static_cast<DWORD>(Address - LoadAddr);
DWORD RVA = static_cast<DWORD>(Address - LoadAddr);
if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol))
if (S_OK != Session->findSymbolByRVA(RVA, EnumVal, &Symbol))
return nullptr;
return nullptr;
}
}
auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, Symbol);
auto RawSymbol = llvm::make_unique<DIARawSymbol>(*this, Symbol);
return PDBSymbol::create(*this, std::move(RawSymbol));
return PDBSymbol::create(*this, std::move(RawSymbol));
}
}


std::unique_ptr<IPDBEnumLineNumbers>
std::unique_ptr<IPDBEnumLineNumbers>
DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland,
DIASession::findLineNumbers(const PDBSymbolCompiland &Compiland,
const IPDBSourceFile &File) const {
const IPDBSourceFile &File) const {
const DIARawSymbol &RawCompiland =
const DIARawSymbol &RawCompiland =
static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File);
const DIASourceFile &RawFile = static_cast<const DIASourceFile &>(File);


CComPtr<IDiaEnumLineNumbers> LineNumbers;
CComPtr<IDiaEnumLineNumbers> LineNumbers;
if (S_OK !=
if (S_OK !=
Session->findLines(RawCompiland.getDiaSymbol(), RawFile.getDiaFile(),
Session->findLines(RawCompiland.getDiaSymbol(), RawFile.getDiaFile(),
&LineNumbers))
&LineNumbers))
return nullptr;
return nullptr;


return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
}
}


std::unique_ptr<IPDBEnumLineNumbers>
std::unique_ptr<IPDBEnumLineNumbers>
DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {
DIASession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const {
CComPtr<IDiaEnumLineNumbers> LineNumbers;
CComPtr<IDiaEnumLineNumbers> LineNumbers;
if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers))
if (S_OK != Session->findLinesByVA(Address, Length, &LineNumbers))
return nullptr;
return nullptr;


return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
return llvm::make_unique<DIAEnumLineNumbers>(LineNumbers);
}
}


std::unique_ptr<IPDBEnumSourceFiles>
std::unique_ptr<IPDBEnumSourceFiles>
DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland,
DIASession::findSourceFiles(const PDBSymbolCompiland *Compiland,
llvm::StringRef Pattern,
llvm::StringRef Pattern,
PDB_NameSearchFlags Flags) const {
PDB_NameSearchFlags Flags) const {
IDiaSymbol *DiaCompiland = nullptr;
IDiaSymbol *DiaCompiland = nullptr;
CComBSTR Utf16Pattern;
CComBSTR Utf16Pattern;
if (!Pattern.empty())
if (!Pattern.empty())
Utf16Pattern = CComBSTR(Pattern.data());
Utf16Pattern = CComBSTR(Pattern.data());


if (Compiland)
if (Compiland)
DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol())
DiaCompiland = static_cast<const DIARawSymbol &>(Compiland->getRawSymbol())
.getDiaSymbol();
.getDiaSymbol();


Flags = static_cast<PDB_NameSearchFlags>(
Flags = static_cast<PDB_NameSearchFlags>(
Flags | PDB_NameSearchFlags::NS_FileNameExtMatch);
Flags | PDB_NameSearchFlags::NS_FileNameExtMatch);
CComPtr<IDiaEnumSourceFiles> SourceFiles;
CComPtr<IDiaEnumSourceFiles> SourceFiles;
if (S_OK !=
if (S_OK !=
Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles))
Session->findFile(DiaCompiland, Utf16Pattern.m_str, Flags, &SourceFiles))
return nullptr;
return nullptr;
return llvm::make_unique<DIAEnumSourceFiles>(*this, SourceFiles);
return llvm::make_unique<DIAEnumSourceFiles>(*this, SourceFiles);
}
}


std::unique_ptr<IPDBSourceFile>
std::unique_ptr<IPDBSourceFile>
DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
DIASession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
llvm::StringRef Pattern,
llvm::StringRef Pattern,
PDB_NameSearchFlags Flags) const {
PDB_NameSearchFlags Flags) const {
auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags);
auto SourceFiles = findSourceFiles(Compiland, Pattern, Flags);
if (!SourceFiles || SourceFiles->getChildCount() == 0)
if (!SourceFiles || SourceFiles->getChildCount() == 0)
return nullptr;
return nullptr;
return SourceFiles->getNext();
return SourceFiles->getNext();
}
}


std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern,
DIASession::findCompilandsForSourceFile(llvm::StringRef Pattern,
PDB_NameSearchFlags Flags) const {
PDB_NameSearchFlags Flags) const {
auto File = findOneSourceFile(nullptr, Pattern, Flags);
auto File = findOneSourceFile(nullptr, Pattern, Flags);
if (!File)
if (!File)
return nullptr;
return nullptr;
return File->getCompilands();
return File->getCompilands();
}
}


std::unique_ptr<PDBSymbolCompiland>
std::unique_ptr<PDBSymbolCompiland>
DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern,
DIASession::findOneCompilandForSourceFile(llvm::StringRef Pattern,
PDB_NameSearchFlags Flags) const {
PDB_NameSearchFlags Flags) const {
auto Compilands = findCompilandsForSourceFile(Pattern, Flags);
auto Compilands = findCompilandsForSourceFile(Pattern, Flags);
if (!Compilands || Compilands->getChildCount() == 0)
if (!Compilands || Compilands->getChildCount() == 0)
return nullptr;
return nullptr;
return Compilands->getNext();
return Compilands->getNext();
}
}


std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const {
std::unique_ptr<IPDBEnumSourceFiles> DIASession::getAllSourceFiles() const {
CComPtr<IDiaEnumSourceFiles> Files;
CComPtr<IDiaEnumSourceFiles> Files;
if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files))
if (S_OK != Session->findFile(nullptr, nullptr, nsNone, &Files))
return nullptr;
return nullptr;


return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
}
}


std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland(
std::unique_ptr<IPDBEnumSourceFiles> DIASession::getSourceFilesForCompiland(
const PDBSymbolCompiland &Compiland) const {
const PDBSymbolCompiland &Compiland) const {
CComPtr<IDiaEnumSourceFiles> Files;
CComPtr<IDiaEnumSourceFiles> Files;


const DIARawSymbol &RawSymbol =
const DIARawSymbol &RawSymbol =
static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
static_cast<const DIARawSymbol &>(Compiland.getRawSymbol());
if (S_OK !=
if (S_OK !=
Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files))
Session->findFile(RawSymbol.getDiaSymbol(), nullptr, nsNone, &Files))
return nullptr;
return nullptr;


return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
return llvm::make_unique<DIAEnumSourceFiles>(*this, Files);
}
}


std::unique_ptr<IPDBSourceFile>
std::unique_ptr<IPDBSourceFile>
DIASession::getSourceFileById(uint32_t FileId) const {
DIASession::getSourceFileById(uint32_t FileId) const {
CComPtr<IDiaSourceFile> LocatedFile;
CComPtr<IDiaSourceFile> LocatedFile;
if (S_OK != Session->findFileById(FileId, &LocatedFile))
if (S_OK != Session->findFileById(FileId, &LocatedFile))
return nullptr;
return nullptr;


return llvm::make_unique<DIASourceFile>(*this, LocatedFile);
return llvm::make_unique<DIASourceFile>(*this, LocatedFile);
}
}


std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const {
std::unique_ptr<IPDBEnumDataStreams> DIASession::getDebugStreams() const {
CComPtr<IDiaEnumDebugStreams> DiaEnumerator;
CComPtr<IDiaEnumDebugStreams> DiaEnumerator;
if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator))
if (S_OK != Session->getEnumDebugStreams(&DiaEnumerator))
return nullptr;
return nullptr;


return llvm::make_unique<DIAEnumDebugStreams>(DiaEnumerator);
return llvm::make_unique<DIAEnumDebugStreams>(DiaEnumerator);
}
}