[+] add callback for load/unload modules

git-svn-id: https://pykd.svn.codeplex.com/svn@65709 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2011-05-22 23:55:20 +00:00
parent 77300508e7
commit 6e2d161966
10 changed files with 364 additions and 69 deletions

View File

@ -7,6 +7,7 @@
#include "dbgmodule.h" #include "dbgmodule.h"
#include "dbgsynsym.h" #include "dbgsynsym.h"
#include "dbgcmd.h" #include "dbgcmd.h"
#include "dbgmodevent.h"
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
@ -51,7 +52,11 @@ HRESULT DbgEventCallbacksManager::GetInterestMask(
__out PULONG Mask __out PULONG Mask
) )
{ {
*Mask = DEBUG_EVENT_CHANGE_SYMBOL_STATE | DEBUG_EVENT_BREAKPOINT; *Mask =
DEBUG_EVENT_CHANGE_SYMBOL_STATE |
DEBUG_EVENT_BREAKPOINT |
DEBUG_EVENT_LOAD_MODULE |
DEBUG_EVENT_UNLOAD_MODULE;
return S_OK; return S_OK;
} }
@ -66,27 +71,25 @@ HRESULT DbgEventCallbacksManager::ChangeSymbolState(
{ {
if (Argument) if (Argument)
{ {
DEBUG_MODULE_PARAMETERS dbgModuleParameters={}; DEBUG_MODULE_PARAMETERS dbgModuleParameters;
HRESULT hres = dbgExt->symbols3->GetModuleParameters( HRESULT hres = dbgExt->symbols3->GetModuleParameters(
1, 1,
&Argument, &Argument,
0, 0,
&dbgModuleParameters); &dbgModuleParameters);
if (SUCCEEDED(hres)) if (SUCCEEDED(hres))
{ {
ModuleInfo moduleInfo(dbgModuleParameters); ModuleInfo moduleInfo(dbgModuleParameters);
restoreSyntheticSymbolForModule(moduleInfo); restoreSyntheticSymbolForModule(moduleInfo);
} }
return S_OK; return S_OK;
} }
//// f.e. is case ".reload /f image.exe", if for image.exe no symbols //// f.e. is case ".reload /f image.exe", if for image.exe no symbols
restoreSyntheticSymbolForAllModules(); restoreSyntheticSymbolForAllModules();
return S_OK; return S_OK;
} }
@ -100,7 +103,45 @@ HRESULT DbgEventCallbacksManager::Breakpoint(
) )
{ {
return dbgBreakpointClass::onBreakpointEvnet( bp ); return dbgBreakpointClass::onBreakpointEvnet( bp );
} }
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
HRESULT DbgEventCallbacksManager::LoadModule(
__in ULONG64 ImageFileHandle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in PCSTR ModuleName,
__in PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp
)
{
try
{
return moduleEvents::onLoadModule(BaseOffset);
}
catch (std::exception &)
{
}
return DEBUG_STATUS_NO_CHANGE;
}
///////////////////////////////////////////////////////////////////////////////////
HRESULT DbgEventCallbacksManager::UnloadModule(
__in PCSTR ImageBaseName,
__in ULONG64 BaseOffset
)
{
try
{
return moduleEvents::onUnloadModule(BaseOffset);
}
catch (std::exception &)
{
}
return DEBUG_STATUS_NO_CHANGE;
}
///////////////////////////////////////////////////////////////////////////////////

View File

@ -25,19 +25,33 @@ private:
STDMETHOD(GetInterestMask)( STDMETHOD(GetInterestMask)(
__out PULONG Mask __out PULONG Mask
); );
STDMETHOD(ChangeSymbolState)( STDMETHOD(ChangeSymbolState)(
__in ULONG Flags, __in ULONG Flags,
__in ULONG64 Argument __in ULONG64 Argument
); );
STDMETHOD(Breakpoint)( STDMETHOD(Breakpoint)(
__in PDEBUG_BREAKPOINT Bp __in PDEBUG_BREAKPOINT Bp
); );
STDMETHOD(LoadModule)(
__in ULONG64 ImageFileHandle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in PCSTR ModuleName,
__in PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp
);
STDMETHOD(UnloadModule)(
__in PCSTR ImageBaseName,
__in ULONG64 BaseOffset
);
private: private:
IDebugClient *m_debugClient; IDebugClient *m_debugClient;
}; };

View File

