[0.2.x] workitem 11665 fixed: work with modules moved to separate module, add load/unload symbols debug events, work with symbol cache moved to separate module

git-svn-id: https://pykd.svn.codeplex.com/svn@83100 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2013-03-28 18:28:42 +00:00 committed by Mikhail I. Izmestev
parent 27fd6ad3b7
commit 342792bc91
11 changed files with 691 additions and 361 deletions

View File

@ -110,6 +110,8 @@ struct DEBUG_EVENT_CALLBACK {
virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64 offset, const std::string &name ) = 0; virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64 offset, const std::string &name ) = 0;
virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0; virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0;
virtual void onExecutionStatusChange( ULONG executionStatus ) = 0; virtual void onExecutionStatusChange( ULONG executionStatus ) = 0;
virtual void onSymbolsLoaded(ULONG64 modBase) = 0;
virtual void onSymbolsUnloaded(ULONG64 modBase OPTIONAL) = 0;
}; };
enum EVENT_TYPE { enum EVENT_TYPE {

View File

@ -27,6 +27,8 @@ private:
virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64 offset, const std::string &name ) = 0; virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64 offset, const std::string &name ) = 0;
virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0; virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0;
virtual void onExecutionStatusChange( ULONG executionStatus ) = 0; virtual void onExecutionStatusChange( ULONG executionStatus ) = 0;
virtual void onSymbolsLoaded(ULONG64 modBase) = 0;
virtual void onSymbolsUnloaded(ULONG64 modBase OPTIONAL) = 0;
}; };
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
@ -57,6 +59,13 @@ public:
void_handler("onExecutionStatusChange", executionStatus ); void_handler("onExecutionStatusChange", executionStatus );
} }
virtual void onSymbolsLoaded(ULONG64 modBase) {
void_handler("onSymbolsLoaded", modBase);
}
virtual void onSymbolsUnloaded(ULONG64 modBase OPTIONAL) {
void_handler("onSymbolsUnloaded", modBase);
}
private: private:

View File

