From b63e923b3ed7f7bf251282541c31d797a28fcb78 Mon Sep 17 00:00:00 2001 From: "SND\\EreTIk_cp" Date: Fri, 16 Sep 2011 17:13:40 +0000 Subject: [PATCH] git-svn-id: https://pykd.svn.codeplex.com/svn@69803 9b283d60-5439-405e-af05-b73fd8c4d996 --- pykd/dbgexcept.cpp | 41 +++-- pykd/dbgexcept.h | 37 +---- pykd/dbgext.cpp | 121 ++++++++++++--- pykd/diawrapper.cpp | 265 ++++++++++++++++++++++++++++++++ pykd/diawrapper.h | 119 +++++++++++++- pykd/pykd_2008.vcproj | 32 ++-- pykd/stdafx.h | 2 + pykd_2008.vssscc | 10 ++ test/targetapp/targetapp.vcproj | 4 +- 9 files changed, 538 insertions(+), 93 deletions(-) create mode 100644 pykd/diawrapper.cpp create mode 100644 pykd_2008.vssscc diff --git a/pykd/dbgexcept.cpp b/pykd/dbgexcept.cpp index 9e7b8bf..470b47b 100644 --- a/pykd/dbgexcept.cpp +++ b/pykd/dbgexcept.cpp @@ -1,33 +1,28 @@ #include "stdafx.h" +#include "dbgexcept.h" + +using namespace pykd; + +//////////////////////////////////////////////////////////////////////////////// + +PyObject *DbgException::baseExceptTypeObject = NULL; + +///////////////////////////////////////////////////////////////////////////////// + +void DbgException::exceptionTranslate( const DbgException &e ) +{ + boost::python::object pyExcept(e); + + PyErr_SetObject( baseExceptTypeObject, pyExcept.ptr() ); +} + +///////////////////////////////////////////////////////////////////////////////// - - - -//#include "dbgexcept.h" -// -/////////////////////////////////////////////////////////////////////////////////// -// -//// типы исключений -// -//PyObject *baseExceptionType = NULL; //PyObject *eventExceptionType = NULL; //PyObject *typeExceptionType = NULL; //PyObject *memoryExceptionType = NULL; // -// -// -/////////////////////////////////////////////////////////////////////////////////// -// -//void DbgException::exceptionTranslate( const DbgException &e ) -//{ -// boost::python::object pyExcept(e); -// -// PyErr_SetObject( baseExceptionType, pyExcept.ptr()); -//} -// -/////////////////////////////////////////////////////////////////////////////////// -// //void WaitEventException::exceptionTranslate( const WaitEventException &e ) //{ // boost::python::object pyExcept(e); diff --git a/pykd/dbgexcept.h b/pykd/dbgexcept.h index 9758371..f69f803 100644 --- a/pykd/dbgexcept.h +++ b/pykd/dbgexcept.h @@ -22,45 +22,22 @@ public: static void exceptionTranslate(const DbgException &e ); + + static void setTypeObject(PyObject *p) { + baseExceptTypeObject = p; + } + +private: + static PyObject *baseExceptTypeObject; }; /////////////////////////////////////////////////////////////////////////////////// -extern PyObject *baseExceptionType; - -/////////////////////////////////////////////////////////////////////////////////// - }; // namespace pykd /////////////////////////////////////////////////////////////////////////////////// - - - - - -//#include -//#include -// -/////////////////////////////////////////////////////////////////////////////////// -// -//class DbgException : public std::exception -//{ -//public: -// -// DbgException( const std::string &desc ) : -// std::exception( desc.c_str() ) -// {} -// -// const char* getDesc() const { -// return what(); -// } -// -// static -// void -// exceptionTranslate(const DbgException &e ); -//}; // //class WaitEventException : public DbgException //{ diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index 989565f..ed1f933 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -1,12 +1,34 @@ #include "stdafx.h" #include +#include #include "module.h" #include "diawrapper.h" #include "dbgclient.h" -namespace python = boost::python; +using namespace pykd; + +//////////////////////////////////////////////////////////////////////////////// + +BOOL WINAPI DllMain( + __in HINSTANCE /*hinstDLL*/, + __in DWORD fdwReason, + __in LPVOID /*lpvReserved*/ +) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + CoInitialize(NULL); + break; + + case DLL_PROCESS_DETACH: + CoUninitialize(); + break; + } + return TRUE; +} //////////////////////////////////////////////////////////////////////////////// @@ -18,7 +40,7 @@ DebugExtensionInitialize( { *Version = DEBUG_EXTENSION_VERSION( 1, 0 ); *Flags = 0; - + return S_OK; } @@ -50,8 +72,14 @@ pycmd( PDEBUG_CLIENT4 client, PCSTR args ) //////////////////////////////////////////////////////////////////////////////// +#define DEF_PY_CONST(x) \ + python::scope().attr(#x) = ##x + BOOST_PYTHON_MODULE( pykd ) { + python::def( "diaOpenPdb", &pyDia::GlobalScope::openPdb, + "Open pdb file for quering debug symbols. Return DiaSymbol of global scope"); + python::class_("dbgClient", "Class representing a debugging session" ) .def( "loadDump", &pykd::DebugClient::loadDump, "Load crash dump" ) .def( "startProcess", &pykd::DebugClient::startProcess, "Start process for debugging" ) @@ -61,22 +89,83 @@ BOOST_PYTHON_MODULE( pykd ) python::class_("module", "Class representing executable module", python::no_init ) .def( python::init( "constructor" ) ); - // python::class_("dia", "class wrapper for MS DIA" ); + python::class_("DiaSymbol", "class wrapper for MS DIA Symbol" ) + .def( "findChildrenNoCase", &pyDia::Symbol::findChildrenNoCase, + "Retrieves the children of the symbol. Case Insensitive. SymTagNull for all symbols" ) + .def( "findChildren", &pyDia::Symbol::findChildren, + "Retrieves the children of the symbol. SymTagNull for all symbols" ) + .def( "size", &pyDia::Symbol::getSize, + "Retrieves the number of bits or bytes of memory used by the object represented by this symbol" ) + .def( "symTag", &pyDia::Symbol::getSymTag, + "Retrieves the symbol type classifier: SymTagXxx" ) + .def("__getattr__", &pyDia::Symbol::getChildByName) + .def("__len__", &pyDia::Symbol::getChildCount ) + .def("__getitem__", &pyDia::Symbol::getChildByIndex); + + python::class_ >("DiaScope", "class wrapper for MS DIA Symbol" ); + + // type of symbol + DEF_PY_CONST(SymTagNull); + DEF_PY_CONST(SymTagExe); + DEF_PY_CONST(SymTagCompiland); + DEF_PY_CONST(SymTagCompilandDetails); + DEF_PY_CONST(SymTagCompilandEnv); + DEF_PY_CONST(SymTagFunction); + DEF_PY_CONST(SymTagBlock); + DEF_PY_CONST(SymTagData); + DEF_PY_CONST(SymTagAnnotation); + DEF_PY_CONST(SymTagLabel); + DEF_PY_CONST(SymTagPublicSymbol); + DEF_PY_CONST(SymTagUDT); + DEF_PY_CONST(SymTagEnum); + DEF_PY_CONST(SymTagFunctionType); + DEF_PY_CONST(SymTagPointerType); + DEF_PY_CONST(SymTagArrayType); + DEF_PY_CONST(SymTagBaseType); + DEF_PY_CONST(SymTagTypedef); + DEF_PY_CONST(SymTagBaseClass); + DEF_PY_CONST(SymTagFriend); + DEF_PY_CONST(SymTagFunctionArgType); + DEF_PY_CONST(SymTagFuncDebugStart); + DEF_PY_CONST(SymTagFuncDebugEnd); + DEF_PY_CONST(SymTagUsingNamespace); + DEF_PY_CONST(SymTagVTableShape); + DEF_PY_CONST(SymTagVTable); + DEF_PY_CONST(SymTagCustom); + DEF_PY_CONST(SymTagThunk); + DEF_PY_CONST(SymTagCustomType); + DEF_PY_CONST(SymTagManagedType); + DEF_PY_CONST(SymTagDimension); + + // exception: + + // base exception + python::class_ dbgExceptionClass( "BaseException", + "Pykd base exception class", + python::no_init ); + dbgExceptionClass + .def( python::init( python::args("desc"), "constructor" ) ) + .def( "desc", &DbgException::getDesc, + "Get exception description" ); + DbgException::setTypeObject( dbgExceptionClass.ptr() ); + + // DIA exceptions + python::class_ > diaException( + "DiaException", + "Debug interface access exception", + python::no_init ); + pyDia::Exception::setTypeObject( diaException.ptr() ); + boost::python::register_exception_translator( + &pyDia::Exception::exceptionTranslate ); } +#undef DEF_PY_CONST + //////////////////////////////////////////////////////////////////////////////// - - - - - - - - //#include // //#include @@ -466,15 +555,6 @@ BOOST_PYTHON_MODULE( pykd ) // // // // исключения -// boost::python::class_ dbgExceptionClass( "BaseException", -// "Pykd base exception class", -// boost::python::no_init ); -// //boost::python::init() ); -// -// dbgExceptionClass -// .def( boost::python::init( boost::python::args("desc"), "constructor" ) ) -// .def( "desc", &DbgException::getDesc, -// "Get exception description" ); // // boost::python::class_ > waitExceptionClass( "WaitEventException", // "Type exception class", @@ -493,7 +573,6 @@ BOOST_PYTHON_MODULE( pykd ) // .def( "getAddress", &MemoryException::getAddress, // "Return target address" ); // -// baseExceptionType = dbgExceptionClass.ptr(); // eventExceptionType = waitExceptionClass.ptr(); // typeExceptionType = typeExceptionClass.ptr(); // memoryExceptionType = memoryExceptionClass.ptr(); diff --git a/pykd/diawrapper.cpp b/pykd/diawrapper.cpp new file mode 100644 index 0000000..e2eaf62 --- /dev/null +++ b/pykd/diawrapper.cpp @@ -0,0 +1,265 @@ + +#include "stdafx.h" + +#include +#include +#include + +#include "diawrapper.h" + +using namespace pykd; + +namespace pyDia { + +//////////////////////////////////////////////////////////////////////////////// + +PyObject *Exception::diaExceptTypeObject = NULL; + +//////////////////////////////////////////////////////////////////////////////// + +std::string Exception::makeFullDesc(const std::string &desc, HRESULT hres) +{ + std::strstream res; + res << "pyDia: " << desc << " failed" << std::endl; + res << "Return value is 0x" << std::hex << hres; + + PCHAR errMessage = NULL; + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + hres, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (PCHAR)&errMessage, + 0, + NULL); + if (errMessage) + { + res << ":" << std::endl; + res << errMessage; + LocalFree(errMessage); + } + else + { + res << std::endl; + } + + return res.str(); +} + +//////////////////////////////////////////////////////////////////////////////// + +void Exception::exceptionTranslate( const Exception &e ) +{ + boost::python::object pyExcept(e); + + PyErr_SetObject( diaExceptTypeObject, pyExcept.ptr() ); +} + +//////////////////////////////////////////////////////////////////////////////// +// Convert to OLESTR helper +//////////////////////////////////////////////////////////////////////////////// +class toOleStr { +public: + toOleStr(const std::string &sz) + { + m_buf.resize( sz.size() + 1, L'\0' ); + ::MultiByteToWideChar( CP_ACP, 0, sz.c_str(), sz.size(), &m_buf[0], m_buf.size() ); + } + + operator const OLECHAR *() const { + return m_buf.empty() ? NULL : &m_buf[0]; + } + +private: + std::vector m_buf; +}; + +//////////////////////////////////////////////////////////////////////////////// + +python::list Symbol::findChildrenImpl( + ULONG symTag, + const std::string &name, + DWORD nameCmpFlags +) +{ + throwIfNull(__FUNCTION__); + + CComPtr< IDiaEnumSymbols > symbols; + HRESULT hres = + m_symbol->findChildren( + static_cast(symTag), + toOleStr(name), + nameCmpFlags, + &symbols); + if (FAILED(hres)) + throw Exception("Get list of children", hres); + + python::list childList; + + CComPtr< IDiaSymbol > child; + ULONG celt; + while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) ) + childList.append( Symbol(child) ); + + return childList; +} + +//////////////////////////////////////////////////////////////////////////////// + +ULONGLONG Symbol::getSize() +{ + throwIfNull(__FUNCTION__); + + ULONGLONG retValue; + HRESULT hres = m_symbol->get_length(&retValue); + if (FAILED(hres)) + throw Exception("Get length", hres); + + return retValue; +} + +//////////////////////////////////////////////////////////////////////////////// + +ULONG Symbol::getSymTag() +{ + throwIfNull(__FUNCTION__); + + DWORD retValue; + HRESULT hres = m_symbol->get_symTag(&retValue); + if (FAILED(hres)) + throw Exception("Get symbol type", hres); + + return retValue; +} + +//////////////////////////////////////////////////////////////////////////////// + +python::object Symbol::getChildByName(const std::string &_name) +{ + throwIfNull(__FUNCTION__); + + CComPtr< IDiaEnumSymbols > symbols; + HRESULT hres = + m_symbol->findChildren( + SymTagNull, + toOleStr(_name), + nsCaseSensitive, + &symbols); + if (FAILED(hres)) + throw Exception("Get child by name", hres); + + LONG count; + hres = symbols->get_Count(&count); + if (FAILED(hres)) + throw Exception("Get count of children", hres); + + if (count != 1) + throw Exception("Query unique child", S_FALSE); + + CComPtr< IDiaSymbol > child; + hres = symbols->Item(0, &child); + if (FAILED(hres)) + throw Exception("Build child object", hres); + + return python::object( Symbol(child) ); +} + +//////////////////////////////////////////////////////////////////////////////// + +ULONG Symbol::getChildCount() +{ + throwIfNull(__FUNCTION__); + + CComPtr< IDiaEnumSymbols > symbols; + HRESULT hres = + m_symbol->findChildren( + SymTagNull, + NULL, + nsCaseSensitive, + &symbols); + if (FAILED(hres)) + throw Exception("Get child count", hres); + + LONG count; + hres = symbols->get_Count(&count); + if (FAILED(hres)) + throw Exception("Get count of count", hres); + + return count; +} + +//////////////////////////////////////////////////////////////////////////////// + +python::object Symbol::getChildByIndex(ULONG _index) +{ + throwIfNull(__FUNCTION__); + + CComPtr< IDiaEnumSymbols > symbols; + HRESULT hres = + m_symbol->findChildren( + SymTagNull, + NULL, + nsCaseSensitive, + &symbols); + if (FAILED(hres)) + throw Exception("Get child by index", hres); + + LONG count; + hres = symbols->get_Count(&count); + if (FAILED(hres)) + throw Exception("Get count of children", hres); + + if (LONG(_index) >= count) + throw Exception("Check child index", S_FALSE); + + CComPtr< IDiaSymbol > child; + hres = symbols->Item(_index, &child); + if (FAILED(hres)) + throw Exception("Build child object", hres); + + return python::object( Symbol(child) ); +} + +//////////////////////////////////////////////////////////////////////////////// + +GlobalScope::GlobalScope( + __inout CComPtr< IDiaDataSource > &_scope, + __inout CComPtr< IDiaSession > &_session, + __inout CComPtr< IDiaSymbol > &_globalScope +) : Symbol(_globalScope) + , m_source( _scope.Detach() ) + , m_session( _session.Detach() ) +{ +} + +//////////////////////////////////////////////////////////////////////////////// + +python::object GlobalScope::openPdb(const std::string &filePath) +{ + CComPtr< IDiaDataSource > _scope; + + HRESULT hres = + _scope.CoCreateInstance(__uuidof(DiaSource), NULL, CLSCTX_INPROC_SERVER); + if ( FAILED(hres) ) + throw Exception("Create scope instance", hres); + + hres = _scope->loadDataFromPdb( toOleStr(filePath) ); + if ( FAILED(hres) ) + throw Exception("Load pdb file", hres); + + CComPtr< IDiaSession > _session; + hres = _scope->openSession(&_session); + if ( FAILED(hres) ) + throw Exception("Open session for querying symbols", hres); + + CComPtr< IDiaSymbol > _globalScope; + hres = _session->get_globalScope(&_globalScope); + if ( FAILED(hres) ) + throw Exception("Retrieves a reference to the global scope", hres); + + return python::object(GlobalScope(_scope, _session, _globalScope)); +} + +//////////////////////////////////////////////////////////////////////////////// + +} diff --git a/pykd/diawrapper.h b/pykd/diawrapper.h index dfb452a..4bc2beb 100644 --- a/pykd/diawrapper.h +++ b/pykd/diawrapper.h @@ -1,9 +1,122 @@ + #pragma once +#include "dbgexcept.h" -namespace pykd { +namespace pyDia { -class DiaWrapper{ +//////////////////////////////////////////////////////////////////////////////// +// DIA Exceptions +//////////////////////////////////////////////////////////////////////////////// +class Exception : public pykd::DbgException { +public: + Exception(const std::string &desc, HRESULT hres) + : DbgException( makeFullDesc(desc, hres) ) + , m_hres(hres) + { + } + + HRESULT getRes() const { + return m_hres; + } + + static void exceptionTranslate(const Exception &e); + + static void setTypeObject(PyObject *p) { + diaExceptTypeObject = p; + } + +private: + + static PyObject *diaExceptTypeObject; + + static std::string makeFullDesc(const std::string &desc, HRESULT hres); + + HRESULT m_hres; }; +//////////////////////////////////////////////////////////////////////////////// +// Symbol +//////////////////////////////////////////////////////////////////////////////// +class Symbol { +public: + Symbol() {} -}; \ No newline at end of file + python::list findChildren( + ULONG symTag, + const std::string &name, + bool fnMatch + ) + { + return + findChildrenImpl( + symTag, + name, + fnMatch ? nsCaseSensitive : nsRegularExpression); + } + python::list findChildrenNoCase( + ULONG symTag, + const std::string &name, + bool fnMatch + ) + { + return + findChildrenImpl( + symTag, + name, + fnMatch ? nsCaseInsensitive : nsCaseInRegularExpression); + } + + ULONGLONG getSize(); + + ULONG getSymTag(); + + python::object getChildByName(const std::string &_name); + ULONG getChildCount(); + python::object getChildByIndex(ULONG _index); + +protected: + + void throwIfNull(const char *desc) + { + if (!m_symbol) + throw Exception(desc, S_FALSE); + } + + Symbol(__inout CComPtr< IDiaSymbol > _symbol) { + m_symbol = _symbol.Detach(); + } + + python::list findChildrenImpl( + ULONG symTag, + const std::string &name, + DWORD nameCmpFlags + ); + + CComPtr< IDiaSymbol > m_symbol; +}; + +//////////////////////////////////////////////////////////////////////////////// +// Global scope: source + sessions +//////////////////////////////////////////////////////////////////////////////// +class GlobalScope : public Symbol { +public: + GlobalScope() {} + + // create GlobalScope instance + static python::object openPdb(const std::string &filePath); + +private: + + GlobalScope( + __inout CComPtr< IDiaDataSource > &_scope, + __inout CComPtr< IDiaSession > &_session, + __inout CComPtr< IDiaSymbol > &_globalScope + ); + + CComPtr< IDiaDataSource > m_source; + CComPtr< IDiaSession > m_session; +}; + +//////////////////////////////////////////////////////////////////////////////// + +}; diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index d8c8fb4..bfbca6f 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -1,11 +1,11 @@ + + diff --git a/pykd/stdafx.h b/pykd/stdafx.h index 52a9e8f..b1273e3 100644 --- a/pykd/stdafx.h +++ b/pykd/stdafx.h @@ -30,6 +30,7 @@ #include #include +#include // //#ifndef __field_ecount_opt @@ -46,6 +47,7 @@ #include #include #pragma warning(pop) +namespace python = boost::python; // //#include // diff --git a/pykd_2008.vssscc b/pykd_2008.vssscc new file mode 100644 index 0000000..794f014 --- /dev/null +++ b/pykd_2008.vssscc @@ -0,0 +1,10 @@ +п»ї"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/test/targetapp/targetapp.vcproj b/test/targetapp/targetapp.vcproj index fbcff0c..ecb52b4 100644 --- a/test/targetapp/targetapp.vcproj +++ b/test/targetapp/targetapp.vcproj @@ -1,11 +1,11 @@