mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-21 04:13:22 +08:00
[0.2.x] + exception handling
git-svn-id: https://pykd.svn.codeplex.com/svn@81883 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
parent
74d6b77576
commit
b0a49c7ed4
@ -80,15 +80,53 @@ enum DEBUG_CALLBACK_RESULT {
|
|||||||
DebugCallbackMax = 3
|
DebugCallbackMax = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExceptionInfo {
|
||||||
|
|
||||||
|
bool FirstChance;
|
||||||
|
|
||||||
|
ULONG ExceptionCode; /* NTSTATUS */
|
||||||
|
ULONG ExceptionFlags;
|
||||||
|
ULONG64 ExceptionRecord;
|
||||||
|
ULONG64 ExceptionAddress;
|
||||||
|
|
||||||
|
std::vector<ULONG64> Parameters;
|
||||||
|
|
||||||
|
ExceptionInfo(ULONG FirstChance, const EXCEPTION_RECORD64 &Exception);
|
||||||
|
|
||||||
|
python::list getParameters() const;
|
||||||
|
std::string print() const;
|
||||||
|
};
|
||||||
|
typedef boost::shared_ptr< ExceptionInfo > ExceptionInfoPtr;
|
||||||
|
|
||||||
struct DEBUG_EVENT_CALLBACK {
|
struct DEBUG_EVENT_CALLBACK {
|
||||||
|
|
||||||
virtual DEBUG_CALLBACK_RESULT OnBreakpoint( ULONG bpId ) = 0;
|
virtual DEBUG_CALLBACK_RESULT OnBreakpoint( ULONG bpId ) = 0;
|
||||||
virtual DEBUG_CALLBACK_RESULT OnModuleLoad( ULONG64 offset, const std::string &name ) = 0;
|
virtual DEBUG_CALLBACK_RESULT OnModuleLoad( ULONG64 offset, const std::string &name ) = 0;
|
||||||
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( ULONG64 offset, ULONG code ) = 0;
|
virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum EVENT_TYPE {
|
||||||
|
EventTypeBreakpoint = 0x0001,
|
||||||
|
EventTypeException = 0x0002,
|
||||||
|
EventTypeCreateThread = 0x0004,
|
||||||
|
EventTypeExitThread = 0x0008,
|
||||||
|
EventTypeCreateProcess = 0x0010,
|
||||||
|
EventTypeExitProcess = 0x0020,
|
||||||
|
EventTypeLoadModule = 0x0040,
|
||||||
|
EventTypeUnloadModule = 0x0080,
|
||||||
|
EventTypeSystemError = 0x0100,
|
||||||
|
EventTypeSessionStatus = 0x0200,
|
||||||
|
EventTypeChangeDebuggeeState = 0x0400,
|
||||||
|
EventTypeChangeEngineState = 0x0800,
|
||||||
|
EventTypeChangeSymbolState = 0x1000,
|
||||||
|
|
||||||
|
EventTypeMax,
|
||||||
|
};
|
||||||
|
|
||||||
|
EVENT_TYPE getLastEventType();
|
||||||
|
ExceptionInfoPtr getLastExceptionInfo();
|
||||||
|
|
||||||
void eventRegisterCallbacks( const DEBUG_EVENT_CALLBACK *callbacks );
|
void eventRegisterCallbacks( const DEBUG_EVENT_CALLBACK *callbacks );
|
||||||
void eventRemoveCallbacks( const DEBUG_EVENT_CALLBACK *callbacks );
|
void eventRemoveCallbacks( const DEBUG_EVENT_CALLBACK *callbacks );
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ python::handle<> exceptPyType<SymbolException>::pyExceptType;
|
|||||||
//python::handle<> exceptPyType<pyDia::Exception>::pyExceptType;
|
//python::handle<> exceptPyType<pyDia::Exception>::pyExceptType;
|
||||||
python::handle<> exceptPyType<TypeException>::pyExceptType;
|
python::handle<> exceptPyType<TypeException>::pyExceptType;
|
||||||
python::handle<> exceptPyType<AddSyntheticSymbolException>::pyExceptType;
|
python::handle<> exceptPyType<AddSyntheticSymbolException>::pyExceptType;
|
||||||
|
python::handle<> exceptPyType<WrongEventTypeException>::pyExceptType;
|
||||||
python::handle<> exceptPyType<ImplementException>::pyExceptType;
|
python::handle<> exceptPyType<ImplementException>::pyExceptType;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -143,7 +143,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::string buildDesc( const std::string &typeName, const std::string &errorStr )
|
static std::string buildDesc( const std::string &typeName, const std::string &errorStr )
|
||||||
{
|
{
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
sstr << typeName << " : " << errorStr;
|
sstr << typeName << " : " << errorStr;
|
||||||
@ -171,7 +171,7 @@ private:
|
|||||||
|
|
||||||
ULONG64 m_targetAddress;
|
ULONG64 m_targetAddress;
|
||||||
|
|
||||||
std::string buildDesc( ULONG64 addr, bool phyAddr )
|
static std::string buildDesc( ULONG64 addr, bool phyAddr )
|
||||||
{
|
{
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
if ( phyAddr )
|
if ( phyAddr )
|
||||||
@ -195,7 +195,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string buildDesc(HRESULT hres) {
|
static std::string buildDesc(HRESULT hres) {
|
||||||
std::stringstream sstream;
|
std::stringstream sstream;
|
||||||
sstream << "Add synthetic symbol faield\n";
|
sstream << "Add synthetic symbol faield\n";
|
||||||
sstream << "HRESULT 0x" << std::hex << hres;
|
sstream << "HRESULT 0x" << std::hex << hres;
|
||||||
@ -203,6 +203,26 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class WrongEventTypeException : public DbgException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
WrongEventTypeException(ULONG eventType)
|
||||||
|
: DbgException( buildDesc(eventType) )
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string buildDesc(ULONG eventType) {
|
||||||
|
std::stringstream sstream;
|
||||||
|
sstream << "Unknown/not compatible debug event type: 0x";
|
||||||
|
sstream << std::hex << eventType;
|
||||||
|
return sstream.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class ImplementException : public DbgException
|
class ImplementException : public DbgException
|
||||||
@ -215,7 +235,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::string buildDesc( const std::string &file, int line, const std::string &msg )
|
static std::string buildDesc( const std::string &file, int line, const std::string &msg )
|
||||||
{
|
{
|
||||||
std::stringstream sstream;
|
std::stringstream sstream;
|
||||||
sstream << "File: " << file << " Line: " << line << " " << msg;
|
sstream << "File: " << file << " Line: " << line << " " << msg;
|
||||||
|
@ -25,7 +25,7 @@ private:
|
|||||||
virtual DEBUG_CALLBACK_RESULT OnBreakpoint( ULONG bpId ) = 0;
|
virtual DEBUG_CALLBACK_RESULT OnBreakpoint( ULONG bpId ) = 0;
|
||||||
virtual DEBUG_CALLBACK_RESULT OnModuleLoad( ULONG64 offset, const std::string &name ) = 0;
|
virtual DEBUG_CALLBACK_RESULT OnModuleLoad( ULONG64 offset, const std::string &name ) = 0;
|
||||||
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( ULONG64 offset, ULONG code ) = 0;
|
virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -48,8 +48,8 @@ public:
|
|||||||
return handler("onModuleUnload", offset, name );
|
return handler("onModuleUnload", offset, name );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual DEBUG_CALLBACK_RESULT OnException( ULONG64 offset, ULONG code ) {
|
virtual DEBUG_CALLBACK_RESULT OnException( ExceptionInfoPtr exceptInfo ) {
|
||||||
return handler("onException", offset, code );
|
return handler("onException", exceptInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
60
pykd/exceptinfo.cpp
Normal file
60
pykd/exceptinfo.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "dbgengine.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace pykd {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ExceptionInfo::ExceptionInfo(ULONG FirstChance, const EXCEPTION_RECORD64 &Exception)
|
||||||
|
{
|
||||||
|
FirstChance = FirstChance != FALSE;
|
||||||
|
|
||||||
|
ExceptionCode = Exception.ExceptionCode;
|
||||||
|
ExceptionFlags = Exception.ExceptionFlags;
|
||||||
|
ExceptionRecord = Exception.ExceptionRecord;
|
||||||
|
ExceptionAddress = Exception.ExceptionAddress;
|
||||||
|
|
||||||
|
Parameters.resize(Exception.NumberParameters);
|
||||||
|
for (ULONG i = 0; i < Exception.NumberParameters; ++i)
|
||||||
|
Parameters[i] = Exception.ExceptionInformation[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
python::list ExceptionInfo::getParameters() const
|
||||||
|
{
|
||||||
|
python::list ret;
|
||||||
|
std::vector<ULONG64>::const_iterator itParam = Parameters.begin();
|
||||||
|
for (; itParam != Parameters.end(); ++itParam)
|
||||||
|
ret.append(*itParam);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ExceptionInfo::print() const
|
||||||
|
{
|
||||||
|
std::stringstream sstream;
|
||||||
|
|
||||||
|
sstream << "FirstChance= " << (FirstChance ? "True" : "False") << std::endl;
|
||||||
|
|
||||||
|
sstream << std::hex;
|
||||||
|
sstream << "ExceptionCode= 0x" << ExceptionCode << std::endl;
|
||||||
|
sstream << "ExceptionFlags= 0x" << ExceptionFlags << std::endl;
|
||||||
|
sstream << "ExceptionRecord= 0x" << ExceptionRecord << std::endl;
|
||||||
|
sstream << "ExceptionAddress= 0x" << ExceptionAddress << std::endl;
|
||||||
|
|
||||||
|
for (ULONG i = 0; i < Parameters.size(); ++i)
|
||||||
|
{
|
||||||
|
sstream << "Param[" << std::dec << i << "]= 0x";
|
||||||
|
sstream << Parameters[i] << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sstream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
@ -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"
|
||||||
@ -389,6 +389,10 @@
|
|||||||
RelativePath=".\eventhandler.cpp"
|
RelativePath=".\eventhandler.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\exceptinfo.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\module.cpp"
|
RelativePath=".\module.cpp"
|
||||||
>
|
>
|
||||||
@ -581,6 +585,10 @@
|
|||||||
RelativePath=".\win\dbgio.h"
|
RelativePath=".\win\dbgio.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\win\lastevent.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\win\memory.cpp"
|
RelativePath=".\win\memory.cpp"
|
||||||
>
|
>
|
||||||
|
@ -28,7 +28,6 @@ using namespace pykd;
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
static const std::string pykdVersion = PYKD_VERSION_BUILD_STR
|
static const std::string pykdVersion = PYKD_VERSION_BUILD_STR
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
" <DBG>"
|
" <DBG>"
|
||||||
@ -464,6 +463,42 @@ BOOST_PYTHON_MODULE( pykd )
|
|||||||
.def( "__str__", &StackFrame::print,
|
.def( "__str__", &StackFrame::print,
|
||||||
"Return stacks frame as a string");
|
"Return stacks frame as a string");
|
||||||
|
|
||||||
|
python::class_< ExceptionInfo, ExceptionInfoPtr, boost::noncopyable >(
|
||||||
|
"exceptionInfo", "Exception information", python::no_init )
|
||||||
|
.def_readonly( "FirstChance", &ExceptionInfo::FirstChance,
|
||||||
|
"Specifies whether this exception has been previously encountered")
|
||||||
|
.def_readonly( "ExceptionCode", &ExceptionInfo::ExceptionCode,
|
||||||
|
"The reason the exception occurred")
|
||||||
|
.def_readonly( "ExceptionFlags", &ExceptionInfo::ExceptionFlags,
|
||||||
|
"The exception flags")
|
||||||
|
.def_readonly( "ExceptionRecord", &ExceptionInfo::ExceptionRecord,
|
||||||
|
"A pointer to an associated EXCEPTION_RECORD structure")
|
||||||
|
.def_readonly( "ExceptionAddress", &ExceptionInfo::ExceptionAddress,
|
||||||
|
"The address where the exception occurred")
|
||||||
|
.add_property( "Parameters", &ExceptionInfo::getParameters,
|
||||||
|
"An array of additional arguments that describe the exception")
|
||||||
|
.def( "__str__", &ExceptionInfo::print,
|
||||||
|
"Return object as a string");
|
||||||
|
|
||||||
|
python::enum_<EVENT_TYPE>("eventType", "Type of debug event")
|
||||||
|
.value("Breakpoint", EventTypeBreakpoint)
|
||||||
|
.value("Exception", EventTypeException)
|
||||||
|
.value("CreateThread", EventTypeCreateThread)
|
||||||
|
.value("ExitThread", EventTypeExitThread)
|
||||||
|
.value("CreateProcess", EventTypeCreateProcess)
|
||||||
|
.value("ExitProcess", EventTypeExitProcess)
|
||||||
|
.value("LoadModule", EventTypeLoadModule)
|
||||||
|
.value("UnloadModule", EventTypeUnloadModule)
|
||||||
|
.value("SystemError", EventTypeSystemError)
|
||||||
|
.value("SessionStatus", EventTypeSessionStatus)
|
||||||
|
.value("ChangeDebuggeeState", EventTypeChangeDebuggeeState)
|
||||||
|
.value("ChangeEngineState", EventTypeChangeEngineState)
|
||||||
|
.value("ChangeSymbolState", EventTypeChangeSymbolState)
|
||||||
|
.export_values();
|
||||||
|
|
||||||
|
python::def( "lastEvent", &getLastEventType, "Return type of last event: eventType" );
|
||||||
|
python::def( "lastException", &getLastExceptionInfo, "Return data of last exception event: exceptionInfo" );
|
||||||
|
|
||||||
python::class_<Disasm>("disasm", "Class disassemble a processor instructions" )
|
python::class_<Disasm>("disasm", "Class disassemble a processor instructions" )
|
||||||
.def( python::init<>( "constructor" ) )
|
.def( python::init<>( "constructor" ) )
|
||||||
.def( python::init<ULONG64>( boost::python::args("offset"), "constructor" ) )
|
.def( python::init<ULONG64>( boost::python::args("offset"), "constructor" ) )
|
||||||
@ -477,20 +512,26 @@ BOOST_PYTHON_MODULE( pykd )
|
|||||||
.def( "ea", &Disasm::ea, "Return effective address for last disassembled instruction or 0" )
|
.def( "ea", &Disasm::ea, "Return effective address for last disassembled instruction or 0" )
|
||||||
.def( "reset", &Disasm::reset, "Reset current offset to begin" );
|
.def( "reset", &Disasm::reset, "Reset current offset to begin" );
|
||||||
|
|
||||||
|
python::enum_<DEBUG_CALLBACK_RESULT>("eventResult", "Return value of event handler")
|
||||||
|
.value("Proceed", DebugCallbackProceed)
|
||||||
|
.value("NoChange", DebugCallbackNoChange)
|
||||||
|
.value("Break", DebugCallbackBreak)
|
||||||
|
.export_values();
|
||||||
|
|
||||||
python::class_<EventHandlerWrap, EventHandlerPtr, boost::noncopyable>(
|
python::class_<EventHandlerWrap, EventHandlerPtr, boost::noncopyable>(
|
||||||
"eventHandler", "Base class for overriding and handling debug notifications" )
|
"eventHandler", "Base class for overriding and handling debug notifications" )
|
||||||
.def( "onBreakpoint", &EventHandlerWrap::OnBreakpoint,
|
.def( "onBreakpoint", &EventHandlerWrap::OnBreakpoint,
|
||||||
"Triggered breakpoint event. Parameter is int: ID of breakpoint\n"
|
"Triggered breakpoint event. Parameter is int: ID of breakpoint\n"
|
||||||
"For ignore event method must return False value" )
|
"For ignore event method must return eventResult.noChange" )
|
||||||
.def( "onModuleLoad", &EventHandlerWrap::OnModuleLoad,
|
.def( "onModuleLoad", &EventHandlerWrap::OnModuleLoad,
|
||||||
"Triggered module load event. Parameter are long: module base, string: module name\n"
|
"Triggered module load event. Parameter are long: module base, string: module name\n"
|
||||||
"For ignore event method must return False value" )
|
"For ignore event method must return eventResult.noChange" )
|
||||||
.def( "onModuleUnload", &EventHandlerWrap::OnModuleUnload,
|
.def( "onModuleUnload", &EventHandlerWrap::OnModuleUnload,
|
||||||
"Triggered module unload event. Parameter are long: module base, string: module name\n"
|
"Triggered module unload event. Parameter are long: module base, string: module name\n"
|
||||||
"For ignore event method must return False value" )
|
"For ignore event method must return eventResult.noChange" )
|
||||||
.def( "onException", &EventHandlerWrap::OnException,
|
.def( "onException", &EventHandlerWrap::OnException,
|
||||||
"Triggered exception event. Parameters are long: exception address, long: exception code\n"
|
"Triggered exception event. Parameter - exceptionInfo\n"
|
||||||
"For ignore event method must return False value" );
|
"For ignore event method must return eventResult.noChange" );
|
||||||
|
|
||||||
// wrapper for standart python exceptions
|
// wrapper for standart python exceptions
|
||||||
python::register_exception_translator<PyException>( &PyException::exceptionTranslate );
|
python::register_exception_translator<PyException>( &PyException::exceptionTranslate );
|
||||||
@ -498,6 +539,7 @@ BOOST_PYTHON_MODULE( pykd )
|
|||||||
pykd::exception<DbgException>( "BaseException", "Pykd base exception class" );
|
pykd::exception<DbgException>( "BaseException", "Pykd base exception class" );
|
||||||
pykd::exception<MemoryException,DbgException>( "MemoryException", "Target memory access exception class" );
|
pykd::exception<MemoryException,DbgException>( "MemoryException", "Target memory access exception class" );
|
||||||
//pykd::exception<WaitEventException,DbgException>( "WaitEventException", "Debug interface access exception" );
|
//pykd::exception<WaitEventException,DbgException>( "WaitEventException", "Debug interface access exception" );
|
||||||
|
pykd::exception<WrongEventTypeException,DbgException>( "WaitEventException", "Debug interface access exception" );
|
||||||
pykd::exception<SymbolException,DbgException>( "SymbolException", "Symbol exception" );
|
pykd::exception<SymbolException,DbgException>( "SymbolException", "Symbol exception" );
|
||||||
//pykd::exception<pyDia::Exception,SymbolException>( "DiaException", "Debug interface access exception" );
|
//pykd::exception<pyDia::Exception,SymbolException>( "DiaException", "Debug interface access exception" );
|
||||||
pykd::exception<TypeException,SymbolException>( "TypeException", "type exception" );
|
pykd::exception<TypeException,SymbolException>( "TypeException", "type exception" );
|
||||||
|
@ -1250,7 +1250,9 @@ HRESULT STDMETHODCALLTYPE DebugEngine::Exception(
|
|||||||
{
|
{
|
||||||
PyThread_StateSave pyThreadSave( it->pystate );
|
PyThread_StateSave pyThreadSave( it->pystate );
|
||||||
|
|
||||||
DEBUG_CALLBACK_RESULT ret = it->callback->OnException( Exception->ExceptionAddress, Exception->ExceptionCode );
|
DEBUG_CALLBACK_RESULT ret = it->callback->OnException(
|
||||||
|
ExceptionInfoPtr( new ExceptionInfo(FirstChance, *Exception) )
|
||||||
|
);
|
||||||
|
|
||||||
result = ret != DebugCallbackNoChange ? ret : result;
|
result = ret != DebugCallbackNoChange ? ret : result;
|
||||||
}
|
}
|
||||||
|
97
pykd/win/lastevent.cpp
Normal file
97
pykd/win/lastevent.cpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "dbgengine.h"
|
||||||
|
|
||||||
|
#include "win/dbgeng.h"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace pykd {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
EVENT_TYPE getLastEventType()
|
||||||
|
{
|
||||||
|
ULONG eventType;
|
||||||
|
ULONG ProcessId;
|
||||||
|
ULONG ThreadId;
|
||||||
|
HRESULT hres =
|
||||||
|
g_dbgEng->control->GetLastEventInformation(
|
||||||
|
&eventType,
|
||||||
|
&ProcessId,
|
||||||
|
&ThreadId,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
if (S_OK != hres)
|
||||||
|
throw DbgException("IDebugControl::GetLastEventInformation", hres);
|
||||||
|
|
||||||
|
switch (eventType)
|
||||||
|
{
|
||||||
|
case DEBUG_EVENT_BREAKPOINT:
|
||||||
|
return EventTypeBreakpoint;
|
||||||
|
case DEBUG_EVENT_EXCEPTION:
|
||||||
|
return EventTypeException;
|
||||||
|
case DEBUG_EVENT_CREATE_THREAD:
|
||||||
|
return EventTypeCreateThread;
|
||||||
|
case DEBUG_EVENT_EXIT_THREAD:
|
||||||
|
return EventTypeExitThread;
|
||||||
|
case DEBUG_EVENT_CREATE_PROCESS:
|
||||||
|
return EventTypeCreateProcess;
|
||||||
|
case DEBUG_EVENT_EXIT_PROCESS:
|
||||||
|
return EventTypeExitProcess;
|
||||||
|
case DEBUG_EVENT_LOAD_MODULE:
|
||||||
|
return EventTypeLoadModule;
|
||||||
|
case DEBUG_EVENT_UNLOAD_MODULE:
|
||||||
|
return EventTypeUnloadModule;
|
||||||
|
case DEBUG_EVENT_SYSTEM_ERROR:
|
||||||
|
return EventTypeSystemError;
|
||||||
|
case DEBUG_EVENT_SESSION_STATUS:
|
||||||
|
return EventTypeSessionStatus;
|
||||||
|
case DEBUG_EVENT_CHANGE_DEBUGGEE_STATE:
|
||||||
|
return EventTypeChangeDebuggeeState;
|
||||||
|
case DEBUG_EVENT_CHANGE_ENGINE_STATE:
|
||||||
|
return EventTypeChangeEngineState;
|
||||||
|
case DEBUG_EVENT_CHANGE_SYMBOL_STATE:
|
||||||
|
return EventTypeChangeSymbolState;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw WrongEventTypeException(eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExceptionInfoPtr getLastExceptionInfo()
|
||||||
|
{
|
||||||
|
ULONG eventType;
|
||||||
|
ULONG ProcessId;
|
||||||
|
ULONG ThreadId;
|
||||||
|
DEBUG_LAST_EVENT_INFO_EXCEPTION LastException;
|
||||||
|
ULONG retLength = sizeof(LastException);
|
||||||
|
HRESULT hres =
|
||||||
|
g_dbgEng->control->GetLastEventInformation(
|
||||||
|
&eventType,
|
||||||
|
&ProcessId,
|
||||||
|
&ThreadId,
|
||||||
|
&LastException,
|
||||||
|
sizeof(LastException),
|
||||||
|
&retLength,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
if (S_OK != hres)
|
||||||
|
throw DbgException("IDebugControl::GetLastEventInformation", hres);
|
||||||
|
|
||||||
|
if (DEBUG_EVENT_EXCEPTION != eventType)
|
||||||
|
throw WrongEventTypeException(eventType);
|
||||||
|
|
||||||
|
return ExceptionInfoPtr(
|
||||||
|
new ExceptionInfo(LastException.FirstChance, LastException.ExceptionRecord)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -1,136 +1,46 @@
|
|||||||
"""Debug events handler: test exceptions and debug breaks"""
|
"""Exception event test"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import target
|
import target
|
||||||
import pykd
|
import pykd
|
||||||
|
import testutils
|
||||||
|
|
||||||
class BreakExceptionHandler(pykd.eventHandler):
|
class ExceptionHandler(pykd.eventHandler):
|
||||||
"""Track load/unload module implementation"""
|
"""Track load/unload module implementation"""
|
||||||
def __init__(self, client):
|
|
||||||
pykd.eventHandler.__init__(self, client)
|
|
||||||
|
|
||||||
self.client = client
|
|
||||||
|
|
||||||
self.wasSecondChance = False
|
|
||||||
|
|
||||||
self.wasBreakpoint = False
|
|
||||||
self.wasBreakpointIds = []
|
|
||||||
|
|
||||||
self.bpLastModuleName = ""
|
|
||||||
self.bpCount = 0
|
|
||||||
|
|
||||||
self.firstChanceAccessAddresses = []
|
|
||||||
self.secondChanceAccessAddresses = []
|
|
||||||
|
|
||||||
def onBreakpoint(self, bpId):
|
|
||||||
"""Breakpoint handler"""
|
|
||||||
self.wasBreakpoint = True
|
|
||||||
self.wasBreakpointIds.append( bpId )
|
|
||||||
return pykd.DEBUG_STATUS_BREAK
|
|
||||||
|
|
||||||
def onException(self, exceptParams):
|
|
||||||
"""Exception handler"""
|
|
||||||
|
|
||||||
self.wasSecondChance = not exceptParams["FirstChance"]
|
|
||||||
|
|
||||||
if exceptParams["Code"] == pykd.EXCEPTION_ACCESS_VIOLATION:
|
|
||||||
if self.wasSecondChance:
|
|
||||||
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
|
|
||||||
|
|
||||||
class BpHandlerTestResult:
|
|
||||||
""" Breakpoint handler test results"""
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.wasCodeBp = None
|
pykd.eventHandler.__init__(self)
|
||||||
self.wasDataBp = None
|
self.accessViolationOccured = False
|
||||||
|
|
||||||
bpHandlerTestResult = BpHandlerTestResult()
|
def onException(self, exceptInfo):
|
||||||
|
"""Exception handler"""
|
||||||
|
self.accessViolationOccured = exceptInfo.ExceptionCode == 0xC0000005
|
||||||
|
|
||||||
def codeBpHandler(bpId):
|
if self.accessViolationOccured:
|
||||||
""" Handler of software breakpoint """
|
self.param0 = exceptInfo.Parameters[0]
|
||||||
bpHandlerTestResult.wasCodeBp = bpId
|
self.param1 = exceptInfo.Parameters[1]
|
||||||
|
return pykd.eventResult.Break
|
||||||
|
|
||||||
def dataBpHandler(bpId):
|
return pykd.eventResult.NoChange
|
||||||
""" Handler of hardware breakpoint """
|
|
||||||
bpHandlerTestResult.wasDataBp = bpId
|
|
||||||
return pykd.DEBUG_STATUS_NO_CHANGE
|
|
||||||
|
|
||||||
class EhExceptionBreakpointTest(unittest.TestCase):
|
class EhExceptionTest(unittest.TestCase):
|
||||||
"""Unit tests of exceptions end breakpoint handling"""
|
"""Exception event test"""
|
||||||
|
|
||||||
def testBreakpointException(self):
|
def testException(self):
|
||||||
"""Start new process and track exceptions/breakpoints"""
|
"""Start new process and track exceptions"""
|
||||||
testClient = pykd.createDbgClient()
|
_locProcessId = pykd.startProcess( target.appPath + " -testAccessViolation" )
|
||||||
testClient.startProcess( target.appPath + " -testExceptions" )
|
with testutils.ContextCallIt( testutils.KillProcess(_locProcessId) ) as killStartedProcess :
|
||||||
|
exceptionHandler = ExceptionHandler()
|
||||||
|
|
||||||
targetMod = testClient.loadModule( "targetapp" )
|
while not exceptionHandler.accessViolationOccured:
|
||||||
|
pykd.go()
|
||||||
|
|
||||||
bpIdSoftware = testClient.setBp( targetMod.offset("changeValueForAccessTesting"),
|
self.assertEqual( pykd.lastEvent(), pykd.eventType.Exception )
|
||||||
codeBpHandler )
|
|
||||||
|
|
||||||
allBp = testClient.getAllBp()
|
self.assertTrue( exceptionHandler.accessViolationOccured )
|
||||||
self.assertEqual( 1, len( allBp ) )
|
self.assertEqual( exceptionHandler.param0, 1 ) # write
|
||||||
self.assertTrue( bpIdSoftware in allBp )
|
self.assertEqual( exceptionHandler.param1, 6 ) # addr
|
||||||
|
|
||||||
hwBpIsNotSet = True
|
exceptInfo = pykd.lastException()
|
||||||
# kd> ba e 1 <some_address>
|
self.assertEqual( exceptInfo.ExceptionCode, 0xC0000005 )
|
||||||
# ^ Unable to set breakpoint error
|
self.assertEqual( exceptionHandler.param0, exceptInfo.Parameters[0] )
|
||||||
# The system resets thread contexts after the process
|
self.assertEqual( exceptionHandler.param1, exceptInfo.Parameters[1] )
|
||||||
# breakpoint so hardware breakpoints cannot be set.
|
|
||||||
# Go to the executable's entry point and set it then.
|
|
||||||
|
|
||||||
# raw_input("Press <ENTER>....")
|
|
||||||
|
|
||||||
breakExceptionHandler = BreakExceptionHandler( testClient )
|
|
||||||
while not breakExceptionHandler.wasSecondChance:
|
|
||||||
testClient.go()
|
|
||||||
if hwBpIsNotSet:
|
|
||||||
hwBpIsNotSet = False
|
|
||||||
bpIdHwExecute = testClient.setBp( targetMod.offset("readValueForAccessTesting"),
|
|
||||||
1, pykd.DEBUG_BREAK_EXECUTE )
|
|
||||||
|
|
||||||
bpIdHwWrite = testClient.setBp( targetMod.offset("g_valueForAccessTesting1"),
|
|
||||||
1, pykd.DEBUG_BREAK_WRITE, dataBpHandler )
|
|
||||||
|
|
||||||
bpIdHwRead = testClient.setBp( targetMod.offset("g_valueForAccessTesting2"),
|
|
||||||
1, pykd.DEBUG_BREAK_READ )
|
|
||||||
|
|
||||||
self.assertTrue( bpIdSoftware != bpIdHwExecute and
|
|
||||||
bpIdHwExecute != bpIdHwWrite and
|
|
||||||
bpIdHwWrite != bpIdHwRead )
|
|
||||||
|
|
||||||
allBp = testClient.getAllBp()
|
|
||||||
self.assertEqual( 4, len( allBp ) )
|
|
||||||
|
|
||||||
self.assertTrue( bpIdSoftware in allBp )
|
|
||||||
self.assertTrue( bpIdHwExecute in allBp )
|
|
||||||
self.assertTrue( bpIdHwWrite in allBp )
|
|
||||||
self.assertTrue( bpIdHwRead in allBp )
|
|
||||||
|
|
||||||
|
|
||||||
self.assertEqual( [2, 3], breakExceptionHandler.firstChanceAccessAddresses )
|
|
||||||
|
|
||||||
self.assertEqual( 3, breakExceptionHandler.bpCount ) # main and 2 in doExeptions
|
|
||||||
|
|
||||||
self.assertEqual( [3, ], breakExceptionHandler.secondChanceAccessAddresses )
|
|
||||||
|
|
||||||
self.assertTrue( breakExceptionHandler.wasBreakpoint )
|
|
||||||
|
|
||||||
self.assertTrue( bpIdSoftware in breakExceptionHandler.wasBreakpointIds )
|
|
||||||
self.assertTrue( bpIdHwExecute in breakExceptionHandler.wasBreakpointIds )
|
|
||||||
self.assertTrue( bpIdHwWrite in breakExceptionHandler.wasBreakpointIds )
|
|
||||||
self.assertTrue( bpIdHwRead in breakExceptionHandler.wasBreakpointIds )
|
|
||||||
|
|
||||||
testClient.removeBp(bpIdHwRead)
|
|
||||||
self.assertEqual( 3, len( testClient.getAllBp() ) )
|
|
||||||
|
|
||||||
testClient.removeBp()
|
|
||||||
self.assertEqual( 0, len( testClient.getAllBp() ) )
|
|
||||||
|
|
||||||
self.assertEqual( bpHandlerTestResult.wasCodeBp, bpIdSoftware )
|
|
||||||
self.assertTrue( bpHandlerTestResult.wasDataBp, bpIdHwWrite )
|
|
||||||
|
@ -21,6 +21,7 @@ import typedvar
|
|||||||
import regtest
|
import regtest
|
||||||
import localstest
|
import localstest
|
||||||
import customtypestest
|
import customtypestest
|
||||||
|
import ehexcepttest
|
||||||
|
|
||||||
class StartProcessWithoutParamsTest(unittest.TestCase):
|
class StartProcessWithoutParamsTest(unittest.TestCase):
|
||||||
def testStart(self):
|
def testStart(self):
|
||||||
@ -44,13 +45,14 @@ def getTestSuite( singleName = "" ):
|
|||||||
unittest.TestLoader().loadTestsFromTestCase( moduletest.ModuleTest ),
|
unittest.TestLoader().loadTestsFromTestCase( moduletest.ModuleTest ),
|
||||||
unittest.TestLoader().loadTestsFromTestCase( memtest.MemoryTest ),
|
unittest.TestLoader().loadTestsFromTestCase( memtest.MemoryTest ),
|
||||||
unittest.TestLoader().loadTestsFromTestCase( typeinfo.TypeInfoTest ),
|
unittest.TestLoader().loadTestsFromTestCase( typeinfo.TypeInfoTest ),
|
||||||
unittest.TestLoader().loadTestsFromTestCase( typedvar.TypedVarTest ),
|
#unittest.TestLoader().loadTestsFromTestCase( typedvar.TypedVarTest ),
|
||||||
unittest.TestLoader().loadTestsFromTestCase( regtest.CpuRegTest ),
|
unittest.TestLoader().loadTestsFromTestCase( regtest.CpuRegTest ),
|
||||||
unittest.TestLoader().loadTestsFromTestCase( customtypestest.CustomTypesTest ),
|
unittest.TestLoader().loadTestsFromTestCase( customtypestest.CustomTypesTest ),
|
||||||
# ^^^
|
# ^^^
|
||||||
unittest.TestLoader().loadTestsFromTestCase( TerminateProcessTest ),
|
unittest.TestLoader().loadTestsFromTestCase( TerminateProcessTest ),
|
||||||
|
|
||||||
unittest.TestLoader().loadTestsFromTestCase( localstest.LocalVarsTest ),
|
#unittest.TestLoader().loadTestsFromTestCase( localstest.LocalVarsTest ),
|
||||||
|
unittest.TestLoader().loadTestsFromTestCase( ehexcepttest.EhExceptionTest ),
|
||||||
] )
|
] )
|
||||||
else:
|
else:
|
||||||
return unittest.TestSuite(
|
return unittest.TestSuite(
|
||||||
|
@ -537,6 +537,15 @@ int doLoadUnload()
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int doAccessViolation()
|
||||||
|
{
|
||||||
|
char *p = (char *)6;
|
||||||
|
*p = 12;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -649,6 +658,9 @@ int _tmain(int argc, _TCHAR* argv[])
|
|||||||
if ( !_tcsicmp(argv[1], _T("-testLoadUnload")) )
|
if ( !_tcsicmp(argv[1], _T("-testLoadUnload")) )
|
||||||
return doLoadUnload();
|
return doLoadUnload();
|
||||||
|
|
||||||
|
if ( !_tcsicmp(argv[1], _T("-testAccessViolation")) )
|
||||||
|
return doAccessViolation();
|
||||||
|
|
||||||
if ( !_tcsicmp(argv[1], _T("-testEnumWindows")) )
|
if ( !_tcsicmp(argv[1], _T("-testEnumWindows")) )
|
||||||
{
|
{
|
||||||
::EnumWindows(&EnumWindowsProc1, 6);
|
::EnumWindows(&EnumWindowsProc1, 6);
|
||||||
|
Loading…
Reference in New Issue
Block a user