@ -3,15 +3,12 @@
#include "module.h" #include "module.h"
#include "dbgexcept.h" #include "dbgexcept.h"
#include "vardata.h" #include "vardata.h"
#include "symsessioncache.h"
namespace pykd { namespace pykd {
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
Module::SymbolSessionCache Module::m_symSessionCache;
///////////////////////////////////////////////////////////////////////////////////
ModulePtr Module::loadModuleByName( const std::string &moduleName ) ModulePtr Module::loadModuleByName( const std::string &moduleName )
{ {
return ModulePtr( new Module( moduleName ) ); return ModulePtr( new Module( moduleName ) );
@ -55,11 +52,9 @@ SymbolSessionPtr& Module::getSymSession()
if (m_symSession) if (m_symSession)
return m_symSession; return m_symSession;
SymbolMapKey cacheKey = { m_name, m_size, m_timeDataStamp, m_checkSum }; SymCacheModuleKey cacheKey = { m_name, m_size, m_timeDataStamp, m_checkSum };
SymbolSessionCache::iterator found = m_symSessionCache.find( cacheKey ); if ( findSymCacheEntry( cacheKey, m_symSession ) )
if ( found != m_symSessionCache.end() )
{ {
m_symSession = found->second;
if ( !m_symSession ) if ( !m_symSession )
throw SymbolException( "failed to load symbol file" ); throw SymbolException( "failed to load symbol file" );
@ -71,7 +66,7 @@ SymbolSessionPtr& Module::getSymSession()
m_symSession = loadSymbolFile( m_base, m_imageName); m_symSession = loadSymbolFile( m_base, m_imageName);
if (m_symSession) if (m_symSession)
{ {
m_symSessionCache.insert( std::make_pair( cacheKey, m_symSession ) ); insertSymCacheEntry( m_base, cacheKey, m_symSession );
return m_symSession; return m_symSession;
} }
} }
@ -90,7 +85,7 @@ SymbolSessionPtr& Module::getSymSession()
if (m_symSession) if (m_symSession)
{ {
m_symSessionCache.insert( std::make_pair( cacheKey, m_symSession ) ); insertSymCacheEntry( m_base, cacheKey, m_symSession );
return m_symSession; return m_symSession;
} }
} }
@ -102,15 +97,14 @@ SymbolSessionPtr& Module::getSymSession()
m_symSession = loadSymbolFromExports(m_base); m_symSession = loadSymbolFromExports(m_base);
if (m_symSession) if (m_symSession)
{ {
m_symSessionCache.insert( std::make_pair( cacheKey, m_symSession ) ); insertSymCacheEntry( m_base, cacheKey, m_symSession );
return m_symSession; return m_symSession;
} }
} }
catch(const DbgException&) catch(const DbgException&)
{} {}
m_symSessionCache.insert( std::make_pair( cacheKey, SymbolSessionPtr() ) ); insertSymCacheEntry( m_base, cacheKey, SymbolSessionPtr() );
throw SymbolException( "failed to load symbol file" ); throw SymbolException( "failed to load symbol file" );
} }
@ -137,8 +131,8 @@ SymbolPtr Module::getSymScope()
void Module::reloadSymbols() void Module::reloadSymbols()
{ {
SymbolMapKey cacheKey = { m_name, m_size, m_timeDataStamp, m_checkSum }; SymCacheModuleKey cacheKey = { m_name, m_size, m_timeDataStamp, m_checkSum };
m_symSessionCache.erase( cacheKey ); eraseSymCacheEntry( cacheKey );
m_symSession.reset(); m_symSession.reset();
getSymSession(); getSymSession();

View File

@ -24,40 +24,6 @@ public:
static static
ModulePtr loadModuleByOffset( ULONG64 offset ); ModulePtr loadModuleByOffset( ULONG64 offset );
private:
struct SymbolMapKey{
std::string name;
ULONG size;
ULONG timeStamp;
ULONG checkSum;
bool operator < ( const SymbolMapKey& key ) const
{
if ( name < key.name )
return true;
if ( name > key.name )
return false;
if ( size < key.size )
return true;
if ( size > key.size )
return false;
if ( timeStamp < key.timeStamp )
return true;
if ( timeStamp > key.timeStamp )
return false;
return checkSum < key.checkSum;
}
};
typedef std::map<SymbolMapKey,SymbolSessionPtr> SymbolSessionCache;
static SymbolSessionCache m_symSessionCache;
SymbolSessionPtr getFromCache();
public: public:
Module(const std::string &name ); Module(const std::string &name );

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"
@ -441,6 +441,10 @@
RelativePath=".\stkframe.cpp" RelativePath=".\stkframe.cpp"
> >
</File> </File>
<File
RelativePath=".\symsessioncache.cpp"
>
</File>
<File <File
RelativePath=".\typedvar.cpp" RelativePath=".\typedvar.cpp"
> >
@ -527,6 +531,10 @@
RelativePath=".\symengine.h" RelativePath=".\symengine.h"
> >
</File> </File>
<File
RelativePath=".\symsessioncache.h"
>
</File>
<File <File
RelativePath=".\typedvar.h" RelativePath=".\typedvar.h"
> >
@ -581,6 +589,10 @@
RelativePath=".\win\dbgio.h" RelativePath=".\win\dbgio.h"
> >
</File> </File>
<File
RelativePath=".\win\dbgmod.cpp"
>
</File>
<File <File
RelativePath=".\win\lastevent.cpp" RelativePath=".\win\lastevent.cpp"
> >

View File

@ -613,7 +613,13 @@ BOOST_PYTHON_MODULE( pykd )
"For ignore event method must return eventResult.noChange" ) "For ignore event method must return eventResult.noChange" )
.def( "onExecutionStatusChange", &EventHandlerWrap::onExecutionStatusChange, .def( "onExecutionStatusChange", &EventHandlerWrap::onExecutionStatusChange,
"Triggered execution status changed. Parameter - execution status.\n" "Triggered execution status changed. Parameter - execution status.\n"
"There is no return value" ); "There is no return value" )
.def( "onSymbolsLoaded", &EventHandlerWrap::onSymbolsLoaded,
"Triggered debug symbols loaded. Parameter - module base\n"
"There is no return value")
.def( "onSymbolsUnloaded", &EventHandlerWrap::onSymbolsUnloaded,
"Triggered debug symbols unloaded. Parameter - module base or 0 (all modules)\n"
"There is no return value");
// wrapper for standart python exceptions // wrapper for standart python exceptions
python::register_exception_translator<PyException>( &PyException::exceptionTranslate ); python::register_exception_translator<PyException>( &PyException::exceptionTranslate );

