diff --git a/pykd/dbgclient.h b/pykd/dbgclient.h index ba52408..9f8530d 100644 --- a/pykd/dbgclient.h +++ b/pykd/dbgclient.h @@ -8,6 +8,7 @@ #include "dbgexcept.h" #include "module.h" +#include "dbgio.h" ///////////////////////////////////////////////////////////////////////////////// @@ -57,13 +58,21 @@ public: ULONG64 addr64( ULONG64 addr ); - void dprint( const std::string &str, bool dml = false ); + void dprint( const std::wstring &str, bool dml = false ); - void dprintln( const std::string &str, bool dml = false ); + void dprintln( const std::wstring &str, bool dml = false ); - void eprint( const std::string &str ); + void eprint( const std::wstring &str ); - void eprintln( const std::string &str ); + void eprintln( const std::wstring &str ); + + DbgOut dout() { + return DbgOut( m_client ); + } + + DbgIn din() { + return DbgIn( m_client ); + } private: diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index a428d56..c982c0e 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -1,14 +1,16 @@ #include "stdafx.h" #include - #include +#include + #include "windbg.h" #include "module.h" #include "diawrapper.h" #include "dbgclient.h" #include "dbgio.h" +#include "dbgpath.h" using namespace pykd; @@ -45,6 +47,9 @@ static python::dict genDict(const pyDia::Symbol::ValueNameEntry srcValues[], siz //////////////////////////////////////////////////////////////////////////////// +BOOST_PYTHON_FUNCTION_OVERLOADS( dprint_, dprint, 1, 2 ) +BOOST_PYTHON_FUNCTION_OVERLOADS( dprintln_, dprintln, 1, 2 ) + #define DEF_PY_CONST_ULONG(x) \ python::scope().attr(#x) = ULONG(##x) @@ -82,10 +87,10 @@ BOOST_PYTHON_MODULE( pykd ) "Return instance of Module class" ); python::def( "findModule", &pykd::findModule, "Return instance of the Module class which posseses specified address" ); - python::def( "dprint", &pykd::dprint, - "Print out string. If dml = True string is printed with dml highlighting ( only for windbg )" ); - python::def( "dprintln", &pykd::dprintln, - "Print out string and insert end of line symbol. If dml = True string is printed with dml highlighting ( only for windbg )" ); + python::def( "dprint", &pykd::dprint, dprint_( boost::python::args( "str", "dml" ), + "Print out string. If dml = True string is printed with dml highlighting ( only for windbg )" ) ); + python::def( "dprintln", &pykd::dprintln, dprintln_( boost::python::args( "str", "dml" ), + "Print out string and insert end of line symbol. If dml = True string is printed with dml highlighting ( only for windbg )" ) ); python::class_("typeInfo", "Class representing typeInfo", python::no_init ) .def( "name", &pykd::TypeInfo::getName ) @@ -117,6 +122,12 @@ BOOST_PYTHON_MODULE( pykd ) "Return typeInfo class by type name" ) .def("__getattr__", &pykd::Module::getSymbol, "Return address of the symbol" ); + + boost::python::class_( "dout", "dout", python::no_init ) + .def( "write", &DbgOut::write ); + + boost::python::class_( "din", "din", python::no_init ) + .def( "readline", &DbgIn::readline ); python::def( "diaLoadPdb", &pyDia::GlobalScope::loadPdb, "Open pdb file for quering debug symbols. Return DiaSymbol of global scope"); @@ -380,11 +391,104 @@ py( PDEBUG_CLIENT4 client, PCSTR args ) try { + // получаем достпу к глобальному мапу ( нужен для вызова exec_file ) + boost::python::object main = python::import("__main__"); + + boost::python::object global(main.attr("__dict__")); + + boost::python::import( "pykd" ); + + // настраиваем ввод/вывод ( чтобы в скрипте можно было писать print ) + + boost::python::object sys = boost::python::import("sys"); + + sys.attr("stdout") = 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 != "" ) + 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( argsList[i].c_str() ); + + PySys_SetArgv( (int)argsList.size(), pythonArgs ); + + delete[] pythonArgs; + + // найти путь к файлу + std::string scriptName; + std::string filePath; + DbgPythonPath dbgPythonPath; + + if ( !dbgPythonPath.findPath( argsList[0], scriptName, filePath ) ) + { + dbgClient->eprintln( L"script file not found" ); + } + else + try { + + python::object result; + result = python::exec_file( scriptName.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 *errvalueStr= PyUnicode_FromObject(errvalue); + + dbgClient->eprintln( PyUnicode_AS_UNICODE( errvalueStr ) ); + + if ( traceback ) + { + python::object traceObj( python::handle<>( python::borrowed( traceback ) ) ); + + dbgClient->eprintln( L"\nTraceback:" ); + + python::object pFunc( tracebackModule.attr("format_tb") ); + python::list traceList( pFunc( traceObj ) ); + + for ( long i = 0; i < python::len(traceList); ++i ) + dbgClient->eprintln( python::extract(traceList[i]) ); + } + + Py_DECREF(errvalueStr); + } + + Py_XDECREF(errvalue); + Py_XDECREF(errtype); + Py_XDECREF(traceback); + } + } catch(...) { - dbgClient->eprintln( "unexpected error" ); + dbgClient->eprintln( L"unexpected error" ); } Py_EndInterpreter( localInterpreter ); @@ -414,7 +518,7 @@ pycmd( PDEBUG_CLIENT4 client, PCSTR args ) } catch(...) { - dbgClient->eprintln( "unexpected error" ); + dbgClient->eprintln( L"unexpected error" ); } WindbgGlobalSession::SavePyState(); diff --git a/pykd/dbgio.cpp b/pykd/dbgio.cpp index b79ab08..2f350cc 100644 --- a/pykd/dbgio.cpp +++ b/pykd/dbgio.cpp @@ -10,7 +10,7 @@ namespace pykd { /////////////////////////////////////////////////////////////////////////////////// -void DebugClient::dprint( const std::string &str, bool dml ) +void DebugClient::dprint( const std::wstring &str, bool dml ) { if ( WindbgGlobalSession::isInit() ) { @@ -18,18 +18,18 @@ void DebugClient::dprint( const std::string &str, bool dml ) { m_control->ControlledOutputWide( dml ? DEBUG_OUTCTL_AMBIENT_DML : DEBUG_OUTCTL_AMBIENT_TEXT, DEBUG_OUTPUT_NORMAL, - L"%s", + L"%ws", str.substr( i*100, min( str.size() - i*100, 100 ) ).c_str() ); } } else { - std::cout << str; + std::wcout << str; } } -void dprint( const std::string &str, bool dml ) +void dprint( const std::wstring &str, bool dml ) { g_dbgClient->dprint( str, dml ); } @@ -37,19 +37,19 @@ void dprint( const std::string &str, bool dml ) /////////////////////////////////////////////////////////////////////////////////// -void DebugClient::dprintln( const std::string &str, bool dml ) +void DebugClient::dprintln( const std::wstring &str, bool dml ) { - this->dprint( str + "\r\n", dml ); + this->dprint( str + L"\r\n", dml ); } -void dprintln( const std::string &str, bool dml ) +void dprintln( const std::wstring &str, bool dml ) { g_dbgClient->dprintln( str, dml ); } /////////////////////////////////////////////////////////////////////////////////// -void DebugClient::eprint( const std::string &str ) +void DebugClient::eprint( const std::wstring &str ) { if ( WindbgGlobalSession::isInit() ) { @@ -57,102 +57,64 @@ void DebugClient::eprint( const std::string &str ) { m_control->OutputWide( DEBUG_OUTPUT_ERROR, - L"%s", + L"%ws", str.substr( i*100, min( str.size() - i*100, 100 ) ).c_str() ); } } else { - std::cerr << str; + std::wcerr << str; } } -void eprint( const std::string &str ) +void eprint( const std::wstring &str ) { g_dbgClient->eprint( str ); } /////////////////////////////////////////////////////////////////////////////////// -void DebugClient::eprintln( const std::string &str ) +void DebugClient::eprintln( const std::wstring &str ) { - this->eprint( str + "\r\n"); + this->eprint( str + L"\r\n"); } -void eprintln( const std::string &str ) +void eprintln( const std::wstring &str ) { g_dbgClient->eprintln( str ); } /////////////////////////////////////////////////////////////////////////////////// +void +DbgOut::write( const std::wstring &str ) +{ + if ( WindbgGlobalSession::isInit() ) + { + for ( size_t i = 0; i < str.size() / 100 + 1; ++i ) + { + m_control->OutputWide( + DEBUG_OUTPUT_ERROR, + L"%ws", + str.substr( i*100, min( str.size() - i*100, 100 ) ).c_str() + ); + } + } + else + { + std::wcerr << str; + } +} + +/////////////////////////////////////////////////////////////////////////////////// + +std::string +DbgIn::readline() +{ + return ""; +} + +/////////////////////////////////////////////////////////////////////////////////// + }; // namesapce pykd - - - - - - - - - - - - - - - - - - - - -// -//void dbgPrint::dprint( const boost::python::object& obj, bool dml ) -//{ -// std::wstring str = boost::python::extract( obj ); -// -// if ( isWindbgExt() ) -// { -// -// for ( size_t i = 0; i < str.size() / 100 + 1; ++i ) -// { -// dbgExt->control4->ControlledOutputWide( -// dml ? DEBUG_OUTCTL_AMBIENT_DML : DEBUG_OUTCTL_AMBIENT_TEXT, DEBUG_OUTPUT_NORMAL, -// L"%ws", -// str.substr( i*100, min( str.size() - i*100, 100 ) ).c_str() -// ); -// } -// } -// else -// { -// std::wcout << str; -// } -//} -// -/////////////////////////////////////////////////////////////////////////////////// -// -//void dbgPrint::dprintln( const boost::python::object& obj, bool dml ) -//{ -// std::wstring str = boost::python::extract( obj ); -// str += L"\r\n"; -// -// if ( isWindbgExt() ) -// { -// for ( size_t i = 0; i < str.size() / 100 + 1; ++i ) -// { -// dbgExt->control4->ControlledOutputWide( -// dml ? DEBUG_OUTCTL_AMBIENT_DML : DEBUG_OUTCTL_AMBIENT_TEXT, DEBUG_OUTPUT_NORMAL, -// L"%ws", -// str.substr( i*100, min( str.size() - i*100, 100 ) ).c_str() -// ); -// } -// } -// else -// { -// std::wcout << str; -// } -//} -// -/////////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgio.h b/pykd/dbgio.h index aa1fc1a..7447171 100644 --- a/pykd/dbgio.h +++ b/pykd/dbgio.h @@ -1,238 +1,45 @@ #pragma once +#include "dbgobj.h" namespace pykd { /////////////////////////////////////////////////////////////////////////////////// -void dprint( const std::string &str, bool dml = false ); +void dprint( const std::wstring &str, bool dml = false ); -void dprintln( const std::string &str, bool dml = false ); +void dprintln( const std::wstring &str, bool dml = false ); -void eprint( const std::string &str ); +void eprint( const std::wstring &str ); -void eprintln( const std::string &str ); +void eprintln( const std::wstring &str ); -/////////////////////////////////////////////////////////////////////////////////// - -}; - - - - -// -//class dbgPrint { -// -//public: -// -// static void dprint( const boost::python::object& obj, bool dml = false ); -// -// static void dprintln( const boost::python::object& obj, bool dml = false ); -// -//}; -// ///////////////////////////////////////////////////////////////////////////////// -// -//// класс для перехвата вывода в отладчик -// -//class OutputReader : public IDebugOutputCallbacks { -// -//public: -// -// OutputReader( IDebugClient *debugClient ) -// { -// HRESULT hres; -// -// try { -// -// m_debugClient = debugClient; -// m_debugClient->AddRef(); -// -// hres = m_debugClient->GetOutputCallbacks( &m_previousCallback ); -// if ( FAILED( hres ) ) -// { -// throw hres; -// } -// -// hres = m_debugClient->SetOutputCallbacks( this ); -// if ( FAILED( hres ) ) -// { -// throw hres; -// } -// -// } catch( ... ) -// { -// m_debugClient->Release(); -// m_debugClient = NULL; -// } -// } -// -// ~OutputReader() -// { -// if ( m_debugClient ) -// { -// m_debugClient->SetOutputCallbacks( m_previousCallback ); -// m_debugClient->Release(); -// } -// } -// -// const std::string& -// Line() const { -// return m_readLine; -// } -// -//private: -// -// // IUnknown. -// STDMETHOD(QueryInterface)( -// __in REFIID InterfaceId, -// __out PVOID* Interface ) { -// return E_NOINTERFACE; -// } -// -// STDMETHOD_(ULONG, AddRef)() { -// return 1L; -// } -// -// -// STDMETHOD_(ULONG, Release)() { -// return 0L; -// } -// -// STDMETHOD(Output)( -// __in ULONG Mask, -// __in PCSTR Text ) -// { -// if ( Mask == DEBUG_OUTPUT_NORMAL ) -// { -// m_readLine += std::string( Text ); -// } -// -// return S_OK; -// } -// -//private: -// -// std::string m_readLine; -// -// IDebugClient *m_debugClient; -// -// IDebugOutputCallbacks *m_previousCallback; -//}; -// -///////////////////////////////////////////////////////////////////////////////// -// -//class InputReader : public IDebugInputCallbacks { -// -//public: -// -// InputReader( IDebugClient *debugClient ) -// { -// HRESULT hres; -// -// try { -// -// m_debugClient = debugClient; -// m_debugClient->AddRef(); -// -// hres = m_debugClient->GetInputCallbacks( &m_previousCallback ); -// if ( FAILED( hres ) ) -// { -// throw hres; -// } -// -// hres = m_debugClient->SetInputCallbacks( this ); -// if ( FAILED( hres ) ) -// { -// throw hres; -// } -// -// } catch( ... ) -// { -// m_debugClient->Release(); -// m_debugClient = NULL; -// } -// } -// -// ~InputReader() -// { -// if ( m_debugClient ) -// { -// m_debugClient->SetInputCallbacks( m_previousCallback ); -// m_debugClient->Release(); -// } -// } -// -// -//private: -// -// // IUnknown. -// STDMETHOD(QueryInterface)( -// __in REFIID InterfaceId, -// __out PVOID* Interface ) { -// return E_NOINTERFACE; -// } -// -// STDMETHOD_(ULONG, AddRef)() { -// return 1L; -// } -// -// -// STDMETHOD_(ULONG, Release)() { -// return 0L; -// } -// -// STDMETHOD( EndInput )() { -// return S_OK; -// } -// -// STDMETHOD( StartInput )( -// IN ULONG BufferSize ) { -// return S_OK; -// } -// -//private: -// -// IDebugClient *m_debugClient; -// -// IDebugInputCallbacks *m_previousCallback; -// -//}; -// -// -/////////////////////////////////////////////////////////////////////////////////// -// -//class dbgOut { -// -//public: -// -// void -// write( const boost::python::object &str ) { -// dbgPrint::dprint( str ); -// } -// -//}; -// -/////////////////////////////////////////////////////////////////////////////////// -// -//class dbgIn { -// -//public: -// -// std::string -// readline() { -// -// char str[100]; -// ULONG inputSize; -// -// OutputReader outputReader( dbgExt->client ); -// -// dbgExt->control->Input( str, sizeof(str), &inputSize ); -// -// return std::string( str ); -// } -// -//}; -// -/////////////////////////////////////////////////////////////////////////////////// +class DbgOut : private DbgObject { + +public: + + DbgOut( IDebugClient5 *client ) : DbgObject( client ) + {} + + void + write( const std::wstring &str ); +}; + +///////////////////////////////////////////////////////////////////////////////// + +class DbgIn : private DbgObject { + +public: + + DbgIn( IDebugClient5 *client ) : DbgObject( client ) + {} + + std::string + readline(); +}; + +///////////////////////////////////////////////////////////////////////////////// + +}; \ No newline at end of file diff --git a/pykd/dbgpath.h b/pykd/dbgpath.h index 3f790f1..6942fe6 100644 --- a/pykd/dbgpath.h +++ b/pykd/dbgpath.h @@ -1,6 +1,7 @@ #pragma once #include +#include /////////////////////////////////////////////////////////////////////////////// @@ -26,7 +27,5 @@ private: }; -//extern DbgPythonPath& dbgPythonPath; - /////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index 78ad19c..6817165 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -369,6 +369,10 @@ RelativePath=".\dbgmem.cpp" > + + @@ -451,6 +455,10 @@ RelativePath=".\dbgobj.h" > + +