diff --git a/pykd/dbgmem.h b/pykd/dbgmem.h index 46c8e76..9203e1c 100644 --- a/pykd/dbgmem.h +++ b/pykd/dbgmem.h @@ -5,6 +5,7 @@ namespace pykd { /////////////////////////////////////////////////////////////////////////////////// ULONG64 addr64( ULONG64 offset ); +HRESULT readMemoryImpl(ULONG64 offset, PVOID buffer, ULONG length, ULONG *readed = NULL, bool phyAddr = false); void readMemory( ULONG64 offset, PVOID buffer, ULONG length, bool phyAddr = FALSE ); bool isVaValid( ULONG64 addr ); bool compareMemory( ULONG64 addr1, ULONG64 addr2, ULONG length, bool phyAddr = FALSE ); diff --git a/pykd/dia/diacallback.h b/pykd/dia/diacallback.h new file mode 100644 index 0000000..266291b --- /dev/null +++ b/pykd/dia/diacallback.h @@ -0,0 +1,100 @@ +// +// DIA load callback +// + +#pragma once + +namespace pykd { + +class DiaLoadCallback2 : public IDiaLoadCallback2 { + int m_nRefCount; + std::string *m_openedSymbolFile; +public: + DiaLoadCallback2(std::string *openedSymbolFile = NULL) + : m_nRefCount(1), m_openedSymbolFile(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( IDiaLoadCallback2 ) ) + *ppUnk = (IDiaLoadCallback2 *)this; + else if (rid == __uuidof( IDiaLoadCallback ) ) + *ppUnk = (IDiaLoadCallback *)this; + else if (rid == __uuidof( IUnknown ) ) + *ppUnk = (IUnknown *)this; + else + *ppUnk = NULL; + + if ( *ppUnk != NULL ) { + AddRef(); + return S_OK; + } + return E_NOINTERFACE; + } + + HRESULT STDMETHODCALLTYPE NotifyDebugDir( + BOOL fExecutable, + DWORD cbData, + BYTE data[] + ) + { + DBG_UNREFERENCED_PARAMETER(fExecutable); + DBG_UNREFERENCED_PARAMETER(cbData); + DBG_UNREFERENCED_PARAMETER(data); + return S_OK; + } + HRESULT STDMETHODCALLTYPE NotifyOpenDBG( + LPCOLESTR dbgPath, + HRESULT resultCode + ) + { + if (S_OK == resultCode && m_openedSymbolFile) + *m_openedSymbolFile = autoBstr::asStr((BSTR)dbgPath); + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE NotifyOpenPDB( + LPCOLESTR pdbPath, + HRESULT resultCode + ) + { + if (S_OK == resultCode && m_openedSymbolFile) + *m_openedSymbolFile = autoBstr::asStr((BSTR)pdbPath); + + return S_OK; + } + HRESULT STDMETHODCALLTYPE RestrictRegistryAccess() { + return S_OK; + } + HRESULT STDMETHODCALLTYPE RestrictSymbolServerAccess() { + return S_OK; + } + HRESULT STDMETHODCALLTYPE RestrictOriginalPathAccess() { + return S_OK; + } + HRESULT STDMETHODCALLTYPE RestrictReferencePathAccess() { + return S_OK; + } + HRESULT STDMETHODCALLTYPE RestrictDBGAccess() { + return S_OK; + } + HRESULT STDMETHODCALLTYPE RestrictSystemRootAccess() { + return S_OK; + } +}; + +} diff --git a/pykd/dia/diawrapper.cpp b/pykd/dia/diawrapper.cpp index b1c7f63..7ba5c82 100644 --- a/pykd/dia/diawrapper.cpp +++ b/pykd/dia/diawrapper.cpp @@ -3,6 +3,8 @@ #include "dbghelp.h" #include "dia/diawrapper.h" #include "win/utils.h" +#include "dbgengine.h" +#include "diacallback.h" namespace pykd { @@ -120,7 +122,18 @@ std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres, ID //////////////////////////////////////////////////////////////////////////////// -SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase ) +interface IDiaLoadDataImpl +{ + virtual ~IDiaLoadDataImpl() {} + virtual HRESULT load(__inout IDiaDataSource &DiaDataSource) = 0; +}; + +//////////////////////////////////////////////////////////////////////////////// + +static SymbolSessionPtr loadDebugSymbols( + IDiaLoadDataImpl &LoadDataImpl, + ULONGLONG loadBase +) { HRESULT hres; DiaDataSourcePtr dataSource; @@ -130,9 +143,9 @@ SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase if ( S_OK != hres ) throw DiaException("Call ::CoCreateInstance", hres); - hres = dataSource->loadDataFromPdb( toWStr(filePath) ); + hres = LoadDataImpl.load(*dataSource); if ( S_OK != hres ) - throw DiaException("Call IDiaDataSource::loadDataFromPdb", hres); + throw DiaException("Call IDiaDataSource::loadDataXxx", hres); DiaSessionPtr _session; hres = dataSource->openSession(&_session); @@ -151,6 +164,119 @@ SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase 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) + { + } + + HRESULT STDMETHODCALLTYPE 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 ) diff --git a/pykd/module.cpp b/pykd/module.cpp index ac5e69c..e1b4569 100644 --- a/pykd/module.cpp +++ b/pykd/module.cpp @@ -22,7 +22,6 @@ Module::Module(const std::string &moduleName ) { m_base = findModuleBase( moduleName ); m_name = moduleName; - m_symfile = getModuleSymbolFileName( m_base ); m_imageName = getModuleImageName( m_base ); m_timeDataStamp = getModuleTimeStamp( m_base ); m_checkSum = getModuleCheckSum( m_base ); @@ -35,7 +34,6 @@ Module::Module(ULONG64 offset ) { m_base = findModuleBase( addr64(offset) ); m_name = getModuleName( m_base ); - m_symfile = getModuleSymbolFileName( m_base ); m_imageName = getModuleImageName( m_base ); m_timeDataStamp = getModuleTimeStamp( m_base ); m_checkSum = getModuleCheckSum( m_base ); @@ -46,20 +44,15 @@ Module::Module(ULONG64 offset ) SymbolSessionPtr& Module::getSymSession() { - do { - - if ( m_symSession ) - return m_symSession; - - if ( m_symfile.empty() ) - break; - - m_symSession = loadSymbolFile( m_symfile, m_base ); - - } while( false ); + m_symSession = loadSymbolFile(m_base, m_imageName, m_symfile); if ( !m_symSession ) - throw SymbolException( "failed to find symbol file" ); + { + m_symfile = getModuleSymbolFileName(m_base); + m_symSession = loadSymbolFile(m_symfile, m_base); + if (m_symSession) + throw SymbolException( "failed to load symbol file" ); + } return m_symSession; } @@ -75,8 +68,8 @@ SymbolPtr& Module::getSymScope() void Module::reloadSymbols() { - m_symfile = getModuleSymbolFileName( m_base ); m_symSession.reset(); + getSymSession(); } ///////////////////////////////////////////////////////////////////////////////////// @@ -114,6 +107,8 @@ std::string Module::print() { std::stringstream sstr; + prepareSymbolFile(); + sstr << "Module: " << m_name << std::endl; sstr << "Start: " << std::hex << m_base << " End: " << getEnd() << " Size: " << m_size << std::endl; sstr << "Image: " << m_imageName << std::endl; @@ -248,6 +243,19 @@ std::string Module::getSourceFile( ULONG64 offset ) return fileName; } +void Module::prepareSymbolFile() +{ + try + { + // load symbols for modules, if need + getSymSession(); + } + catch (const SymbolException &e) + { + DBG_UNREFERENCED_LOCAL_VARIABLE(e); + } +} + /////////////////////////////////////////////////////////////////////////////////// }; // end of namespace pykd diff --git a/pykd/module.h b/pykd/module.h index 12d2abf..3a9842a 100644 --- a/pykd/module.h +++ b/pykd/module.h @@ -46,7 +46,8 @@ public: return m_size; } - std::string getSymFile() const { + std::string getSymFile() { + prepareSymbolFile(); return m_symfile; } @@ -116,6 +117,8 @@ private: ULONG getRvaByName(const std::string &symName); + void prepareSymbolFile(); + std::string m_name; std::string m_imageName; std::string m_symfile; diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index 480f8e5..aebc749 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -1,7 +1,7 @@ + + diff --git a/pykd/symengine.h b/pykd/symengine.h index 996a06c..c05beba 100644 --- a/pykd/symengine.h +++ b/pykd/symengine.h @@ -172,7 +172,14 @@ public: std::string getBasicTypeName( ULONG basicType ); -SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase = 0); +SymbolSessionPtr loadSymbolFile(const std::string &filePath, ULONGLONG loadBase = 0); + +SymbolSessionPtr loadSymbolFile( + __in ULONGLONG loadBase, + __in const std::string &executable, + __out std::string &loadedSymbolFile, + __in_opt std::string symbolSearchPath = std::string() +); //////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/win/memory.cpp b/pykd/win/memory.cpp index 5a534bd..528c033 100644 --- a/pykd/win/memory.cpp +++ b/pykd/win/memory.cpp @@ -65,12 +65,9 @@ bool isVaValid( ULONG64 addr ) /////////////////////////////////////////////////////////////////////////////////// -void readMemory( ULONG64 offset, PVOID buffer, ULONG length, bool phyAddr ) +HRESULT readMemoryImpl(ULONG64 offset, PVOID buffer, ULONG length, ULONG *readed, bool phyAddr) { - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - + HRESULT hres; if ( phyAddr == false ) { offset = addr64NoSafe( offset ); @@ -81,13 +78,24 @@ void readMemory( ULONG64 offset, PVOID buffer, ULONG length, bool phyAddr ) DBG_UNREFERENCED_LOCAL_VARIABLE(nextAddress); - hres = g_dbgEng->dataspace->ReadVirtual( offset, buffer, length, NULL ); + hres = g_dbgEng->dataspace->ReadVirtual( offset, buffer, length, readed ); } else { - hres = g_dbgEng->dataspace->ReadPhysical( offset, buffer, length, NULL ); + hres = g_dbgEng->dataspace->ReadPhysical( offset, buffer, length, readed ); } + return hres; +} + +/////////////////////////////////////////////////////////////////////////////////// + +void readMemory( ULONG64 offset, PVOID buffer, ULONG length, bool phyAddr ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres = readMemoryImpl(offset, buffer, length, NULL, phyAddr); + if ( FAILED( hres ) ) throw MemoryException( offset, phyAddr ); }