193
pykd/symsessioncache.cpp Normal file
View File

@ -0,0 +1,193 @@
//
// Cache of loaded executable module symbols:
// Map: module -> symbol session
//
#include "stdafx.h"
#include "dbgengine.h"
#include "symsessioncache.h"
//////////////////////////////////////////////////////////////////////////////
namespace pykd {
/////////////////////////////////////////////////////////////////////////////////////
class Impl : protected DEBUG_EVENT_CALLBACK {
public:
Impl();
~Impl();
bool find(const SymCacheModuleKey &cacheKey, SymbolSessionPtr &symSession);
void insert(ULONG64 modBase, const SymCacheModuleKey &cacheKey, SymbolSessionPtr symSession);
void erase(const SymCacheModuleKey &cacheKey);
void clear();
protected:
// DEBUG_EVENT_CALLBACK:
virtual DEBUG_CALLBACK_RESULT OnBreakpoint( ULONG ) {
return DebugCallbackNoChange;
}
virtual DEBUG_CALLBACK_RESULT OnModuleLoad( ULONG64, const std::string & ) {
return DebugCallbackNoChange;
}
virtual DEBUG_CALLBACK_RESULT OnModuleUnload( ULONG64, const std::string & );
virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr ) {
return DebugCallbackNoChange;
}
virtual void onExecutionStatusChange( ULONG ) {
}
virtual void onSymbolsLoaded(ULONG64 modBase) {
}
virtual void onSymbolsUnloaded(ULONG64 modBase OPTIONAL);
private:
typedef std::map< ULONG64, SymCacheModuleKey > Base2Key;
Base2Key m_base2Key;
boost::recursive_mutex m_base2KeyLock;
typedef std::map< SymCacheModuleKey, SymbolSessionPtr > Key2Sym;
Key2Sym m_key2Sym;
boost::recursive_mutex m_key2SymLock;
};
/////////////////////////////////////////////////////////////////////////////////////
Impl::Impl()
{
eventRegisterCallbacks(this);
}
/////////////////////////////////////////////////////////////////////////////////////
Impl::~Impl()
{
eventRemoveCallbacks(this);
}
/////////////////////////////////////////////////////////////////////////////////////
DEBUG_CALLBACK_RESULT Impl::OnModuleUnload( ULONG64 modBase, const std::string & )
{
boost::recursive_mutex::scoped_lock l(m_base2KeyLock);
if (modBase)
m_base2Key.erase(modBase);
else
m_base2Key.clear();
return DebugCallbackNoChange;
}
/////////////////////////////////////////////////////////////////////////////////////
void Impl::onSymbolsUnloaded(ULONG64 modBase)
{
if (!modBase)
{
boost::recursive_mutex::scoped_lock l(m_key2SymLock);
m_key2Sym.clear();
return;
}
SymCacheModuleKey cacheKey;
{
boost::recursive_mutex::scoped_lock l(m_base2KeyLock);
Base2Key::const_iterator it = m_base2Key.find(modBase);
if (it == m_base2Key.end())
return;
cacheKey = it->second;
}
boost::recursive_mutex::scoped_lock l(m_key2SymLock);
m_key2Sym.erase(cacheKey);
}
/////////////////////////////////////////////////////////////////////////////////////
namespace
{
Impl &getImpl()
{
// contruct after DebugEngine
static Impl g_Impl;
return g_Impl;
}
}
/////////////////////////////////////////////////////////////////////////////////////
bool findSymCacheEntry(const SymCacheModuleKey &cacheKey, SymbolSessionPtr &symSession)
{
return getImpl().find(cacheKey, symSession);
}
bool Impl::find(const SymCacheModuleKey &cacheKey, SymbolSessionPtr &symSession)
{
boost::recursive_mutex::scoped_lock l(m_key2SymLock);
Key2Sym::const_iterator it = m_key2Sym.find(cacheKey);
if (it == m_key2Sym.end())
{
symSession.reset();
return false;
}
symSession = it->second;
return true;
}
/////////////////////////////////////////////////////////////////////////////////////
void insertSymCacheEntry(ULONG64 modBase, const SymCacheModuleKey &cacheKey, SymbolSessionPtr symSession)
{
return getImpl().insert(modBase, cacheKey, symSession);
}
void Impl::insert(ULONG64 modBase, const SymCacheModuleKey &cacheKey, SymbolSessionPtr symSession)
{
{
boost::recursive_mutex::scoped_lock l(m_base2KeyLock);
m_base2Key[modBase] = cacheKey;
}
{
boost::recursive_mutex::scoped_lock l(m_key2SymLock);
m_key2Sym[cacheKey] = symSession;
}
}
/////////////////////////////////////////////////////////////////////////////////////
void eraseSymCacheEntry(const SymCacheModuleKey &cacheKey)
{
return getImpl().erase(cacheKey);
}
void Impl::erase(const SymCacheModuleKey &cacheKey)
{
boost::recursive_mutex::scoped_lock l(m_key2SymLock);
m_key2Sym.erase(cacheKey);
}
/////////////////////////////////////////////////////////////////////////////////////
void clearSymCache()
{
return getImpl().clear();
}
void Impl::clear()
{
boost::recursive_mutex::scoped_lock l(m_key2SymLock);
m_key2Sym.clear();
}
/////////////////////////////////////////////////////////////////////////////////////
} // namespace pykd
//////////////////////////////////////////////////////////////////////////////