@ -28,6 +28,7 @@
#include "dbgprocess.h" #include "dbgprocess.h"
#include "dbgsynsym.h" #include "dbgsynsym.h"
#include "dbgclient.h" #include "dbgclient.h"
#include "dbgmodevent.h"
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -221,7 +222,7 @@ BOOST_PYTHON_MODULE( pykd )
boost::python::class_<dbgModuleClass>( "dbgModuleClass", boost::python::class_<dbgModuleClass>( "dbgModuleClass",
"Class representing module in the target memory" ) "Class representing module in the target memory" )
.def("begin", &dbgModuleClass::getBegin, .def("begin", &dbgModuleClass::getBegin,
"Return start address of the module" ) "Return start address of the module" )
.def("end", &dbgModuleClass::getEnd, .def("end", &dbgModuleClass::getEnd,
"Return end address of the module" ) "Return end address of the module" )
.def("size", &dbgModuleClass::getSize, .def("size", &dbgModuleClass::getSize,
@ -249,7 +250,7 @@ BOOST_PYTHON_MODULE( pykd )
"Return address of the symbol" ) "Return address of the symbol" )
.def("__str__", &dbgModuleClass::print, .def("__str__", &dbgModuleClass::print,
"Return a nice string represention of the dbgModuleClass" ); "Return a nice string represention of the dbgModuleClass" );
boost::python::class_<dbgExtensionClass>( boost::python::class_<dbgExtensionClass>(
"ext", "ext",
"windbg extension wrapper", "windbg extension wrapper",
@ -275,7 +276,7 @@ BOOST_PYTHON_MODULE( pykd )
boost::python::class_<dbgOut>( "windbgOut", "windbgOut" ) boost::python::class_<dbgOut>( "windbgOut", "windbgOut" )
.def( "write", &dbgOut::write ); .def( "write", &dbgOut::write );
boost::python::class_<dbgIn>( "windbgIn", "windbgIn" ) boost::python::class_<dbgIn>( "windbgIn", "windbgIn" )
.def( "readline", &dbgIn::readline ); .def( "readline", &dbgIn::readline );
boost::python::class_<dbgBreakpointClass>( "bp", boost::python::class_<dbgBreakpointClass>( "bp",
"Class representing breakpoint", "Class representing breakpoint",
boost::python::init<ULONG64,boost::python::object&>( boost::python::args("offset", "callback"), boost::python::init<ULONG64,boost::python::object&>( boost::python::args("offset", "callback"),
@ -287,6 +288,15 @@ BOOST_PYTHON_MODULE( pykd )
.def( "__str__", &dbgBreakpointClass::print, .def( "__str__", &dbgBreakpointClass::print,
"Return a nice string represention of the breakpoint class" ); "Return a nice string represention of the breakpoint class" );
boost::python::class_<moduleEventsWrap, boost::noncopyable>( "modEvents",
"Class for processing of events: loading and unloading modules" )
.def( "onLoad", &moduleEvents::onLoad, &moduleEventsWrap::onLoadDef,
"Load module event. Parameter is instance of dbgModuleClass. "
"For ignore event method must return DEBUG_STATUS_NO_CHANGE value" )
.def( "onUnload", &moduleEvents::onUnload, &moduleEventsWrap::onUnloadDef,
"Unload module event. Parameter is instance of dbgModuleClass. "
"For ignore event method must return DEBUG_STATUS_NO_CHANGE value" );
// debug status // debug status
_DEF_PY_CONST(DEBUG_STATUS_NO_CHANGE); _DEF_PY_CONST(DEBUG_STATUS_NO_CHANGE);
_DEF_PY_CONST(DEBUG_STATUS_GO); _DEF_PY_CONST(DEBUG_STATUS_GO);

108
pykd/dbgmodevent.cpp Normal file
View File

@ -0,0 +1,108 @@
/////////////////////////////////////////////////////////////////////////////////
// Load/Unload module events
/////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "dbgeng.h"
#include "dbgmodule.h"
#include "dbgmodevent.h"
/////////////////////////////////////////////////////////////////////////////////
moduleEvents::modCallbacksColl moduleEvents::modCallbacks;
moduleEvents::modCallbacksLock moduleEvents::modCallbacksMtx;
/////////////////////////////////////////////////////////////////////////////////
moduleEvents::moduleEvents()
{
modCallbacksScopedLock lock(modCallbacksMtx);
modCallbacks.insert(this);
}
/////////////////////////////////////////////////////////////////////////////////
moduleEvents::~moduleEvents()
{
modCallbacksScopedLock lock(modCallbacksMtx);
modCallbacks.erase(this);
}
/////////////////////////////////////////////////////////////////////////////////
ULONG moduleEvents::onLoadModule(__in ULONG64 addr)
{
modCallbacksScopedLock lock(modCallbacksMtx);
if (modCallbacks.empty())
return DEBUG_STATUS_NO_CHANGE;
ULONG64 moduleBase;
ULONG moduleSize;
std::string moduleName;
queryModuleParams(addr, moduleName, moduleBase, moduleSize);
dbgModuleClass module(moduleName, moduleBase, moduleSize);
modCallbacksColl::iterator itCallback = modCallbacks.begin();
while (itCallback != modCallbacks.end())
{
const ULONG retValue = (*itCallback)->onLoad(module);
if (DEBUG_STATUS_NO_CHANGE != retValue)
return retValue;
++itCallback;
}
return DEBUG_STATUS_NO_CHANGE;
}
/////////////////////////////////////////////////////////////////////////////////
ULONG moduleEvents::onUnloadModule(__in ULONG64 addr)
{
modCallbacksScopedLock lock(modCallbacksMtx);
if (modCallbacks.empty())
return DEBUG_STATUS_NO_CHANGE;
ULONG64 moduleBase;
ULONG moduleSize;
std::string moduleName;
queryModuleParams(addr, moduleName, moduleBase, moduleSize);
dbgModuleClass module(moduleName, moduleBase, moduleSize);
modCallbacksColl::iterator itCallback = modCallbacks.begin();
while (itCallback != modCallbacks.end())
{
const ULONG retValue = (*itCallback)->onUnload(module);
if (DEBUG_STATUS_NO_CHANGE != retValue)
return retValue;
++itCallback;
}
return DEBUG_STATUS_NO_CHANGE;
}
/////////////////////////////////////////////////////////////////////////////////
ULONG moduleEventsWrap::onLoad(
const dbgModuleClass &module
)
{
if (boost::python::override override = get_override("onLoad"))
return override(module);
return moduleEvents::onLoad(module);
}
/////////////////////////////////////////////////////////////////////////////////
ULONG moduleEventsWrap::onUnload(
const dbgModuleClass &module
)
{
if (boost::python::override override = get_override("onUnload"))
return override(module);
return moduleEvents::onUnload(module);
}
/////////////////////////////////////////////////////////////////////////////////

53
pykd/dbgmodevent.h Normal file
View File

@ -0,0 +1,53 @@
/////////////////////////////////////////////////////////////////////////////////
// Load/Unload module events
/////////////////////////////////////////////////////////////////////////////////
#include <set>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
interface moduleEvents
{
moduleEvents();
virtual ~moduleEvents();
virtual ULONG onLoad(const dbgModuleClass &/* module */)
{
return DEBUG_STATUS_NO_CHANGE;
}
virtual ULONG onUnload(const dbgModuleClass &/* module */)
{
return DEBUG_STATUS_NO_CHANGE;
}
static ULONG onLoadModule(__in ULONG64 addr);
static ULONG onUnloadModule(__in ULONG64 addr);
private:
typedef std::set<moduleEvents *> modCallbacksColl;
static modCallbacksColl modCallbacks;
typedef boost::interprocess::interprocess_recursive_mutex modCallbacksLock;
static modCallbacksLock modCallbacksMtx;
typedef boost::interprocess::scoped_lock<modCallbacksLock> modCallbacksScopedLock;
};
// python wrapper for moduleEvents
struct moduleEventsWrap : moduleEvents, boost::python::wrapper<moduleEvents>
{
ULONG onLoad(const dbgModuleClass &module);
ULONG onLoadDef(const dbgModuleClass &module)
{
return moduleEvents::onLoad(module);
}
ULONG onUnload(const dbgModuleClass &module);
ULONG onUnloadDef(const dbgModuleClass &module)
{
return moduleEvents::onUnload(module);
}
};
/////////////////////////////////////////////////////////////////////////////////

View File

@ -47,61 +47,82 @@ loadModule( const std::string &moduleName )
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
void queryModuleParams(
__in ULONG64 addr,
__out std::string &name,
__out ULONG64 &base,
__out ULONG &size
)
{
addr = addr64( addr );
ULONG moduleIndex;
HRESULT hres =
dbgExt->symbols->GetModuleByOffset( addr, 0, &moduleIndex, &base);
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleByOffset failed" );
DEBUG_MODULE_PARAMETERS moduleParam = { 0 };
hres = dbgExt->symbols->GetModuleParameters( 1, &base, 0, &moduleParam );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleParameters failed" );
size = moduleParam.Size;
ULONG moduleNameChars = 0;
dbgExt->symbols->GetModuleNames(
moduleIndex,
0,
NULL,
0,
NULL,
NULL,
0,
&moduleNameChars,
NULL,
0,
NULL );
name.resize(moduleNameChars + 1);
hres = dbgExt->symbols->GetModuleNames(
moduleIndex,
0,
NULL,
0,
NULL,
&name[0],
(ULONG)name.size(),
NULL,
NULL,
0,
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleNames failed" );
}
/////////////////////////////////////////////////////////////////////////////////
boost::python::object boost::python::object
findModule( ULONG64 addr ) findModule( ULONG64 addr )
{ {
HRESULT hres;
addr = addr64( addr );
try { try {
ULONG64 moduleBase;
ULONG moduleIndex; ULONG moduleSize;
ULONG64 moduleBase; std::string moduleName;
hres = dbgExt->symbols->GetModuleByOffset( addr, 0, &moduleIndex, &moduleBase ); queryModuleParams(addr, moduleName, moduleBase, moduleSize);
return
if ( FAILED( hres ) ) boost::python::object(
{ dbgModuleClass( moduleName, moduleBase, moduleSize )
return boost::python::object(); );
}
DEBUG_MODULE_PARAMETERS moduleParam = { 0 };
hres = dbgExt->symbols->GetModuleParameters( 1, &moduleBase, 0, &moduleParam );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleParameters failed" );
char moduleName[0x100];
hres =
dbgExt->symbols->GetModuleNames(
moduleIndex,
0,
NULL,
0,
NULL,
moduleName,
sizeof( moduleName ),
NULL,
NULL,
0,
NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugSymbol::GetModuleNames failed" );
return boost::python::object( dbgModuleClass( moduleName, moduleBase, moduleParam.Size ) );
} }
catch( std::exception &e ) catch( std::exception &e )
{ {
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() ); dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd error: %s\n", e.what() );
} }
catch(...) catch(...)
{ {
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" ); dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "pykd unexpected error\n" );
} }
return boost::python::object(); return boost::python::object();
} }
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////

View File

@ -162,6 +162,14 @@ private:
boost::python::object boost::python::object
loadModule( const std::string &moduleName ); loadModule( const std::string &moduleName );
// query module parameters (for construct dbgModuleClass) by virtual address
// error : DbgException exception
void queryModuleParams(
__in ULONG64 addr,
__out std::string &name,
__out ULONG64 &base,
__out ULONG &size
);
boost::python::object boost::python::object
findModule( ULONG64 addr ); findModule( ULONG64 addr );

View File

@ -376,6 +376,10 @@
RelativePath=".\dbgmem.cpp" RelativePath=".\dbgmem.cpp"
> >
</File> </File>
<File
RelativePath=".\dbgmodevent.cpp"
>
</File>
<File <File
RelativePath=".\dbgmodule.cpp" RelativePath=".\dbgmodule.cpp"
> >
@ -494,6 +498,10 @@
RelativePath=".\dbgmem.h" RelativePath=".\dbgmem.h"
> >
</File> </File>
<File
RelativePath=".\dbgmodevent.h"
>
</File>
<File <File
RelativePath=".\dbgmodule.h" RelativePath=".\dbgmodule.h"
> >

View File

@ -78,7 +78,6 @@
GenerateDebugInformation="true" GenerateDebugInformation="true"
SubSystem="2" SubSystem="2"
TargetMachine="1" TargetMachine="1"
Profile="true"
/> />
<Tool <Tool
Name="VCALinkTool" Name="VCALinkTool"
@ -159,7 +158,6 @@
GenerateDebugInformation="true" GenerateDebugInformation="true"
SubSystem="2" SubSystem="2"
TargetMachine="17" TargetMachine="17"
Profile="true"
/> />
<Tool <Tool
Name="VCALinkTool" Name="VCALinkTool"
@ -367,6 +365,10 @@
RelativePath=".\dbgmem.cpp" RelativePath=".\dbgmem.cpp"
> >
</File> </File>
<File
RelativePath=".\dbgmodevent.cpp"
>
</File>
<File <File
RelativePath=".\dbgmodule.cpp" RelativePath=".\dbgmodule.cpp"
> >
@ -485,6 +487,10 @@
RelativePath=".\dbgmem.h" RelativePath=".\dbgmem.h"
> >
</File> </File>
<File
RelativePath=".\dbgmodevent.h"
>
</File>
<File <File
RelativePath=".\dbgmodule.h" RelativePath=".\dbgmodule.h"
> >

26
samples/goLoad.py Normal file
View File

@ -0,0 +1,26 @@
"""
Wait (execute) for load target module
"""
from pykd import *
import fnmatch
import sys
class modLoad(modEvents):
def __init__(self, mask):
modEvents.__init__(self)
self.mask = mask
def onLoad(self, module):
if fnmatch.fnmatch( module.name(), self.mask ):
return DEBUG_STATUS_BREAK
return DEBUG_STATUS_NO_CHANGE
if __name__ == "__main__":
if len(sys.argv) == 2:
loadHandler = modLoad( sys.argv[1] )
go()
else:
dprintln( "Wait (execute) for load target module\nInvalid command line" )
dprintln( "Using" + sys.argv[0] + " <MOD_FILE_NAME>" )
dprintln( "\tMOD_FILE_NAME - name of target module with wildcard" )