diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index 230a3e5..26befd6 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -221,17 +221,17 @@ BOOST_PYTHON_MODULE( pykd ) "Delete synthetic symbols by virtual address" ); boost::python::def( "delSynSymbolsMask", &delSyntheticSymbolsMask, "Delete synthetic symbols by mask of module and symbol name"); - - + + boost::python::class_( "typeInfo", "Class representing non-primitive type info: structure, union, etc. attributes is a fields of non-primitive type" ) .def(boost::python::init( boost::python::args("module", "type"), "constructor" ) ) .def(boost::python::init( boost::python::args("typeName"), "constructor" ) ) .def(boost::python::init( boost::python::args("typeName", "align"), "constructor" ) ) .def("size", &TypeInfo::size, - "Return full size of non-primitive type" ) + "Return full size of non-primitive type" ) .def("name", &TypeInfo::name, - "Return type's name" ) + "Return type's name" ) .def("__str__", &TypeInfo::print, "Return a nice string represention: print names and offsets of fields" ) .def("__getattr__", &TypeInfo::getField ) @@ -241,9 +241,11 @@ BOOST_PYTHON_MODULE( pykd ) "add new field for typeInfo" ) ) .def("offset", &TypeInfo::getFieldOffset, "Return offset while type is part of the more complex type" ) + .def("setAlignReq", &TypeInfo::setAlignReq, + "Set alignment requirement" ) .def("load", &TypeInfo::loadVar, loadOver( boost::python::args( "offset", "count"), "Create instance of the typedVar class with this typeInfo" ) ); - + DEF_PY_GLOBAL( "char_t", TypeInfo("", "char") ); DEF_PY_GLOBAL( "uchar_t", TypeInfo("", "unsigned char") ); DEF_PY_GLOBAL( "short_t", TypeInfo("", "short") ); @@ -251,11 +253,11 @@ BOOST_PYTHON_MODULE( pykd ) DEF_PY_GLOBAL( "long_t", TypeInfo("", "long") ); DEF_PY_GLOBAL( "ulong_t", TypeInfo("", "unsigned long") ); DEF_PY_GLOBAL( "int_t", TypeInfo("", "int") ); - DEF_PY_GLOBAL( "uint_t", TypeInfo("", "unsigned int") ); - DEF_PY_GLOBAL( "ptr_t", TypeInfo("", "void*") ); - DEF_PY_GLOBAL( "double_t", TypeInfo("", "double") ); - DEF_PY_GLOBAL( "longlong_t", TypeInfo("", "int64") ); - DEF_PY_GLOBAL( "ulonglong_t", TypeInfo("", "unsigned int64") ); + DEF_PY_GLOBAL( "uint_t", TypeInfo("", "unsigned int") ); + DEF_PY_GLOBAL( "ptr_t", TypeInfo("", "void*") ); + DEF_PY_GLOBAL( "double_t", TypeInfo("", "double") ); + DEF_PY_GLOBAL( "longlong_t", TypeInfo("", "int64") ); + DEF_PY_GLOBAL( "ulonglong_t", TypeInfo("", "unsigned int64") ); boost::python::class_( "typedVar", "Class of non-primitive type object, child class of typeClass. Data from target is copied into object instance" ) diff --git a/pykd/dbgtype.cpp b/pykd/dbgtype.cpp index e241099..bca22ae 100644 --- a/pykd/dbgtype.cpp +++ b/pykd/dbgtype.cpp @@ -20,6 +20,8 @@ TypeInfo::TypeInfoMap TypeInfo::g_typeInfoCache; /////////////////////////////////////////////////////////////////////////////////// TypeInfo::TypeInfo( const std::string &moduleName, const std::string &typeName ) + : m_align(0) + , m_alignReq(1) { HRESULT hres; bool baseType = checkBaseType(typeName); @@ -51,14 +53,14 @@ TypeInfo::TypeInfo( const std::string &moduleName, const std::string &typeName m_isPointer = true; m_size = ptrSize(); break; - } - + } + if ( baseType ) { m_isBaseType = true; m_size = getBaseTypeSize( typeName ); - break; - } + break; + } ULONG64 moduleBase = 0; hres = dbgExt->symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &moduleBase ); @@ -72,7 +74,7 @@ TypeInfo::TypeInfo( const std::string &moduleName, const std::string &typeName hres = dbgExt->symbols->GetTypeSize( moduleBase, typeId, &m_size ); if ( FAILED( hres ) ) - throw TypeException(); + throw TypeException(); for ( ULONG i = 0; ; ++i ) { @@ -103,13 +105,13 @@ TypeInfo::TypeInfo( const std::string &moduleName, const std::string &typeName if ( fieldTypeNameStr == "__unnamed" || fieldTypeNameStr.find("") < fieldTypeNameStr.size() ) { - m_fields.push_back( TypeField( fieldName, TypeInfo( moduleName, moduleBase, fieldTypeId ), fieldSize, fieldOffset ) ); + addField( fieldName, TypeInfo( moduleName, moduleBase, fieldTypeId ), fieldSize, fieldOffset ); } else { - m_fields.push_back( TypeField( fieldName, TypeInfo( moduleName, fieldTypeName ), fieldSize, fieldOffset ) ); - } - } + addField( fieldName, TypeInfo( moduleName, fieldTypeName ), fieldSize, fieldOffset ); + } + } } while( FALSE ); @@ -121,6 +123,8 @@ TypeInfo::TypeInfo( const std::string &moduleName, const std::string &typeName /////////////////////////////////////////////////////////////////////////////////// TypeInfo::TypeInfo( const std::string &moduleName, ULONG64 moduleBase, ULONG typeId ) + : m_align(0) + , m_alignReq(1) { HRESULT hres; @@ -162,11 +166,11 @@ TypeInfo::TypeInfo( const std::string &moduleName, ULONG64 moduleBase, ULONG typ if ( fieldTypeNameStr == "__unnamed" || fieldTypeNameStr.find("") < fieldTypeNameStr.size() ) { - m_fields.push_back( TypeField( fieldName, TypeInfo( moduleName, moduleBase, fieldTypeId ), fieldSize, fieldOffset ) ); + addField( fieldName, TypeInfo( moduleName, moduleBase, fieldTypeId ), fieldSize, fieldOffset ); } else { - m_fields.push_back( TypeField( fieldName, TypeInfo( moduleName, fieldTypeName ), fieldSize, fieldOffset ) ); + addField( fieldName, TypeInfo( moduleName, fieldTypeName ), fieldSize, fieldOffset ); } } @@ -278,8 +282,8 @@ TypeInfo::getFieldByIndex( boost::python::object &obj ) const } TypeInfo tinf = m_fields[index].type; - tinf.m_parentOffset = m_fields[index].offset; - return boost::python::object( tinf ); + tinf.m_parentOffset = m_fields[index].offset; + return boost::python::object( tinf ); } else { @@ -343,14 +347,10 @@ TypeInfo::appendField( const TypeInfo &typeInfo, const std::string &fieldName, U } ULONG offset = m_size; - - if ( typeInfo.isBaseType() ) - { - offset += offset % min( typeInfo.size(), m_align ); - } + offset += offset % ( m_align ? m_align : typeInfo.getAlignReq() ); const ULONG addSize = typeInfo.size() * count; - m_fields.push_back( TypeField( fieldName, typeInfo, addSize, offset ) ); + addField( fieldName, typeInfo, addSize, offset ); m_size = offset + addSize; m_arraySize = offset + addSize; } @@ -856,10 +856,10 @@ TypedVar::TypedVar( const TypeInfo &typeInfo, ULONG64 targetOffset, char* buffer { if ( bufferLength < typeInfo.size() ) throw TypeException(); - + m_buffer.insert( m_buffer.begin(), buffer, buffer + bufferLength ); } - + /////////////////////////////////////////////////////////////////////////////////// boost::python::object @@ -1001,6 +1001,32 @@ TypedVar::print() ///////////////////////////////////////////////////////////////////////////////////// +ULONG TypeInfo::getAlignReq() const +{ + if (isBaseType()) + return size(); + + if (isPtr()) + return ptrSize(); + + return m_alignReq; +} + +///////////////////////////////////////////////////////////////////////////////////// + +void TypeInfo::addField( + const std::string &name_, + const TypeInfo &type_, + ULONG size_, + ULONG offset_ +) +{ + m_alignReq = max(m_alignReq, type_.getAlignReq()); + m_fields.push_back( TypeField( name_, type_, size_, offset_ ) ); +} + +///////////////////////////////////////////////////////////////////////////////////// + ULONG sizeofType( const std::string &moduleName, const std::string &typeName ) { diff --git a/pykd/dbgtype.h b/pykd/dbgtype.h index 5c696c2..c362ba2 100644 --- a/pykd/dbgtype.h +++ b/pykd/dbgtype.h @@ -23,106 +23,112 @@ public: m_size(0), m_arraySize( 0 ), m_parentOffset( 0 ), - m_align( ptrSize() ), + m_align( 0 ), m_isFreezed( false ), m_isBaseType( false ), - m_isPointer( false ) + m_isPointer( false ), + m_alignReq(1) {} - TypeInfo( const std::string customName, ULONG align=0 ) : + TypeInfo( const std::string customName, ULONG align = 0) : m_typeName( customName ), m_size( 0 ), m_arraySize( 0 ), m_parentOffset( 0 ), m_isFreezed( false ), - m_align( align == 0 ? ptrSize() : align ), + m_align( align ), m_isBaseType( false ), - m_isPointer( false ) + m_isPointer( false ), + m_alignReq(1) {} - + TypeInfo( const std::string &moduleName, const std::string &typeName ); - + TypeInfo( const std::string &moduleName, ULONG64 moduleBase, ULONG typeId ); - + static const TypeInfo& get( const std::string &moduleName, const std::string &typeName ); - + ULONG size() const { return m_size; } - + ULONG count() const { assert( m_size != 0 && m_arraySize >= m_size ); return m_arraySize / m_size; } - + ULONG fullSize() const { return m_arraySize; } - + const std::string name() const { return m_typeName; } - + const std::string moduleName() const { return m_moduleName; } - + boost::python::object load( void* buffer, size_t bufferLength ) const; - + std::string printField( size_t index, void* buffer, size_t bufferLength ) const; - + std::string print() const; TypeInfo getField( const std::string &fieldName ) const; - + TypeInfo - getFieldAt( size_t index ) const; - + getFieldAt( size_t index ) const; + ULONG getFieldOffset() const { return m_parentOffset; } - + boost::python::object getFieldByIndex( boost::python::object &index ) const; - + size_t getFieldCount() const { return m_fields.size(); } - + void appendField( const TypeInfo &typeInfo, const std::string &fieldName, ULONG count = 1 ); - + bool isBaseType() const { return m_isBaseType; } - + bool isPtr() const { return m_isPointer; } - + bool isEnum() const { return !m_isBaseType && !m_isPointer && m_fields.size() == 0 && m_size == 4; } - + boost::python::object loadVar( ULONG64 targetOffset, ULONG count = 1) const; + void setAlignReq(ULONG alignReq) { + m_alignReq = alignReq; + } + public: typedef std::map< std::pair, TypeInfo> TypeInfoMap; @@ -154,46 +160,57 @@ public: private: + ULONG getAlignReq() const; + + void addField( + const std::string &name_, + const TypeInfo &type_, + ULONG size_, + ULONG offset_ + ); + typedef boost::python::object (*basicTypeLoader)( void* address, size_t size ); - + typedef std::string (*basicTypePrinter)( void* address, size_t size ); - + static TypeInfoMap g_typeInfoCache; - + static const char* basicTypeNames[]; - + static size_t basicTypeSizes[]; - + static basicTypeLoader basicTypeLoaders[]; - + static basicTypePrinter basicTypePrinters[]; ULONG m_size; - + ULONG m_arraySize; - + std::string m_typeName; - + std::string m_moduleName; - + TypeFieldList m_fields; - + bool m_isPointer; - + bool m_isBaseType; - + bool m_isFreezed; - + ULONG m_align; - - ULONG m_parentOffset; - + + ULONG m_alignReq; + + ULONG m_parentOffset; + static bool checkBaseType( const std::string &typeName ); - + static ULONG getBaseTypeSize( const std::string &typeName ); }; diff --git a/samples/rpcSrvIf.py b/samples/rpcSrvIf.py new file mode 100644 index 0000000..090f423 --- /dev/null +++ b/samples/rpcSrvIf.py @@ -0,0 +1,109 @@ +""" +Prase first param RpcServerRegisterIf[Xxx] +""" + +import sys +from pykd import * + +def rpcSrvIf(ifSpec): + """ + Prase RPC server interface specification + + Usage example: + + kd> ba e 1 rpcrt4!RPC_SERVER::RegisterInterface + kd> gc + + And analyze first parameter + + for x86: + kd> !py rpcSrvIf poi(@esp+@$ptrsize) + or for x64: + kd> !py rpcSrvIf @rdx + + P.S. RPC_SERVER::RegisterInterface called from: RpcServerRegisterIf, + RpcServerRegisterIf2 and RpcServerRegisterIfEx + + """ + + def formatSintaxId(synId): + + def formatGuid(guid): + part1 = "%08x-%04x-%04x" % (guid.data1, guid.data2, guid.data3) + part2 = "".join( ["%02x" % _byte for _byte in guid.data4] ) + part3 = "".join( ["%02x" % _byte for _byte in guid.data5] ) + return part1 + "-" + part2 + "-" + part3 + + def formatRpcVer(prcVer): + return "v.%d.%d" % (prcVer.MajorVersion, prcVer.MinorVersion) + + return formatGuid(synId.SyntaxGUID) + " " + formatRpcVer(synId.SyntaxVersion) + + # prepare structures for parsing + commGuid = typeInfo("rpcSrvIf~_GUID") + commGuid.append(ulong_t, "data1") + commGuid.append(ushort_t, "data2") + commGuid.append(ushort_t, "data3") + commGuid.append(uchar_t, "data4", 2) + commGuid.append(uchar_t, "data5", 6) + # print commGuid + + rpcVersion = typeInfo("rpcSrvIf~_RPC_VERSION") + rpcVersion.append(ushort_t, "MajorVersion") + rpcVersion.append(ushort_t, "MinorVersion") + # print rpcVersion + + rpcSintaxIdentifier = typeInfo("rpcSrvIf~_RPC_SYNTAX_IDENTIFIER") + rpcSintaxIdentifier.append(commGuid, "SyntaxGUID") + rpcSintaxIdentifier.append(rpcVersion, "SyntaxVersion") + # print rpcSintaxIdentifier + + prcDispatchTable = typeInfo("rpcSrvIf~_RPC_DISPATCH_TABLE") + prcDispatchTable.append(uint_t, "DispatchTableCount") + prcDispatchTable.append(ptr_t, "DispatchTable") + prcDispatchTable.append(ptr_t, "Reserved") + # print prcDispatchTable + + midlServerInfoHeader = typeInfo("rpcSrvIf~_MIDL_SERVER_INFO_hdr") + midlServerInfoHeader.append(ptr_t, "pStubDesc") + midlServerInfoHeader.append(ptr_t, "DispatchTable") + # print midlServerInfoHeader + + rpcServerInterface = typeInfo("rpcSrvIf~_RPC_SERVER_INTERFACE") + rpcServerInterface.append(uint_t, "Length") + rpcServerInterface.append(rpcSintaxIdentifier, "InterfaceId") + rpcServerInterface.append(rpcSintaxIdentifier, "TransferSyntax") + rpcServerInterface.append(ptr_t, "DispatchTable") # -> prcDispatchTable + rpcServerInterface.append(uint_t, "RpcProtseqEndpointCount") + rpcServerInterface.append(ptr_t, "RpcProtseqEndpoint") + rpcServerInterface.append(ptr_t, "DefaultManagerEpv") + rpcServerInterface.append(ptr_t, "InterpreterInfo") # -> midlServerInfoHeader + rpcServerInterface.append(uint_t, "Flags") + # print rpcServerInterface + + # get and print interface header + srvIf = rpcServerInterface.load( ifSpec ) + dprintln("Interface ID : " + formatSintaxId(srvIf.InterfaceId) ) + dprintln("Transfer Syntax : " + formatSintaxId(srvIf.TransferSyntax) ) + dprintln("Endpoint count : %d" % srvIf.RpcProtseqEndpointCount ) + if srvIf.RpcProtseqEndpointCount: + protoseqEndp = srvIf.RpcProtseqEndpoint + for i in range(0, srvIf.RpcProtseqEndpointCount): + dprintln("\t[%02d] protocol is `" % i + loadCStr( ptrPtr(protoseqEndp) ) + "'" ) + protoseqEndp += ptrSize() + dprintln("\t[%02d] endpoint is `" % i + loadCStr( ptrPtr(protoseqEndp) ) + "'" ) + protoseqEndp += ptrSize() + + dprintln("") + + # query dispatch routines table + dspTableSize = prcDispatchTable.load(srvIf.DispatchTable).DispatchTableCount + dspTable = midlServerInfoHeader.load(srvIf.InterpreterInfo).DispatchTable + dprintln('Routine Table 0x%x, count %d (0x%02x)\n' % + (dspTable, dspTableSize, dspTable, dspTableSize, dspTableSize) ,True) + +if __name__ == "__main__": + if len(sys.argv) == 2: + rpcSrvIf( expr(sys.argv[1]) ) + else: + dprintln(rpcSrvIf.__doc__)