[0.2.x] ~ref: dia symbol loader

git-svn-id: https://pykd.svn.codeplex.com/svn@80119 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2012-10-09 10:57:57 +00:00 committed by Mikhail I. Izmestev
parent 4cb4014242
commit 6c9444877d
3 changed files with 259 additions and 177 deletions

203
pykd/dia/diaload.cpp Normal file
View File

@ -0,0 +1,203 @@
//
// Load debug symbols using DIA
//
#include "stdafx.h"
#include "dbghelp.h"
#include "dia/diawrapper.h"
#include "win/utils.h"
#include "dbgengine.h"
#include "diacallback.h"
//////////////////////////////////////////////////////////////////////////////////
namespace pykd {
//////////////////////////////////////////////////////////////////////////////////
namespace diaLoad {
//////////////////////////////////////////////////////////////////////////////////
// DIA data source loader
interface IDataProvider
{
virtual ~IDataProvider() {}
virtual HRESULT load(__inout IDiaDataSource &DiaDataSource) = 0;
};
//////////////////////////////////////////////////////////////////////////////////
// Load debug symbols using DIA
static SymbolSessionPtr createSession(
IDataProvider &DataProvider,
ULONGLONG loadBase
)
{
HRESULT hres;
DiaDataSourcePtr dataSource;
hres = dataSource.CoCreateInstance(__uuidof(DiaSource), NULL, CLSCTX_INPROC_SERVER);
if ( S_OK != hres )
throw DiaException("Call ::CoCreateInstance", hres);
hres = DataProvider.load(*dataSource);
if ( S_OK != hres )
throw DiaException("Call IDiaDataSource::loadDataXxx", hres);
DiaSessionPtr _session;
hres = dataSource->openSession(&_session);
if ( S_OK != hres )
throw DiaException("Call IDiaDataSource::openSession", hres);
hres = _session->put_loadAddress(loadBase);
if (S_OK != hres)
throw DiaException("Call IDiaSession::put_loadAddress", hres);
DiaSymbolPtr _globalScope;
hres = _session->get_globalScope(&_globalScope);
if ( S_OK != hres )
throw DiaException("Call IDiaSymbol::get_globalScope", hres);
return SymbolSessionPtr( new DiaSession( _session, _globalScope ) );
}
//////////////////////////////////////////////////////////////////////////////////
// Load debug symbols using symbol file
class DataFromPdb : public IDataProvider {
std::wstring m_filePath;
public:
DataFromPdb(__in const std::string &filePath) {
m_filePath = toWStr(filePath);
}
virtual HRESULT load(__inout IDiaDataSource &dataSource) override {
return dataSource.loadDataFromPdb( m_filePath.c_str() );
}
};
// Access to executable file over RVA-callback
class ReadExeAtRVACallback : public IDiaReadExeAtRVACallback {
ULONGLONG m_loadBase;
int m_nRefCount;
CComPtr< IDiaLoadCallback2 > m_diaLoadCallback2;
public:
ReadExeAtRVACallback(
__in ULONGLONG loadBase,
__out std::string &openedSymbolFile
) : m_loadBase(loadBase), m_nRefCount(1)
, m_diaLoadCallback2( new DiaLoadCallback2(&openedSymbolFile) )
{
}
// IUnknown impl
ULONG STDMETHODCALLTYPE AddRef() {
m_nRefCount++;
return m_nRefCount;
}
ULONG STDMETHODCALLTYPE Release() {
const int nRefCount = (--m_nRefCount);
if (!nRefCount)
delete this;
return nRefCount;
}
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID rid, void **ppUnk ) {
if ( ppUnk == NULL )
return E_INVALIDARG;
if (rid == __uuidof(IDiaReadExeAtRVACallback))
{
*ppUnk = this;
return S_OK;
}
return m_diaLoadCallback2->QueryInterface(rid, ppUnk);
}
// IDiaReadExeAtRVACallback impl
virtual HRESULT STDMETHODCALLTYPE ReadExecutableAtRVA(
/* [in] */ DWORD relativeVirtualAddress,
/* [in] */ DWORD cbData,
/* [out] */ DWORD *pcbData,
/* [size_is][out] */ BYTE *pbData
) override {
return
readMemoryImpl(
m_loadBase + relativeVirtualAddress,
pbData,
cbData,
pcbData);
}
};
// Load debug symbols using ReadExeAtRVACallback
struct DataForExeByRva : IDataProvider {
std::string m_openedSymbolFile;
DataForExeByRva(
__in ULONGLONG loadBase,
__in const std::string &executable,
__in const std::string &symbolSearchPath
) : m_loadBase(loadBase)
{
m_executable = toWStr(executable);
if (symbolSearchPath.empty())
m_symbolSearchPath = toWStr( getSymbolPath() );
else
m_symbolSearchPath = toWStr( symbolSearchPath );
}
virtual HRESULT load(__inout IDiaDataSource &dataSource) override {
CComPtr< IUnknown > readExeAtRVACallback(new ReadExeAtRVACallback(m_loadBase, m_openedSymbolFile) );
return
dataSource.loadDataForExe(
m_executable.c_str(),
m_symbolSearchPath.c_str(),
readExeAtRVACallback);
}
protected:
ULONGLONG m_loadBase;
std::wstring m_executable;
std::wstring m_symbolSearchPath;
};
//////////////////////////////////////////////////////////////////////////////////
} // namespace diaLoad
//////////////////////////////////////////////////////////////////////////////////
SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase )
{
diaLoad::DataFromPdb dataFromPdb(filePath);
return diaLoad::createSession(dataFromPdb, loadBase);
}
//////////////////////////////////////////////////////////////////////////////////
SymbolSessionPtr loadSymbolFile(
__in ULONGLONG loadBase,
__in const std::string &executable,
__out std::string &loadedSymbolFile,
__in_opt std::string symbolSearchPath /*= std::string()*/
)
{
diaLoad::DataForExeByRva dataForExeByRva(loadBase, executable, symbolSearchPath);
SymbolSessionPtr symSession = diaLoad::createSession(dataForExeByRva, loadBase);
loadedSymbolFile = dataForExeByRva.m_openedSymbolFile;
return symSession;
}
//////////////////////////////////////////////////////////////////////////////////
} // namespace pykd