59
pykd/symsessioncache.h Normal file
View File

@ -0,0 +1,59 @@
//
// Cache of loaded executable module symbols:
// Map: module -> symbol session
//
#pragma once
////////////////////////////////////////////////////////////////////////////////
#include "symengine.h"
////////////////////////////////////////////////////////////////////////////////
namespace pykd {
////////////////////////////////////////////////////////////////////////////////
struct SymCacheModuleKey {
std::string name;
ULONG size;
ULONG timeStamp;
ULONG checkSum;
bool operator < ( const SymCacheModuleKey& key ) const
{
if ( name < key.name )
return true;
if ( name > key.name )
return false;
if ( size < key.size )
return true;
if ( size > key.size )
return false;
if ( timeStamp < key.timeStamp )
return true;
if ( timeStamp > key.timeStamp )
return false;
return checkSum < key.checkSum;
}
};
////////////////////////////////////////////////////////////////////////////////
bool findSymCacheEntry(const SymCacheModuleKey &cacheKey, SymbolSessionPtr &symSession);
void insertSymCacheEntry(ULONG64 modBase, const SymCacheModuleKey &cacheKey, SymbolSessionPtr symSession);
void eraseSymCacheEntry(const SymCacheModuleKey &cacheKey);
void clearSymCache();
////////////////////////////////////////////////////////////////////////////////
} // namespace pykd
////////////////////////////////////////////////////////////////////////////////

View File

