mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-21 04:13:22 +08:00
506 lines
20 KiB
C++
506 lines
20 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <wdbgexts.h>
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
#include <boost/python/module.hpp>
|
|
#include <boost/python/def.hpp>
|
|
#include <boost/tokenizer.hpp>
|
|
#include <boost/python/overloads.hpp>
|
|
|
|
#include "dbgext.h"
|
|
#include "dbgprint.h"
|
|
#include "dbgreg.h"
|
|
#include "dbgtype.h"
|
|
#include "dbgmodule.h"
|
|
#include "dbgsym.h"
|
|
#include "dbgmem.h"
|
|
#include "dbgsystem.h"
|
|
#include "dbgcmd.h"
|
|
#include "dbgdump.h"
|
|
#include "dbgexcept.h"
|
|
#include "dbgeventcb.h"
|
|
#include "dbgsession.h"
|
|
#include "dbgcallback.h"
|
|
#include "dbgpath.h"
|
|
#include "dbginput.h"
|
|
#include "dbgprocess.h"
|
|
#include "dbgsynsym.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// óêàçàòåëü íà òåêóùéè èíòåðôåéñ
|
|
DbgExt *dbgExt = NULL;
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class WindbgGlobalSession
|
|
{
|
|
public:
|
|
|
|
WindbgGlobalSession() {
|
|
|
|
boost::python::import( "pykd" );
|
|
|
|
main = boost::python::import("__main__");
|
|
|
|
// ïåðåíàïðàâëåíèå ñòàíäàðòíûõ ïîòîêîâ ÂÂ
|
|
boost::python::object sys = boost::python::import( "sys");
|
|
|
|
dbgOut dout;
|
|
sys.attr("stdout") = boost::python::object( dout );
|
|
|
|
dbgIn din;
|
|
sys.attr("stdin") = boost::python::object( din );
|
|
}
|
|
|
|
boost::python::object
|
|
global() {
|
|
return main.attr("__dict__");
|
|
}
|
|
|
|
private:
|
|
|
|
boost::python::object main;
|
|
|
|
};
|
|
|
|
WindbgGlobalSession *windbgGlobalSession = NULL;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( dprint, DbgPrint::dprint, 1, 2 )
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( dprintln, DbgPrint::dprintln, 1, 2 )
|
|
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( loadBytes, loadArray<unsigned char>, 2, 3 )
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( loadWords, loadArray<unsigned short>, 2, 3 )
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( loadDWords, loadArray<unsigned long>, 2, 3 )
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( loadQWords, loadArray<unsigned __int64> , 2, 3 )
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignBytes, loadArray<char> , 2, 3 )
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignWords, loadArray<short> , 2, 3 )
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignDWords, loadArray<long> , 2, 3 )
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignQWords, loadArray<__int64>, 2, 3 )
|
|
|
|
BOOST_PYTHON_FUNCTION_OVERLOADS( compareMemoryOver, compareMemory, 3, 4 )
|
|
|
|
BOOST_PYTHON_MODULE( pykd )
|
|
{
|
|
boost::python::def( "go", &setExecutionStatus<DEBUG_STATUS_GO> );
|
|
boost::python::def( "trace", &setExecutionStatus<DEBUG_STATUS_STEP_INTO> );
|
|
boost::python::def( "step", &setExecutionStatus<DEBUG_STATUS_STEP_OVER> );
|
|
boost::python::def( "expr", &evaluate );
|
|
boost::python::def( "createSession", &dbgCreateSession ); // deprecated
|
|
boost::python::def( "isSessionStart", &dbgIsSessionStart );
|
|
boost::python::def( "symbolsPath", &dbgSymPath );
|
|
boost::python::def( "dprint", &DbgPrint::dprint, dprint( boost::python::args( "str", "dml" ), "" ) );
|
|
boost::python::def( "dprintln", &DbgPrint::dprintln, dprintln( boost::python::args( "str", "dml" ), "" ) );
|
|
boost::python::def( "loadDump", &dbgLoadDump );
|
|
boost::python::def( "startProcess", &startProcess );
|
|
boost::python::def( "dbgCommand", &dbgCommand );
|
|
boost::python::def( "isValid", &isOffsetValid );
|
|
boost::python::def( "is64bitSystem", &is64bitSystem );
|
|
boost::python::def( "isKernelDebugging", &isKernelDebugging );
|
|
boost::python::def( "ptrSize", ptrSize );
|
|
boost::python::def( "reg", &loadRegister );
|
|
boost::python::def( "typedVar", &loadTypedVar );
|
|
boost::python::def( "typedVarList", &loadTypedVarList );
|
|
boost::python::def( "typedVarArray", &loadTypedVarArray );
|
|
boost::python::def( "containingRecord", &containingRecord );
|
|
boost::python::def( "getTypeClass", &getTypeClass );
|
|
boost::python::def( "sizeof", &sizeofType );
|
|
boost::python::def( "loadModule", &loadModule );
|
|
boost::python::def( "findSymbol", &findSymbolForAddress );
|
|
boost::python::def( "getOffset", &findAddressForSymbol );
|
|
boost::python::def( "findModule", &findModule );
|
|
boost::python::def( "addr64", &addr64 );
|
|
boost::python::def( "loadBytes", &loadArray<unsigned char>, loadBytes( boost::python::args( "address", "number", "phyAddr" ), "" ) );
|
|
boost::python::def( "loadWords", &loadArray<unsigned short>, loadWords( boost::python::args( "address", "number", "phyAddr" ), "" ) );
|
|
boost::python::def( "loadDWords", &loadArray<unsigned long>, loadDWords( boost::python::args( "address", "number", "phyAddr" ), "" ) );
|
|
boost::python::def( "loadQWords", &loadArray<unsigned __int64>, loadQWords( boost::python::args( "address", "number", "phyAddr" ), "" ) );
|
|
boost::python::def( "loadSignBytes", &loadArray<char>, loadSignBytes( boost::python::args( "address", "number", "phyAddr" ), "" ) );
|
|
boost::python::def( "loadSignWords", &loadArray<short>, loadSignWords( boost::python::args( "address", "number", "phyAddr" ), "" ) );
|
|
boost::python::def( "loadSignDWords", &loadArray<long>, loadSignDWords( boost::python::args( "address", "number", "phyAddr" ), "" ) );
|
|
boost::python::def( "loadSignQWords", &loadArray<__int64>, loadSignQWords( boost::python::args( "address", "number", "phyAddr" ), "" ) );
|
|
boost::python::def( "loadPtrs", &loadPtrArray );
|
|
boost::python::def( "loadUnicodeString", &loadUnicodeStr );
|
|
boost::python::def( "loadAnsiString", &loadAnsiStr );
|
|
boost::python::def( "loadCStr", &loadCStr );
|
|
boost::python::def( "loadWStr", &loadWStr );
|
|
boost::python::def( "loadLinkedList", &loadLinkedList );
|
|
boost::python::def( "ptrByte", &loadByPtr<unsigned char> );
|
|
boost::python::def( "ptrSignByte", &loadByPtr<char> );
|
|
boost::python::def( "ptrWord", &loadByPtr<unsigned short> );
|
|
boost::python::def( "ptrSignWord", &loadByPtr<short> );
|
|
boost::python::def( "ptrDWord", &loadByPtr<unsigned long> );
|
|
boost::python::def( "ptrSignDWord", &loadByPtr<long> );
|
|
boost::python::def( "ptrQWord", &loadByPtr<unsigned __int64> );
|
|
boost::python::def( "ptrSignQWord", &loadByPtr<__int64> );
|
|
boost::python::def( "ptrPtr", &loadPtrByPtr );
|
|
boost::python::def( "ptrMWord", &loadMWord );
|
|
boost::python::def( "ptrSignMWord", &loadSignMWord );
|
|
boost::python::def( "compareMemory", &compareMemory, compareMemoryOver( boost::python::args( "addr1", "addr2", "length", "phyAddr" ), "" ) );
|
|
boost::python::def( "getCurrentStack", &getCurrentStack );
|
|
boost::python::def( "locals", &getLocals );
|
|
boost::python::def( "reloadModule", &reloadModule );
|
|
boost::python::def( "getPdbFile", &getPdbFile );
|
|
boost::python::def( "getImplicitThread", &getImplicitThread );
|
|
boost::python::def( "setImplicitThread", &setImplicitThread );
|
|
boost::python::def( "getThreadList", &getThreadList );
|
|
boost::python::def( "getCurrentProcess", &getCurrentProcess );
|
|
boost::python::def( "setCurrentProcess", &setCurrentProcess );
|
|
boost::python::def( "getProcessorMode", &getProcessorMode );
|
|
boost::python::def( "setProcessorMode", &setProcessorMode );
|
|
boost::python::def( "addSynSymbol", &addSyntheticSymbol );
|
|
boost::python::def( "delAllSynSymbols", &delAllSyntheticSymbols);
|
|
boost::python::def( "delSynSymbol", &delSyntheticSymbol );
|
|
boost::python::def( "delSynSymbolsMask", &delSyntheticSymbolsMask);
|
|
boost::python::class_<typeClass, boost::shared_ptr<typeClass> >( "typeClass" )
|
|
.def("sizeof", &typeClass::size )
|
|
.def("offset", &typeClass::getOffset )
|
|
.def("__str__", &typeClass::print);
|
|
boost::python::class_<typedVarClass, boost::python::bases<typeClass>, boost::shared_ptr<typedVarClass> >( "typedVarClass" )
|
|
.def("getAddress", &typedVarClass::getAddress );
|
|
boost::python::class_<dbgModuleClass>( "dbgModuleClass" )
|
|
.def("begin", &dbgModuleClass::getBegin )
|
|
.def("end", &dbgModuleClass::getEnd )
|
|
.def("name", &dbgModuleClass::getName )
|
|
.def("contain", &dbgModuleClass::contain )
|
|
.def("image", &dbgModuleClass::getImageSymbolName )
|
|
.def("pdb", &dbgModuleClass::getPdbName )
|
|
.def("addSynSymbol", &dbgModuleClass::addSyntheticSymbol )
|
|
.def("delAllSynSymbols", &dbgModuleClass::delAllSyntheticSymbols )
|
|
.def("delSynSymbol", &dbgModuleClass::delSyntheticSymbol )
|
|
.def("delSynSymbolsMask", &dbgModuleClass::delSyntheticSymbolsMask )
|
|
.def("__getattr__", &dbgModuleClass::getOffset )
|
|
.def("__str__", &dbgModuleClass::print );
|
|
boost::python::class_<dbgExtensionClass>(
|
|
"ext",
|
|
"windbg extension",
|
|
boost::python::init<const char*>( boost::python::args("path"), "__init__ dbgExtensionClass" ) )
|
|
.def("call", &dbgExtensionClass::call )
|
|
.def("__str__", &dbgExtensionClass::print );
|
|
boost::python::class_<dbgStackFrameClass>( "dbgStackFrameClass", "dbgStackFrameClass" )
|
|
.def_readonly( "instructionOffset", &dbgStackFrameClass::InstructionOffset )
|
|
.def_readonly( "returnOffset", &dbgStackFrameClass::ReturnOffset )
|
|
.def_readonly( "frameOffset", &dbgStackFrameClass::FrameOffset )
|
|
.def_readonly( "stackOffset", &dbgStackFrameClass::StackOffset )
|
|
.def_readonly( "frameNumber", &dbgStackFrameClass::FrameNumber )
|
|
.def( "__str__", &dbgStackFrameClass::print );
|
|
boost::python::class_<dbgOut>( "windbgOut", "windbgOut" )
|
|
.def( "write", &dbgOut::write );
|
|
boost::python::class_<dbgIn>( "windbgIn", "windbgIn" )
|
|
.def( "readline", &dbgIn::readline );
|
|
boost::python::class_<dbgBreakpointClass>(
|
|
"bp",
|
|
"break point",
|
|
boost::python::init<ULONG64>( boost::python::args("offset"), "__init__ dbgBreakpointClass" ) )
|
|
.def( "set", &dbgBreakpointClass::set )
|
|
.def( "remove", &dbgBreakpointClass::remove )
|
|
.def( "__str__", &dbgBreakpointClass::print );
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT
|
|
CALLBACK
|
|
DebugExtensionInitialize(
|
|
OUT PULONG Version,
|
|
OUT PULONG Flags )
|
|
{
|
|
*Version = DEBUG_EXTENSION_VERSION( 1, 0 );
|
|
*Flags = 0;
|
|
|
|
PyImport_AppendInittab("pykd", initpykd );
|
|
|
|
Py_Initialize();
|
|
|
|
windbgGlobalSession = new WindbgGlobalSession();
|
|
|
|
return setDbgSessionStarted();
|
|
}
|
|
|
|
|
|
VOID
|
|
CALLBACK
|
|
DebugExtensionUninitialize()
|
|
{
|
|
DbgEventCallbacks::Stop();
|
|
|
|
delete windbgGlobalSession;
|
|
windbgGlobalSession = NULL;
|
|
|
|
Py_Finalize();
|
|
}
|
|
|
|
|
|
void
|
|
SetupDebugEngine( IDebugClient4 *client, DbgExt *dbgExt )
|
|
{
|
|
client->QueryInterface( __uuidof(IDebugClient), (void **)&dbgExt->client );
|
|
client->QueryInterface( __uuidof(IDebugClient4), (void **)&dbgExt->client4 );
|
|
|
|
|
|
client->QueryInterface( __uuidof(IDebugControl), (void **)&dbgExt->control );
|
|
client->QueryInterface( __uuidof(IDebugControl4), (void **)&dbgExt->control4 );
|
|
|
|
client->QueryInterface( __uuidof(IDebugRegisters), (void **)&dbgExt->registers );
|
|
|
|
client->QueryInterface( __uuidof(IDebugSymbols), (void ** )&dbgExt->symbols );
|
|
client->QueryInterface( __uuidof(IDebugSymbols2), (void ** )&dbgExt->symbols2 );
|
|
client->QueryInterface( __uuidof(IDebugSymbols3), (void ** )&dbgExt->symbols3 );
|
|
|
|
client->QueryInterface( __uuidof(IDebugDataSpaces), (void **)&dbgExt->dataSpaces );
|
|
client->QueryInterface( __uuidof(IDebugDataSpaces4), (void **)&dbgExt->dataSpaces4 );
|
|
|
|
client->QueryInterface( __uuidof(IDebugAdvanced2), (void **)&dbgExt->advanced2 );
|
|
|
|
client->QueryInterface( __uuidof(IDebugSystemObjects), (void**)&dbgExt->system );
|
|
client->QueryInterface( __uuidof(IDebugSystemObjects2), (void**)&dbgExt->system2 );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT
|
|
CALLBACK
|
|
py( PDEBUG_CLIENT4 client, PCSTR args)
|
|
{
|
|
|
|
PyThreadState *globalInterpreter = PyThreadState_Swap( NULL );
|
|
PyThreadState *localInterpreter = Py_NewInterpreter();
|
|
|
|
try {
|
|
|
|
DbgExt ext = { 0 };
|
|
SetupDebugEngine( client, &ext );
|
|
dbgExt = &ext;
|
|
|
|
boost::python::import( "pykd" );
|
|
|
|
boost::python::object main = boost::python::import("__main__");
|
|
|
|
boost::python::object global(main.attr("__dict__"));
|
|
|
|
// ïåðåíàïðàâëåíèå ñòàíäàðòíûõ ïîòîêîâ ÂÂ
|
|
boost::python::object sys = boost::python::import("sys");
|
|
|
|
dbgOut dout;
|
|
sys.attr("stdout") = boost::python::object( dout );
|
|
|
|
dbgIn din;
|
|
sys.attr("stdin") = boost::python::object( din );
|
|
|
|
// ðàçáîð ïàðàìåòðîâ
|
|
typedef boost::escaped_list_separator<char> 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<std::string> argsList;
|
|
|
|
for ( char_tokenizer_t::iterator it = token.begin(); it != token.end(); ++it )
|
|
{
|
|
if ( *it != "" )
|
|
argsList.push_back( *it );
|
|
}
|
|
|
|
if ( argsList.size() == 0 )
|
|
return S_OK;
|
|
|
|
char **pythonArgs = new char* [ argsList.size() ];
|
|
|
|
for ( size_t i = 0; i < argsList.size(); ++i )
|
|
pythonArgs[i] = const_cast<char*>( argsList[i].c_str() );
|
|
|
|
PySys_SetArgv( (int)argsList.size(), pythonArgs );
|
|
|
|
delete[] pythonArgs;
|
|
|
|
|
|
// íàéòè ïóòü ê ôàéëó
|
|
std::string fullFileName;
|
|
std::string filePath;
|
|
DbgPythonPath dbgPythonPath;
|
|
|
|
if ( dbgPythonPath.findPath( argsList[0], fullFileName, filePath ) )
|
|
{
|
|
DWORD oldCurDirLen = GetCurrentDirectoryA( 0, NULL );
|
|
|
|
std::vector<char> oldCurDirCstr(oldCurDirLen);
|
|
|
|
GetCurrentDirectoryA( oldCurDirLen, &oldCurDirCstr[0] );
|
|
|
|
SetCurrentDirectoryA( filePath.c_str() );
|
|
|
|
try {
|
|
|
|
boost::python::object result;
|
|
|
|
result = boost::python::exec_file( fullFileName.c_str(), global, global );
|
|
|
|
}
|
|
catch( boost::python::error_already_set const & )
|
|
{
|
|
// îøèáêà â ñêðèïòå
|
|
PyObject *errtype = NULL, *errvalue = NULL, *traceback = NULL;
|
|
|
|
PyErr_Fetch( &errtype, &errvalue, &traceback );
|
|
|
|
if(errvalue != NULL)
|
|
{
|
|
PyObject *s = PyObject_Str(errvalue);
|
|
|
|
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "%s/n", PyString_AS_STRING( s ) );
|
|
|
|
Py_DECREF(s);
|
|
}
|
|
|
|
Py_XDECREF(errvalue);
|
|
Py_XDECREF(errtype);
|
|
Py_XDECREF(traceback);
|
|
}
|
|
|
|
SetCurrentDirectoryA( &oldCurDirCstr[0] );
|
|
}
|
|
else
|
|
{
|
|
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "script file not found\n" );
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
}
|
|
|
|
Py_EndInterpreter( localInterpreter );
|
|
PyThreadState_Swap( globalInterpreter );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT
|
|
CALLBACK
|
|
pycmd( PDEBUG_CLIENT4 client, PCSTR args )
|
|
{
|
|
try {
|
|
|
|
|
|
DbgExt ext = { 0 };
|
|
|
|
SetupDebugEngine( client, &ext );
|
|
dbgExt = &ext;
|
|
|
|
if ( !std::string( args ).empty() )
|
|
{
|
|
try
|
|
{
|
|
boost::python::exec( args, windbgGlobalSession->global(), windbgGlobalSession->global() );
|
|
}
|
|
catch( boost::python::error_already_set const & )
|
|
{
|
|
// îøèáêà â ñêðèïòå
|
|
PyObject *errtype = NULL, *errvalue = NULL, *traceback = NULL;
|
|
|
|
PyErr_Fetch( &errtype, &errvalue, &traceback );
|
|
|
|
if(errvalue != NULL)
|
|
{
|
|
PyObject *s = PyObject_Str(errvalue);
|
|
|
|
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "%s\n", PyString_AS_STRING( s ) );
|
|
|
|
Py_DECREF(s);
|
|
}
|
|
|
|
Py_XDECREF(errvalue);
|
|
Py_XDECREF(errtype);
|
|
Py_XDECREF(traceback);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char str[100];
|
|
ULONG inputSize;
|
|
bool stopInput = false;
|
|
|
|
do {
|
|
|
|
std::string output;
|
|
|
|
dbgExt->control->Output( DEBUG_OUTPUT_NORMAL, ">>>" );
|
|
|
|
do {
|
|
|
|
OutputReader outputReader( dbgExt->client );
|
|
|
|
HRESULT hres = dbgExt->control->Input( str, sizeof(str), &inputSize );
|
|
|
|
if ( FAILED( hres ) || std::string( str ) == "" )
|
|
{
|
|
stopInput = true;
|
|
break;
|
|
}
|
|
|
|
} while( FALSE );
|
|
|
|
if ( !stopInput )
|
|
try {
|
|
boost::python::exec( str, windbgGlobalSession->global(), windbgGlobalSession->global() );
|
|
}
|
|
catch( boost::python::error_already_set const & )
|
|
{
|
|
// îøèáêà â ñêðèïòå
|
|
PyObject *errtype = NULL, *errvalue = NULL, *traceback = NULL;
|
|
|
|
PyErr_Fetch( &errtype, &errvalue, &traceback );
|
|
|
|
if(errvalue != NULL)
|
|
{
|
|
PyObject *s = PyObject_Str(errvalue);
|
|
|
|
dbgExt->control->Output( DEBUG_OUTPUT_ERROR, "%s/n", PyString_AS_STRING( s ) );
|
|
|
|
Py_DECREF(s);
|
|
}
|
|
|
|
Py_XDECREF(errvalue);
|
|
Py_XDECREF(errtype);
|
|
Py_XDECREF(traceback);
|
|
}
|
|
|
|
} while( !stopInput );
|
|
}
|
|
}
|
|
|
|
catch(...)
|
|
{
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT
|
|
CALLBACK
|
|
pythonpath( PDEBUG_CLIENT4 client, PCSTR args )
|
|
{
|
|
DbgExt ext = { 0 };
|
|
|
|
SetupDebugEngine( client, &ext );
|
|
dbgExt = &ext;
|
|
|
|
//DbgPrint::dprintln( dbgPythonPath.getStr() );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|