View File

@ -3,8 +3,6 @@
#include "dbghelp.h" #include "dbghelp.h"
#include "dia/diawrapper.h" #include "dia/diawrapper.h"
#include "win/utils.h" #include "win/utils.h"
#include "dbgengine.h"
#include "diacallback.h"
namespace pykd { namespace pykd {
@ -92,6 +90,38 @@ std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres, ID
} }
sstream << "Return value is 0x" << std::hex << hres; sstream << "Return value is 0x" << std::hex << hres;
switch (hres)
{
#define _CASE_DIA_ERROR(x) case E_PDB_##x: sstream << ": E_PDB_" #x << std::endl; break
_CASE_DIA_ERROR(USAGE);
_CASE_DIA_ERROR(OUT_OF_MEMORY);
_CASE_DIA_ERROR(FILE_SYSTEM);
_CASE_DIA_ERROR(NOT_FOUND);
_CASE_DIA_ERROR(INVALID_SIG);
_CASE_DIA_ERROR(INVALID_AGE);
_CASE_DIA_ERROR(PRECOMP_REQUIRED);
_CASE_DIA_ERROR(OUT_OF_TI);
_CASE_DIA_ERROR(NOT_IMPLEMENTED);
_CASE_DIA_ERROR(V1_PDB);
_CASE_DIA_ERROR(FORMAT);
_CASE_DIA_ERROR(LIMIT);
_CASE_DIA_ERROR(CORRUPT);
_CASE_DIA_ERROR(TI16);
_CASE_DIA_ERROR(ACCESS_DENIED);
_CASE_DIA_ERROR(ILLEGAL_TYPE_EDIT);
_CASE_DIA_ERROR(INVALID_EXECUTABLE);
_CASE_DIA_ERROR(DBG_NOT_FOUND);
_CASE_DIA_ERROR(NO_DEBUG_INFO);
_CASE_DIA_ERROR(INVALID_EXE_TIMESTAMP);
_CASE_DIA_ERROR(RESERVED);
_CASE_DIA_ERROR(DEBUG_INFO_NOT_IN_PDB);
_CASE_DIA_ERROR(SYMSRV_BAD_CACHE_PATH);
_CASE_DIA_ERROR(SYMSRV_CACHE_FULL);
#undef _CASE_DIA_ERROR
default:
{
PCHAR errMessage = NULL; PCHAR errMessage = NULL;
FormatMessageA( FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
@ -111,6 +141,8 @@ std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres, ID
{ {
sstream << std::endl; sstream << std::endl;
} }
}
}
return sstream.str(); return sstream.str();
} }
@ -120,163 +152,6 @@ std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres, ID
#define callSymbol(method) \ #define callSymbol(method) \
callSymbolT( &IDiaSymbol::##method, #method) callSymbolT( &IDiaSymbol::##method, #method)
////////////////////////////////////////////////////////////////////////////////
interface IDiaLoadDataImpl
{
virtual ~IDiaLoadDataImpl() {}
virtual HRESULT load(__inout IDiaDataSource &DiaDataSource) = 0;
};
////////////////////////////////////////////////////////////////////////////////
static SymbolSessionPtr loadDebugSymbols(
IDiaLoadDataImpl &LoadDataImpl,
ULONGLONG loadBase
)
{
HRESULT hres;
DiaDataSourcePtr dataSource;
hres = dataSource.CoCreateInstance(__uuidof(DiaSource), NULL, CLSCTX_INPROC_SERVER);
if ( S_OK != hres )
throw DiaException("Call ::CoCreateInstance", hres);
hres = LoadDataImpl.load(*dataSource);
if ( S_OK != hres )
throw DiaException("Call IDiaDataSource::loadDataXxx", hres);
DiaSessionPtr _session;
hres = dataSource->openSession(&_session);
if ( S_OK != hres )
throw DiaException("Call IDiaDataSource::openSession", hres);
hres = _session->put_loadAddress(loadBase);
if (S_OK != hres)
throw DiaException("Call IDiaSession::put_loadAddress", hres);
DiaSymbolPtr _globalScope;
hres = _session->get_globalScope(&_globalScope);
if ( S_OK != hres )
throw DiaException("Call IDiaSymbol::get_globalScope", hres);
return SymbolSessionPtr( new DiaSession( _session, _globalScope ) );
}
////////////////////////////////////////////////////////////////////////////////
SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase )
{
struct LoadDataFromPdb : IDiaLoadDataImpl, boost::noncopyable
{
const std::string &m_filePath;
LoadDataFromPdb(const std::string &filePath) : m_filePath(filePath) {}
virtual HRESULT load(__inout IDiaDataSource &dataSource) override
{
return dataSource.loadDataFromPdb( toWStr(m_filePath) );
}
};
LoadDataFromPdb loadDataFromPdb(filePath);
return loadDebugSymbols(loadDataFromPdb, loadBase);
}
//////////////////////////////////////////////////////////////////////////////////
SymbolSessionPtr loadSymbolFile(
__in ULONGLONG loadBase,
__in const std::string &executable,
__out std::string &loadedSymbolFile,
__in_opt std::string symbolSearchPath /*= std::string()*/
)
{
if (symbolSearchPath.empty())
symbolSearchPath = getSymbolPath();
class ReadExeAtRVACallback : public IDiaReadExeAtRVACallback
{
ULONGLONG m_loadBase;
int m_nRefCount;
CComPtr< IDiaLoadCallback2 > m_diaLoadCallback2;
public:
ReadExeAtRVACallback(ULONGLONG loadBase, std::string &openedSymbolFile)
: m_loadBase(loadBase), m_nRefCount(1), m_diaLoadCallback2(new DiaLoadCallback2(&openedSymbolFile))
{
}
ULONG STDMETHODCALLTYPE AddRef() {
m_nRefCount++;
return m_nRefCount;
}
ULONG STDMETHODCALLTYPE Release() {
const int nRefCount = (--m_nRefCount);
if (!nRefCount)
delete this;
return nRefCount;
}
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID rid, void **ppUnk ) {
if ( ppUnk == NULL )
return E_INVALIDARG;
if (rid == __uuidof(IDiaReadExeAtRVACallback))
{
*ppUnk = this;
return S_OK;
}
return m_diaLoadCallback2->QueryInterface(rid, ppUnk);
}
virtual HRESULT STDMETHODCALLTYPE ReadExecutableAtRVA(
/* [in] */ DWORD relativeVirtualAddress,
/* [in] */ DWORD cbData,
/* [out] */ DWORD *pcbData,
/* [size_is][out] */ BYTE *pbData
) override
{
return
readMemoryImpl(
m_loadBase + relativeVirtualAddress,
pbData,
cbData,
pcbData);
}
};
struct LoadDataForExeByRva : IDiaLoadDataImpl, boost::noncopyable
{
ULONGLONG m_loadBase;
const std::string &m_executable;
const std::string &m_symbolSearchPath;
std::string m_openedSymbolFile;
LoadDataForExeByRva(ULONGLONG loadBase, const std::string &executable, std::string symbolSearchPath)
: m_loadBase(loadBase), m_executable(executable), m_symbolSearchPath(symbolSearchPath)
{
}
virtual HRESULT load(__inout IDiaDataSource &dataSource) override
{
CComPtr< IUnknown > readExeAtRVACallback(new ReadExeAtRVACallback(m_loadBase, m_openedSymbolFile) );
return
dataSource.loadDataForExe(
toWStr(m_executable),
toWStr(m_symbolSearchPath),
readExeAtRVACallback);
}
};
LoadDataForExeByRva loadDataForExeByRva(loadBase, executable, symbolSearchPath);
SymbolSessionPtr symSession = loadDebugSymbols(loadDataForExeByRva, loadBase);
loadedSymbolFile = loadDataForExeByRva.m_openedSymbolFile;
return symSession;
}
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
std::string getBasicTypeName( ULONG basicType ) std::string getBasicTypeName( ULONG basicType )

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="windows-1251"?> <?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject <VisualStudioProject
ProjectType="Visual C++" ProjectType="Visual C++"
Version="9,00" Version="9.00"
Name="pykd" Name="pykd"
ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}" ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}"
RootNamespace="pykd" RootNamespace="pykd"
@ -617,6 +617,10 @@
RelativePath=".\dia\diadata.cpp" RelativePath=".\dia\diadata.cpp"
> >
</File> </File>
<File
RelativePath=".\dia\diaload.cpp"
>
</File>
<File <File
RelativePath=".\dia\diawrapper.cpp" RelativePath=".\dia\diawrapper.cpp"
> >