From b06f99520050223b740c9e00f9c9cada5f465d67 Mon Sep 17 00:00:00 2001
From: "SND\\EreTIk_cp" <SND\EreTIk_cp@9b283d60-5439-405e-af05-b73fd8c4d996>
Date: Thu, 8 Sep 2011 17:53:36 +0000
Subject: [PATCH] [~] align of sruct [+] view MIDL-generated server
 RPC-interface

git-svn-id: https://pykd.svn.codeplex.com/svn@69642 9b283d60-5439-405e-af05-b73fd8c4d996
---
 pykd/dbgext.cpp     |  22 +++++----
 pykd/dbgtype.cpp    |  68 ++++++++++++++++++---------
 pykd/dbgtype.h      | 105 ++++++++++++++++++++++++------------------
 samples/rpcSrvIf.py | 109 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 229 insertions(+), 75 deletions(-)
 create mode 100644 samples/rpcSrvIf.py

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>( "typeInfo",
         "Class representing non-primitive type info: structure, union, etc. attributes is a fields of non-primitive type" )
         .def(boost::python::init<std::string,std::string>( boost::python::args("module", "type"), "constructor" ) )
         .def(boost::python::init<std::string>( boost::python::args("typeName"), "constructor" ) )
         .def(boost::python::init<std::string,ULONG>( 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>( "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("<unnamed-tag>") < 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("<unnamed-tag>") < 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<std::string, std::string>, 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('<exec cmd="dps 0x%x L 0x%x">Routine Table 0x%x, count %d (0x%02x)</exec>\n' % 
+            (dspTable, dspTableSize, dspTable, dspTableSize, dspTableSize) ,True)
+
+if __name__ == "__main__":
+  if len(sys.argv) == 2:
+    rpcSrvIf( expr(sys.argv[1]) )
+  else:
+    dprintln(rpcSrvIf.__doc__)