@ -1,12 +1,12 @@
#include "stdafx.h" #include "stdafx.h"
#include <boost\algorithm\string\case_conv.hpp> #include <boost\algorithm\string\case_conv.hpp>
#include <iomanip>
#include "win/dbgeng.h" #include "win/dbgeng.h"
#include "win/dbgio.h" #include "win/dbgio.h"
#include "dbgexcept.h" #include "dbgexcept.h"
#include "eventhandler.h" #include "eventhandler.h"
#include "symengine.h"
namespace pykd { namespace pykd {
@ -370,310 +370,6 @@ std::string debugCommand( const std::wstring &command )
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
ULONG64 findModuleBase( const std::string &moduleName )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 base;
hres = g_dbgEng->symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &base );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleByModuleName failed" );
return base;
}
///////////////////////////////////////////////////////////////////////////////////
ULONG64 findModuleBase( ULONG64 offset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 base;
ULONG moduleIndex;
hres = g_dbgEng->symbols->GetModuleByOffset( offset, 0, &moduleIndex, &base );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleByOffset failed" );
return base;
}
///////////////////////////////////////////////////////////////////////////////////
ULONG64 findModuleBySymbol( const std::string &symbolName )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 base;
hres = g_dbgEng->symbols->GetSymbolModule( ( std::string("!") + symbolName ).c_str(), &base );
if ( FAILED( hres ) )
{
std::stringstream sstr;
sstr << "failed to find module for symbol: " << symbolName;
throw SymbolException( sstr.str() );
}
return base;
}
///////////////////////////////////////////////////////////////////////////////////
std::string getModuleName( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
char moduleName[0x100];
hres = g_dbgEng->symbols->GetModuleNameString(
DEBUG_MODNAME_MODULE,
DEBUG_ANY_ID,
baseOffset,
moduleName,
sizeof( moduleName ),
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleNameString failed" );
return std::string( moduleName );
}
///////////////////////////////////////////////////////////////////////////////////
std::string getModuleImageName( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
char imageName[0x100];
hres = g_dbgEng->symbols->GetModuleNameString(
DEBUG_MODNAME_IMAGE,
DEBUG_ANY_ID,
baseOffset,
imageName,
sizeof( imageName ),
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleNameString failed" );
return std::string( imageName );
}
///////////////////////////////////////////////////////////////////////////////////
ULONG getModuleSize( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
DEBUG_MODULE_PARAMETERS moduleParam = { 0 };
hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleParameters failed" );
return moduleParam.Size;
}
///////////////////////////////////////////////////////////////////////////////////
std::string getModuleSymbolFileName( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
IMAGEHLP_MODULEW64 moduleInfo = {};
hres = g_dbgEng->advanced->GetSymbolInformation(
DEBUG_SYMINFO_IMAGEHLP_MODULEW64,
baseOffset,
0,
&moduleInfo,
sizeof(moduleInfo),
NULL,
NULL,
0,
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" );
if (!*moduleInfo.LoadedPdbName)
{
std::wstringstream sstr;
sstr << L"/f \"" << moduleInfo.ImageName << L"\"";
hres = g_dbgEng->symbols->ReloadWide( sstr.str().c_str() );
if ( FAILED( hres ) )
throw DbgException("IDebugSymbols::Reload failed" );
hres = g_dbgEng->advanced->GetSymbolInformation(
DEBUG_SYMINFO_IMAGEHLP_MODULEW64,
baseOffset,
0,
&moduleInfo,
sizeof(moduleInfo),
NULL,
NULL,
0,
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" );
}
char pdbName[ 256 ];
WideCharToMultiByte( CP_ACP, 0, moduleInfo.LoadedPdbName, 256, pdbName, 256, NULL, NULL );
return std::string( pdbName );
}
///////////////////////////////////////////////////////////////////////////////////
ULONG getModuleTimeStamp( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
DEBUG_MODULE_PARAMETERS moduleParam = { 0 };
hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleParameters failed" );
return moduleParam.TimeDateStamp;
}
///////////////////////////////////////////////////////////////////////////////////
ULONG getModuleCheckSum( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
DEBUG_MODULE_PARAMETERS moduleParam = { 0 };
hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleParameters failed" );
return moduleParam.Checksum;
}
///////////////////////////////////////////////////////////////////////////////
void getModuleFileVersion( ULONG64 baseOffset, USHORT &majorHigh, USHORT &majorLow, USHORT &minorHigh, USHORT &minorLow )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
VS_FIXEDFILEINFO fileInfo={};
HRESULT hres;
hres = g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
"\\",
(PVOID)&fileInfo,
sizeof(fileInfo),
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" );
majorHigh = HIWORD(fileInfo.dwFileVersionMS);
majorLow = LOWORD(fileInfo.dwFileVersionMS);
minorHigh = HIWORD(fileInfo.dwFileVersionLS);
minorLow = LOWORD(fileInfo.dwFileVersionLS);
}
///////////////////////////////////////////////////////////////////////////////
std::string getModuleVersionInfo( ULONG64 baseOffset, const std::string &value )
{
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
};
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG codePagesSize = 0;
hres = g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
"\\VarFileInfo\\Translation",
NULL,
0,
&codePagesSize );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" );
size_t codePageNum = codePagesSize / sizeof(LANGANDCODEPAGE);
std::vector<LANGANDCODEPAGE> codePages(codePageNum);
hres = g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
"\\VarFileInfo\\Translation",
&codePages[0],
codePagesSize,
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" );
ULONG productNameLength = 0;
std::stringstream sstr;
sstr << "\\StringFileInfo\\" << std::hex
<< std::setw(4) << std::setfill('0') << codePages[0].wLanguage
<< std::setw(4) << std::setfill('0') << codePages[0].wCodePage
<< "\\" << value;
ULONG valueLength;
g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
sstr.str().c_str(),
NULL,
0,
&valueLength );
std::vector<char> valueStr(valueLength);
hres = g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
sstr.str().c_str(),
&valueStr[0],
valueLength,
NULL );
if ( hres == S_OK )
return std::string( &valueStr[0] );
return "";
}
///////////////////////////////////////////////////////////////////////////////
ULONG ptrSize() ULONG ptrSize()
{ {
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
@ -1543,6 +1239,35 @@ HRESULT STDMETHODCALLTYPE DebugEngine::ChangeEngineState(
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::ChangeSymbolState(
__in ULONG Flags,
__in ULONG64 Argument )
{
HandlerList::iterator it;
if (Flags & DEBUG_CSS_LOADS)
{
for ( it = m_handlers.begin(); it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
it->callback->onSymbolsLoaded( Argument );
}
}
if (Flags & DEBUG_CSS_UNLOADS)
{
for ( it = m_handlers.begin(); it != m_handlers.end(); ++it )
{
PyThread_StateSave pyThreadSave( it->pystate );
it->callback->onSymbolsUnloaded( Argument );
}
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE DebugEngine::StartInput( HRESULT STDMETHODCALLTYPE DebugEngine::StartInput(
__in ULONG BufferSize ) __in ULONG BufferSize )
{ {

View File

@ -4,6 +4,7 @@
#include "dbgexcept.h" #include "dbgexcept.h"
#include "pyaux.h" #include "pyaux.h"
#include "eventhandler.h" #include "eventhandler.h"
#include "symsessioncache.h"
#include <dbgeng.h> #include <dbgeng.h>
#include <dbghelp.h> #include <dbghelp.h>
@ -15,7 +16,6 @@ namespace pykd {
class DebugEngine : private DebugBaseEventCallbacks, private IDebugInputCallbacks class DebugEngine : private DebugBaseEventCallbacks, private IDebugInputCallbacks
{ {
public: public:
struct DbgEngBind { struct DbgEngBind {
CComQIPtr<IDebugClient4> client; CComQIPtr<IDebugClient4> client;
@ -78,6 +78,7 @@ public:
*Mask |= DEBUG_EVENT_UNLOAD_MODULE; *Mask |= DEBUG_EVENT_UNLOAD_MODULE;
*Mask |= DEBUG_EVENT_EXCEPTION; *Mask |= DEBUG_EVENT_EXCEPTION;
*Mask |= DEBUG_EVENT_CHANGE_ENGINE_STATE; *Mask |= DEBUG_EVENT_CHANGE_ENGINE_STATE;
*Mask |= DEBUG_EVENT_CHANGE_SYMBOL_STATE;
return S_OK; return S_OK;
} }
@ -106,6 +107,10 @@ public:
__in ULONG Flags, __in ULONG Flags,
__in ULONG64 Argument ); __in ULONG64 Argument );
STDMETHOD(ChangeSymbolState)(
__in ULONG Flags,
__in ULONG64 Argument );
STDMETHOD(StartInput)( STDMETHOD(StartInput)(
__in ULONG BufferSize ); __in ULONG BufferSize );
@ -117,12 +122,12 @@ public:
void registerCallbacks( const DEBUG_EVENT_CALLBACK *callbacks ); void registerCallbacks( const DEBUG_EVENT_CALLBACK *callbacks );
void removeCallbacks( const DEBUG_EVENT_CALLBACK *callbacks ); void removeCallbacks( const DEBUG_EVENT_CALLBACK *callbacks );
DebugEngine() : DebugEngine() :
previousExecutionStatus( DebugStatusNoChange ) previousExecutionStatus( DebugStatusNoChange )
{} {}
private: private:
std::auto_ptr<DbgEngBind> m_bind; std::auto_ptr<DbgEngBind> m_bind;
struct DebugEventContext struct DebugEventContext

359
pykd/win/dbgmod.cpp Normal file
View File

@ -0,0 +1,359 @@
//
// Work with modules
//
///////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "dbgeng.h"
#include <iomanip>
///////////////////////////////////////////////////////////////////////////////
namespace pykd {
///////////////////////////////////////////////////////////////////////////////
ULONG64 findModuleBase( const std::string &moduleName )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 base;
hres = g_dbgEng->symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &base );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleByModuleName failed" );
return base;
}
///////////////////////////////////////////////////////////////////////////////////
ULONG64 findModuleBase( ULONG64 offset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 base;
ULONG moduleIndex;
hres = g_dbgEng->symbols->GetModuleByOffset( offset, 0, &moduleIndex, &base );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleByOffset failed" );
return base;
}
///////////////////////////////////////////////////////////////////////////////////
ULONG64 findModuleBySymbol( const std::string &symbolName )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG64 base;
hres = g_dbgEng->symbols->GetSymbolModule( ( std::string("!") + symbolName ).c_str(), &base );
if ( FAILED( hres ) )
{
std::stringstream sstr;
sstr << "failed to find module for symbol: " << symbolName;
throw SymbolException( sstr.str() );
}
return base;
}
///////////////////////////////////////////////////////////////////////////////////
namespace {
std::string getModuleNameImpl( ULONG64 baseOffset )
{
HRESULT hres;
char moduleName[0x100];
hres = g_dbgEng->symbols->GetModuleNameString(
DEBUG_MODNAME_MODULE,
DEBUG_ANY_ID,
baseOffset,
moduleName,
sizeof( moduleName ),
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleNameString failed" );
return std::string( moduleName );
}
}
std::string getModuleName( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
return getModuleNameImpl( baseOffset );
}
///////////////////////////////////////////////////////////////////////////////////
std::string getModuleImageName( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
char imageName[0x100];
hres = g_dbgEng->symbols->GetModuleNameString(
DEBUG_MODNAME_IMAGE,
DEBUG_ANY_ID,
baseOffset,
imageName,
sizeof( imageName ),
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleNameString failed" );
return std::string( imageName );
}
///////////////////////////////////////////////////////////////////////////////////
namespace {
ULONG getModuleSizeImpl( ULONG64 baseOffset )
{
HRESULT hres;
DEBUG_MODULE_PARAMETERS moduleParam = { 0 };
hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleParameters failed" );
return moduleParam.Size;
}
}
ULONG getModuleSize( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
return getModuleSizeImpl( baseOffset );
}
///////////////////////////////////////////////////////////////////////////////////
std::string getModuleSymbolFileName( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
IMAGEHLP_MODULEW64 moduleInfo = {};
hres = g_dbgEng->advanced->GetSymbolInformation(
DEBUG_SYMINFO_IMAGEHLP_MODULEW64,
baseOffset,
0,
&moduleInfo,
sizeof(moduleInfo),
NULL,
NULL,
0,
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" );
if (!*moduleInfo.LoadedPdbName)
{
std::wstringstream sstr;
sstr << L"/f \"" << moduleInfo.ImageName << L"\"";
hres = g_dbgEng->symbols->ReloadWide( sstr.str().c_str() );
if ( FAILED( hres ) )
throw DbgException("IDebugSymbols::Reload failed" );
hres = g_dbgEng->advanced->GetSymbolInformation(
DEBUG_SYMINFO_IMAGEHLP_MODULEW64,
baseOffset,
0,
&moduleInfo,
sizeof(moduleInfo),
NULL,
NULL,
0,
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugAdvanced2::GetSymbolInformation failed" );
}
char pdbName[ 256 ];
WideCharToMultiByte( CP_ACP, 0, moduleInfo.LoadedPdbName, 256, pdbName, 256, NULL, NULL );
return std::string( pdbName );
}
///////////////////////////////////////////////////////////////////////////////////
namespace{
ULONG getModuleTimeStampImpl( ULONG64 baseOffset )
{
HRESULT hres;
DEBUG_MODULE_PARAMETERS moduleParam = { 0 };
hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleParameters failed" );
return moduleParam.TimeDateStamp;
}
}
ULONG getModuleTimeStamp( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
return getModuleTimeStampImpl( baseOffset );
}
///////////////////////////////////////////////////////////////////////////////////
namespace {
ULONG getModuleCheckSumImpl( ULONG64 baseOffset )
{
HRESULT hres;
DEBUG_MODULE_PARAMETERS moduleParam = { 0 };
hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleParameters failed" );
return moduleParam.Checksum;
}
}
ULONG getModuleCheckSum( ULONG64 baseOffset )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
return getModuleCheckSumImpl( baseOffset );
}
///////////////////////////////////////////////////////////////////////////////
void getModuleFileVersion( ULONG64 baseOffset, USHORT &majorHigh, USHORT &majorLow, USHORT &minorHigh, USHORT &minorLow )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
VS_FIXEDFILEINFO fileInfo={};
HRESULT hres;
hres = g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
"\\",
(PVOID)&fileInfo,
sizeof(fileInfo),
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" );
majorHigh = HIWORD(fileInfo.dwFileVersionMS);
majorLow = LOWORD(fileInfo.dwFileVersionMS);
minorHigh = HIWORD(fileInfo.dwFileVersionLS);
minorLow = LOWORD(fileInfo.dwFileVersionLS);
}
///////////////////////////////////////////////////////////////////////////////
std::string getModuleVersionInfo( ULONG64 baseOffset, const std::string &value )
{
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
};
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG codePagesSize = 0;
hres = g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
"\\VarFileInfo\\Translation",
NULL,
0,
&codePagesSize );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" );
size_t codePageNum = codePagesSize / sizeof(LANGANDCODEPAGE);
std::vector<LANGANDCODEPAGE> codePages(codePageNum);
hres = g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
"\\VarFileInfo\\Translation",
&codePages[0],
codePagesSize,
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol2::GetModuleVersionInformation failed" );
ULONG productNameLength = 0;
std::stringstream sstr;
sstr << "\\StringFileInfo\\" << std::hex
<< std::setw(4) << std::setfill('0') << codePages[0].wLanguage
<< std::setw(4) << std::setfill('0') << codePages[0].wCodePage
<< "\\" << value;
ULONG valueLength;
g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
sstr.str().c_str(),
NULL,
0,
&valueLength );
std::vector<char> valueStr(valueLength);
hres = g_dbgEng->symbols->GetModuleVersionInformation(
DEBUG_ANY_ID,
baseOffset,
sstr.str().c_str(),
&valueStr[0],
valueLength,
NULL );
if ( hres == S_OK )
return std::string( &valueStr[0] );
return "";
}
///////////////////////////////////////////////////////////////////////////////
} // namespace pykd
///////////////////////////////////////////////////////////////////////////////