From 0107a6cb1f9e644c970c7faac1a0336ff623bcd0 Mon Sep 17 00:00:00 2001 From: "SND\\EreTIk_cp" Date: Mon, 23 Jan 2012 22:00:00 +0000 Subject: [PATCH] [0.1.x] + exception/breakpoint handling test for separate client + eventHandler catch python exception git-svn-id: https://pykd.svn.codeplex.com/svn@73527 9b283d60-5439-405e-af05-b73fd8c4d996 --- pykd/dbgevent.cpp | 335 ++++---------------------------- pykd/dbgevent.h | 176 +++-------------- pykd/dbgext.cpp | 83 +++++--- test/scripts/ehexcepttest.py | 65 +++++++ test/scripts/pykdtest.py | 6 +- test/targetapp/targetapp.vcproj | 4 + 6 files changed, 185 insertions(+), 484 deletions(-) create mode 100644 test/scripts/ehexcepttest.py diff --git a/pykd/dbgevent.cpp b/pykd/dbgevent.cpp index 0644d59..3817522 100644 --- a/pykd/dbgevent.cpp +++ b/pykd/dbgevent.cpp @@ -1,15 +1,18 @@ -/////////////////////////////////////////////////////////////////////////////////// -//// Load/Unload module events -/////////////////////////////////////////////////////////////////////////////////// -// +//////////////////////////////////////////////////////////////////////////////// +// User-customizing debug event handler +//////////////////////////////////////////////////////////////////////////////// + #include "stdafx.h" #include "dbgevent.h" #include "dbgclient.h" +//////////////////////////////////////////////////////////////////////////////// + +std::wstring fetchPythonExceptionStrings( python::object &tracebackModule ); namespace pykd { -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// EventHandler::EventHandler() { @@ -26,7 +29,7 @@ EventHandler::EventHandler() m_parentClient = g_dbgClient; } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// EventHandler::EventHandler( DebugClientPtr &client ) { @@ -43,14 +46,14 @@ EventHandler::EventHandler( DebugClientPtr &client ) m_parentClient = client; } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// EventHandler::~EventHandler() { m_handlerClient->SetEventCallbacks( NULL ); } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// HRESULT EventHandler::GetInterestMask( __out PULONG Mask @@ -67,79 +70,24 @@ HRESULT EventHandler::GetInterestMask( return S_OK; } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// HRESULT EventHandler::Breakpoint( __in PDEBUG_BREAKPOINT Bp ) { -// boost::python::dict bpParameters; -// -// HRESULT hres; -// ULONG Value = 0; -// ULONG Value2 = 0; -// ULONG64 Value64 = 0; -// std::string str; -// -//#define _ADD_BP_ULONG(x) \ -// hres = Bp->Get##x(&Value); \ -// BOOST_ASSERT( SUCCEEDED( hres ) || hres == E_NOINTERFACE ); \ -// if (SUCCEEDED( hres )) \ -// bpParameters[#x] = Value; -// -//#define _ADD_BP_ULONG2(x, n1, n2) \ -// hres = Bp->Get##x(&Value, &Value2); \ -// BOOST_ASSERT( SUCCEEDED( hres ) || hres == E_NOINTERFACE ); \ -// if (SUCCEEDED( hres )) \ -// { \ -// bpParameters[n1] = Value; bpParameters[n2] = Value2; \ -// } -// -//#define _ADD_BP_ULONG64(x) \ -// hres = Bp->Get##x(&Value64); \ -// BOOST_ASSERT( SUCCEEDED( hres ) || hres == E_NOINTERFACE ); \ -// if (SUCCEEDED( hres )) \ -// bpParameters[#x] = Value64; -// -//#define _ADD_BP_STR(x) \ -// Value = 0; \ -// Bp->Get##x(NULL, 0, &Value); \ -// if (Value) \ -// { \ -// str.resize(Value + 1); \ -// BOOST_VERIFY( SUCCEEDED( \ -// Bp->Get##x(&str[0], (ULONG)str.size(), NULL) \ -// ) ); \ -// if (!str.empty()) bpParameters[#x] = str.c_str(); \ -// } -// -// _ADD_BP_ULONG(Id); -// _ADD_BP_ULONG2(Type, "BreakType", "ProcType"); -// _ADD_BP_ULONG(Flags); -// _ADD_BP_ULONG64(Offset); -// _ADD_BP_ULONG2(DataParameters, "Size", "AccessType"); -// _ADD_BP_ULONG(PassCount); -// _ADD_BP_ULONG(CurrentPassCount); -// _ADD_BP_ULONG(MatchThreadId); -// _ADD_BP_STR(Command); -// _ADD_BP_STR(OffsetExpression); -// -//#undef _ADD_BP_ULONG -//#undef _ADD_BP_ULONG2 -//#undef _ADD_BP_ULONG64 -//#undef _ADD_BP_STR -// - //PyThread_StateSave pyThreadSave; + ULONG Id; + HRESULT hres = Bp->GetId(&Id); + if (S_OK == hres) + { + PyThread_StateSave pyThreadSave( m_parentClient->getThreadState() ); + return onBreakpoint(Id); + } - boost::python::dict bpParameters; - - return onBreakpoint( bpParameters ); - - //onException(bpParameters); - //return S_OK; + return DEBUG_STATUS_NO_CHANGE; } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// HRESULT EventHandler::Exception( __in PEXCEPTION_RECORD64 Exception, @@ -151,7 +99,7 @@ HRESULT EventHandler::Exception( // build list of parameters for (ULONG i = 0; i < Exception->NumberParameters; ++i) - exceptParams.append(Exception->ExceptionInformation[i]); + exceptParams.append( Exception->ExceptionInformation[i] ); exceptData["Code"] = Exception->ExceptionCode; exceptData["Flags"] = Exception->ExceptionFlags; @@ -165,7 +113,7 @@ HRESULT EventHandler::Exception( return onException(exceptData); } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// HRESULT EventHandler::LoadModule( __in ULONG64 ImageFileHandle, @@ -181,7 +129,7 @@ HRESULT EventHandler::LoadModule( return onLoadModule( m_parentClient->loadModuleByOffset(BaseOffset) ); } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// HRESULT EventHandler::UnloadModule( __in PCSTR ImageBaseName, @@ -193,7 +141,7 @@ HRESULT EventHandler::UnloadModule( return onUnloadModule( BaseOffset ); } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// HRESULT EventHandler::SessionStatus( __in ULONG Status @@ -205,7 +153,7 @@ HRESULT EventHandler::SessionStatus( return S_OK; } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// HRESULT EventHandler::ChangeDebuggeeState( __in ULONG Flags, @@ -218,229 +166,14 @@ HRESULT EventHandler::ChangeDebuggeeState( return S_OK; } -/////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +void EventHandlerWrap::onHandlerException() +{ + // TODO: some logging, alerting.... +} + +//////////////////////////////////////////////////////////////////////////////// }; // end pykd namespace - - - - - - - - - - -//#include "dbgevent.h" -//#include "dbgio.h" -//#include "dbgexcept.h" -//#include "pyaux.h" -// -///////////////////////////////////////////////////////////////////////////////////// -// -//debugEvent::debugEvent() -//{ -// HRESULT hres; -// -// hres = dbgExt->client->CreateClient( &m_debugClient ); -// if ( FAILED( hres ) ) -// throw DbgException( "IDebugClient::CreateClient" ); -// -// hres = m_debugClient->SetEventCallbacks(this); -// if (FAILED(hres)) -// throw DbgException( "IDebugClient::SetEventCallbacks" ); -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// -//debugEvent::~debugEvent() -//{ -// m_debugClient->SetEventCallbacks( NULL ); -// -// m_debugClient->Release(); -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// -//HRESULT debugEvent::GetInterestMask( -// __out PULONG Mask -//) -//{ -// *Mask = 0; -// -// *Mask |= DEBUG_EVENT_LOAD_MODULE; -// *Mask |= DEBUG_EVENT_UNLOAD_MODULE; -// *Mask |= DEBUG_EVENT_SESSION_STATUS; -// *Mask |= DEBUG_EVENT_EXCEPTION; -// *Mask |= DEBUG_EVENT_BREAKPOINT; -// -// return S_OK; -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// -//HRESULT debugEvent::Breakpoint( -// __in PDEBUG_BREAKPOINT Bp -//) -//{ -// boost::python::dict bpParameters; -// -// HRESULT hres; -// ULONG Value = 0; -// ULONG Value2 = 0; -// ULONG64 Value64 = 0; -// std::string str; -// -//#define _ADD_BP_ULONG(x) \ -// hres = Bp->Get##x(&Value); \ -// BOOST_ASSERT( SUCCEEDED( hres ) || hres == E_NOINTERFACE ); \ -// if (SUCCEEDED( hres )) \ -// bpParameters[#x] = Value; -// -//#define _ADD_BP_ULONG2(x, n1, n2) \ -// hres = Bp->Get##x(&Value, &Value2); \ -// BOOST_ASSERT( SUCCEEDED( hres ) || hres == E_NOINTERFACE ); \ -// if (SUCCEEDED( hres )) \ -// { \ -// bpParameters[n1] = Value; bpParameters[n2] = Value2; \ -// } -// -//#define _ADD_BP_ULONG64(x) \ -// hres = Bp->Get##x(&Value64); \ -// BOOST_ASSERT( SUCCEEDED( hres ) || hres == E_NOINTERFACE ); \ -// if (SUCCEEDED( hres )) \ -// bpParameters[#x] = Value64; -// -//#define _ADD_BP_STR(x) \ -// Value = 0; \ -// Bp->Get##x(NULL, 0, &Value); \ -// if (Value) \ -// { \ -// str.resize(Value + 1); \ -// BOOST_VERIFY( SUCCEEDED( \ -// Bp->Get##x(&str[0], (ULONG)str.size(), NULL) \ -// ) ); \ -// if (!str.empty()) bpParameters[#x] = str.c_str(); \ -// } -// -// _ADD_BP_ULONG(Id); -// _ADD_BP_ULONG2(Type, "BreakType", "ProcType"); -// _ADD_BP_ULONG(Flags); -// _ADD_BP_ULONG64(Offset); -// _ADD_BP_ULONG2(DataParameters, "Size", "AccessType"); -// _ADD_BP_ULONG(PassCount); -// _ADD_BP_ULONG(CurrentPassCount); -// _ADD_BP_ULONG(MatchThreadId); -// _ADD_BP_STR(Command); -// _ADD_BP_STR(OffsetExpression); -// -//#undef _ADD_BP_ULONG -//#undef _ADD_BP_ULONG2 -//#undef _ADD_BP_ULONG64 -//#undef _ADD_BP_STR -// -// PyThread_StateSave pyThreadSave; -// return onException(bpParameters); -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// -//HRESULT debugEvent::Exception( -// __in PEXCEPTION_RECORD64 Exception, -// __in ULONG FirstChance -//) -//{ -// boost::python::list exceptParams; -// boost::python::dict exceptData; -// -// // build list of parameters -// for (ULONG i = 0; i < Exception->NumberParameters; ++i) -// exceptParams.append(Exception->ExceptionInformation[i]); -// -// // build dict of exception data -//#define _ADD_EXCEPTION_ENTRY(x) exceptData[#x] = Exception->Exception##x -// _ADD_EXCEPTION_ENTRY(Code); -// _ADD_EXCEPTION_ENTRY(Flags); -// _ADD_EXCEPTION_ENTRY(Record); -// _ADD_EXCEPTION_ENTRY(Address); -//#undef _ADD_EXCEPTION_ENTRY -// -// exceptData["Parameters"] = exceptParams; -// -// exceptData["FirstChance"] = (0 != FirstChance); -// -// PyThread_StateSave pyThreadSave; -// return onException(exceptData); -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// -//HRESULT debugEvent::LoadModule( -// __in ULONG64 ImageFileHandle, -// __in ULONG64 BaseOffset, -// __in ULONG ModuleSize, -// __in PCSTR ModuleName, -// __in PCSTR ImageName, -// __in ULONG CheckSum, -// __in ULONG TimeDateStamp -//) -//{ -// std::auto_ptr silentMode( new OutputReader(dbgExt->client) ); -// -// ULONG64 moduleBase; -// ULONG moduleSize; -// std::string moduleName; -// -// queryModuleParams(BaseOffset, moduleName, moduleBase, moduleSize); -// dbgModuleClass module(moduleName, moduleBase, moduleSize); -// silentMode.reset(); -// -// PyThread_StateSave pyThreadSave; -// return onLoadModule( module ); -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// -//HRESULT debugEvent::UnloadModule( -// __in PCSTR ImageBaseName, -// __in ULONG64 BaseOffset -//) -//{ -// std::auto_ptr silentMode( new OutputReader(dbgExt->client) ); -// -// ULONG64 moduleBase; -// ULONG moduleSize; -// std::string moduleName; -// -// queryModuleParams(BaseOffset, moduleName, moduleBase, moduleSize); -// dbgModuleClass module(moduleName, moduleBase, moduleSize); -// silentMode.reset(); -// -// PyThread_StateSave pyThreadSave; -// return onUnloadModule( module ); -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// -//HRESULT debugEvent::SessionStatus( -// __in ULONG Status -//) -//{ -// PyThread_StateSave pyThreadSave; -// return onChangeSessionStatus( Status ); -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// -//HRESULT debugEvent::ChangeDebuggeeState( -// __in ULONG Flags, -// __in ULONG64 Argument -//) -//{ -// PyThread_StateSave pyThreadSave; -// return onChangeDebugeeState(); -//} -// -///////////////////////////////////////////////////////////////////////////////////// -// diff --git a/pykd/dbgevent.h b/pykd/dbgevent.h index d20a127..b8d1a18 100644 --- a/pykd/dbgevent.h +++ b/pykd/dbgevent.h @@ -1,6 +1,6 @@ -///////////////////////////////////////////////////////////////////////////////// -// user-customizing debug event handler -///////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// User-customizing debug event handler +//////////////////////////////////////////////////////////////////////////////// #pragma once @@ -13,7 +13,7 @@ namespace pykd { -///////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// class EventHandler : public DebugBaseEventCallbacks { @@ -69,7 +69,7 @@ protected: protected: - virtual ULONG onBreakpoint(const python::dict &/*bpParameters*/) = 0; + virtual ULONG onBreakpoint(ULONG Id) = 0; virtual ULONG onException(const python::dict &/*exceptData*/) = 0; @@ -88,7 +88,7 @@ protected: DebugClientPtr m_parentClient; }; -///////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// class EventHandlerWrap : public python::wrapper, public EventHandler { @@ -101,8 +101,8 @@ public: EventHandlerWrap( DebugClientPtr &client ) : EventHandler( client ) {} - ULONG onBreakpoint(const python::dict &bpParameters) { - return handler("onBreakpoint", bpParameters); + ULONG onBreakpoint(ULONG Id) { + return handler("onBreakpoint", Id); } ULONG onException(const python::dict &exceptData) { @@ -125,163 +125,41 @@ public: return handler( "onChangeDebugeeState" ); } + void onHandlerException(); + private: template ULONG handler( const char* handlerName, Arg1Type arg1 ) { if (python::override pythonHandler = get_override( handlerName )) - return pythonHandler(arg1); - + { + try { + return pythonHandler(arg1); + } + catch (const python::error_already_set &) { + onHandlerException(); + } + } return DEBUG_STATUS_NO_CHANGE; } ULONG handler( const char* handlerName ) { if (python::override pythonHandler = get_override( handlerName )) - return pythonHandler(); + { + try { + return pythonHandler(); + } + catch (const python::error_already_set &) { + onHandlerException(); + } + } return DEBUG_STATUS_NO_CHANGE; } }; -///////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// }; // end namespace pykd - - - - - - - - - - - - -//#include "dbgeventcb.h" -//#include "dbgmodule.h" -//#include "pyaux.h" -// -/////////////////////////////////////////////////////////////////////////////////// -// -//class debugEvent : public DebugBaseEventCallbacks -//{ -//public: -// -// debugEvent(); -// -// virtual ~debugEvent(); -// -// virtual ULONG onBreakpoint(boost::python::dict &/*bpParameters*/) = 0; -// -// virtual ULONG onException(boost::python::dict &/*exceptData*/) = 0; -// -// virtual ULONG onLoadModule(const dbgModuleClass &/* module */) = 0; -// -// virtual ULONG onUnloadModule(const dbgModuleClass &/* module */) = 0; -// -// virtual ULONG onChangeSessionStatus( ULONG status ) = 0; -// -// virtual ULONG onChangeDebugeeState() = 0; -// -//private: -// -// STDMETHOD_(ULONG, AddRef)() { return 1; } -// STDMETHOD_(ULONG, Release)() { return 1; } -// -// STDMETHOD(GetInterestMask)( -// __out PULONG Mask -// ); -// -// STDMETHOD(Breakpoint)( -// __in PDEBUG_BREAKPOINT Bp -// ); -// -// -// STDMETHOD(Exception)( -// __in PEXCEPTION_RECORD64 Exception, -// __in ULONG FirstChance -// ); -// -// 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 -// ); -// -// STDMETHOD(SessionStatus)( -// __in ULONG Status -// ); -// -// STDMETHOD(ChangeDebuggeeState)( -// __in ULONG Flags, -// __in ULONG64 Argument ); -// -//private: -// -// IDebugClient *m_debugClient; -//}; -// -/////////////////////////////////////////////////////////////////////////////////// -// -//class debugEventWrap : public boost::python::wrapper, public debugEvent -//{ -// -//public: -// -// ULONG onBreakpoint(boost::python::dict &bpParameters) { -// return handler("onBreakpoint", bpParameters); -// } -// -// ULONG onException(boost::python::dict &exceptData) { -// return handler("onException", exceptData); -// } -// -// ULONG onLoadModule(const dbgModuleClass &module) { -// return handler("onLoadModule", module ); -// } -// -// ULONG onUnloadModule(const dbgModuleClass &module) { -// return handler("onUnloadModule", module ); -// } -// -// ULONG onChangeSessionStatus( ULONG status ) { -// return handler( "onChangeSessionStatus", status ); -// } -// -// ULONG onChangeDebugeeState() { -// return handler( "onChangeDebugeeState" ); -// } -// -//private: -// -// template -// ULONG handler( const char* handlerName, Arg1Type arg1 ) -// { -// if (boost::python::override pythonHandler = get_override( handlerName )) -// return pythonHandler(arg1); -// -// return DEBUG_STATUS_NO_CHANGE; -// } -// -// ULONG handler( const char* handlerName ) -// { -// if (boost::python::override pythonHandler = get_override( handlerName )) -// return pythonHandler(); -// -// return DEBUG_STATUS_NO_CHANGE; -// } -//}; -// -/////////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index d47a17b..f10a4c3 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -569,11 +569,7 @@ BOOST_PYTHON_MODULE( pykd ) .def( python::init<>() ) .def( python::init() ) .def( "onBreakpoint", &pykd::EventHandlerWrap::onBreakpoint, - "Triggered breakpoint event. Parameter is dict:\n" - "{\"Id\":int, \"BreakType\":int, \"ProcType\":int, \"Flags\":int, \"Offset\":int," - " \"Size\":int, \"AccessType\":int, \"PassCount\":int, \"CurrentPassCount\":int," - " \"MatchThreadId\":int, \"Command\":str, \"OffsetExpression\":str}\n" - "Detailed information: http://msdn.microsoft.com/en-us/library/ff539284(VS.85).aspx \n" + "Triggered breakpoint event. Parameter is int: ID of breakpoint\n" "For ignore event method must return DEBUG_STATUS_NO_CHANGE value" ) .def( "onException", &pykd::EventHandlerWrap::onException, "Exception event. Parameter is dict:\n" @@ -837,6 +833,30 @@ BOOST_PYTHON_MODULE( pykd ) DEF_PY_CONST_ULONG( DEBUG_USER_WINDOWS_SMALL_DUMP ); DEF_PY_CONST_ULONG( DEBUG_USER_WINDOWS_DUMP ); + // exception codes + DEF_PY_CONST_ULONG(EXCEPTION_ACCESS_VIOLATION); + DEF_PY_CONST_ULONG(EXCEPTION_DATATYPE_MISALIGNMENT); + DEF_PY_CONST_ULONG(EXCEPTION_BREAKPOINT); + DEF_PY_CONST_ULONG(EXCEPTION_SINGLE_STEP); + DEF_PY_CONST_ULONG(EXCEPTION_ARRAY_BOUNDS_EXCEEDED); + DEF_PY_CONST_ULONG(EXCEPTION_FLT_DENORMAL_OPERAND); + DEF_PY_CONST_ULONG(EXCEPTION_FLT_DIVIDE_BY_ZERO); + DEF_PY_CONST_ULONG(EXCEPTION_FLT_INEXACT_RESULT); + DEF_PY_CONST_ULONG(EXCEPTION_FLT_INVALID_OPERATION); + DEF_PY_CONST_ULONG(EXCEPTION_FLT_OVERFLOW); + DEF_PY_CONST_ULONG(EXCEPTION_FLT_STACK_CHECK); + DEF_PY_CONST_ULONG(EXCEPTION_FLT_UNDERFLOW); + DEF_PY_CONST_ULONG(EXCEPTION_INT_DIVIDE_BY_ZERO); + DEF_PY_CONST_ULONG(EXCEPTION_INT_OVERFLOW); + DEF_PY_CONST_ULONG(EXCEPTION_PRIV_INSTRUCTION); + DEF_PY_CONST_ULONG(EXCEPTION_IN_PAGE_ERROR); + DEF_PY_CONST_ULONG(EXCEPTION_ILLEGAL_INSTRUCTION); + DEF_PY_CONST_ULONG(EXCEPTION_NONCONTINUABLE_EXCEPTION); + DEF_PY_CONST_ULONG(EXCEPTION_STACK_OVERFLOW); + DEF_PY_CONST_ULONG(EXCEPTION_INVALID_DISPOSITION); + DEF_PY_CONST_ULONG(EXCEPTION_GUARD_PAGE); + DEF_PY_CONST_ULONG(EXCEPTION_INVALID_HANDLE); + // debug status DEF_PY_CONST_ULONG(DEBUG_STATUS_NO_CHANGE); DEF_PY_CONST_ULONG(DEBUG_STATUS_GO); @@ -859,30 +879,30 @@ BOOST_PYTHON_MODULE( pykd ) //////////////////////////////////////////////////////////////////////////////// WindbgGlobalSession::WindbgGlobalSession() { - + PyImport_AppendInittab("pykd", initpykd ); PyEval_InitThreads(); - Py_Initialize(); + Py_Initialize(); main = boost::python::import("__main__"); - + python::object main_namespace = main.attr("__dict__"); - // делаем аналог from pykd import * + // делаем аналог from pykd import * python::object pykd = boost::python::import( "pykd" ); - + python::dict pykd_namespace( pykd.attr("__dict__") ); - + python::list iterkeys( pykd_namespace.iterkeys() ); - + for (int i = 0; i < boost::python::len(iterkeys); i++) { std::string key = boost::python::extract(iterkeys[i]); - + main_namespace[ key ] = pykd_namespace[ key ]; - } + } pyState = PyEval_SaveThread(); } @@ -941,23 +961,23 @@ py( PDEBUG_CLIENT4 client, PCSTR args ) // настраиваем ввод/вывод ( чтобы в скрипте можно было писать print ) python::object sys = python::import("sys"); - + sys.attr("stdout") = python::object( dbgClient->dout() ); sys.attr("stderr") = python::object( dbgClient->dout() ); sys.attr("stdin") = python::object( dbgClient->din() ); // импортируем модуль обработки исключений ( нужен для вывода traceback а ) boost::python::object tracebackModule = python::import("traceback"); - + // разбор параметров typedef boost::escaped_list_separator char_separator_t; typedef boost::tokenizer< char_separator_t > char_tokenizer_t; - + std::string argsStr( args ); - + char_tokenizer_t token( argsStr , char_separator_t( "", " \t", "\"" ) ); std::vector argsList; - + for ( char_tokenizer_t::iterator it = token.begin(); it != token.end(); ++it ) { if ( *it != "" ) @@ -971,31 +991,31 @@ py( PDEBUG_CLIENT4 client, PCSTR args ) for ( size_t i = 0; i < argsList.size(); ++i ) pythonArgs[i] = const_cast( argsList[i].c_str() ); - + PySys_SetArgv( (int)argsList.size(), pythonArgs ); - delete[] pythonArgs; + delete[] pythonArgs; // найти путь к файлу std::string fullScriptName; - DbgPythonPath dbgPythonPath; + DbgPythonPath dbgPythonPath; if ( !dbgPythonPath.getFullFileName( argsList[0], fullScriptName ) ) { - dbgClient->eprintln( L"script file not found" ); + dbgClient->eprintln( L"script file not found" ); } else - try { - + try { + python::object result; - + result = python::exec_file( fullScriptName.c_str(), global, global ); - } + } catch( boost::python::error_already_set const & ) { // ошибка в скрипте PyObject *errtype = NULL, *errvalue = NULL, *traceback = NULL; - + PyErr_Fetch( &errtype, &errvalue, &traceback ); PyErr_NormalizeException( &errtype, &errvalue, &traceback ); @@ -1013,15 +1033,14 @@ py( PDEBUG_CLIENT4 client, PCSTR args ) for ( long i = 0; i < python::len(lst); ++i ) sstr << std::wstring( python::extract(lst[i]) ) << std::endl; - dbgClient->eprintln( sstr.str() ); - } + } } catch(...) - { + { dbgClient->eprintln( L"unexpected error" ); - } + } Py_EndInterpreter( localInterpreter ); PyThreadState_Swap( globalInterpreter ); diff --git a/test/scripts/ehexcepttest.py b/test/scripts/ehexcepttest.py new file mode 100644 index 0000000..8d8cb52 --- /dev/null +++ b/test/scripts/ehexcepttest.py @@ -0,0 +1,65 @@ +"""Debug events handler: test exceptions and debug breaks""" + +import unittest +import target +import pykd + +class BreakExceptionHandler(pykd.eventHandler): + """Track load/unload module implementation""" + def __init__(self, client): + pykd.eventHandler.__init__(self, client) + + self.client = client + + self.wasSecondChance = False + + self.wasBreakpoint = False + + self.bpLastModuleName = "" + self.bpCount = 0 + + self.firstChanceAccessAddresses = [] + self.secondChanceAccessAddresses = [] + + def onBreakpoint(self, bpId): + """Breakpoint handler""" + self.wasBreakpoint = True + return pykd.DEBUG_STATUS_NO_CHANGE + + def onException(self, exceptParams): + """Exception handler""" + + self.wasSecondChance = not exceptParams["FirstChance"] + + if exceptParams["Code"] == pykd.EXCEPTION_ACCESS_VIOLATION: + if self.wasSecondChance: + print exceptParams["Parameters"] + self.secondChanceAccessAddresses.append( exceptParams["Parameters"][1] ) + else: + self.firstChanceAccessAddresses.append( exceptParams["Parameters"][1] ) + elif exceptParams["Code"] == pykd.EXCEPTION_BREAKPOINT: + self.bpCount += 1 + + return pykd.DEBUG_STATUS_BREAK if self.wasSecondChance else pykd.DEBUG_STATUS_NO_CHANGE + +class EhExceptionBreakpointTest(unittest.TestCase): + """Unit tests of exceptions end breakpoint handling""" + + def testBreakpointException(self): + """Start new process and track exceptions/breakpoints""" + testClient = pykd.createDbgClient() + testClient.startProcess( target.appPath + " -testExceptions" ) + + testClient.dbgCommand( ".reload /f; bp targetapp!doExeptions" ) + + breakExceptionHandler = BreakExceptionHandler( testClient ) + while not breakExceptionHandler.wasSecondChance: + testClient.go() + + self.assertTrue( breakExceptionHandler.wasBreakpoint ) + + self.assertEqual( [2, 3], breakExceptionHandler.firstChanceAccessAddresses ) + + self.assertEqual( 2, breakExceptionHandler.bpCount ) # main and doExeptions + + self.assertEqual( [3, ], breakExceptionHandler.secondChanceAccessAddresses ) diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index ae731de..18bc71f 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -26,6 +26,7 @@ import synsymtest import ehloadtest import thrdctxtest import localstest +import ehexcepttest def getTestSuite( singleName = "" ): if singleName == "": @@ -43,7 +44,8 @@ def getTestSuite( singleName = "" ): unittest.TestLoader().loadTestsFromTestCase( synsymtest.SynSymTest ), unittest.TestLoader().loadTestsFromTestCase( thrdctxtest.ThreadContextTest ), unittest.TestLoader().loadTestsFromTestCase( ehloadtest.EhLoadTest ), - unittest.TestLoader().loadTestsFromTestCase( localstest.LocalVarsTest ) + unittest.TestLoader().loadTestsFromTestCase( localstest.LocalVarsTest ), + unittest.TestLoader().loadTestsFromTestCase( ehexcepttest.EhExceptionBreakpointTest ) ] ) else: return unittest.TestSuite( unittest.TestLoader().loadTestsFromName( singleName ) ) @@ -73,4 +75,4 @@ if __name__ == "__main__": unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( suite ) - #raw_input("\npress return\n") + # raw_input("\npress return\n") diff --git a/test/targetapp/targetapp.vcproj b/test/targetapp/targetapp.vcproj index d726ee9..a03833a 100644 --- a/test/targetapp/targetapp.vcproj +++ b/test/targetapp/targetapp.vcproj @@ -416,6 +416,10 @@ RelativePath="..\scripts\diatest.py" > + +