From d1a30dc6b09c5c490b4565ae3a0f3d4e4d8d53fc Mon Sep 17 00:00:00 2001
From: "SND\\kernelnet_cp"
 <SND\kernelnet_cp@9b283d60-5439-405e-af05-b73fd8c4d996>
Date: Tue, 22 May 2012 08:50:21 +0000
Subject: [PATCH] [0.1.x] fixed : issue #10767 ( typeInfo raises
 symbolException for classes with diamond virtual inheritance )

git-svn-id: https://pykd.svn.codeplex.com/svn@76514 9b283d60-5439-405e-af05-b73fd8c4d996
---
 pykd/diawrapper.cpp          |  19 +++++-
 pykd/diawrapper.h            |   4 ++
 pykd/typedvar.cpp            |  40 ++++++++++++-
 pykd/typedvar.h              |   2 +
 pykd/typeinfo.cpp            | 111 +++++++++++++++++++++++++++++++----
 pykd/typeinfo.h              |  66 ++++++++++++++++-----
 test/scripts/typedvar.py     |   1 -
 test/targetapp/targetapp.cpp |   6 +-
 8 files changed, 218 insertions(+), 31 deletions(-)

diff --git a/pykd/diawrapper.cpp b/pykd/diawrapper.cpp
index c70110f..b8cbbbd 100644
--- a/pykd/diawrapper.cpp
+++ b/pykd/diawrapper.cpp
@@ -174,10 +174,27 @@ ULONG Symbol::getCount()
 
 int Symbol::getVirtualBasePointerOffset()
 {
-    return callSymbol( get_virtualBasePointerOffset);
+    return callSymbol(get_virtualBasePointerOffset);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+
+ULONG Symbol::getVirtualBaseDispIndex()
+{
+    return callSymbol(get_virtualBaseDispIndex);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ULONG Symbol::getVirtualBaseDispSize()
+{
+   SymbolPtr   baseTableType = SymbolPtr( new Symbol( callSymbol(get_virtualBaseTableType), m_machineType ) );
+
+   return (ULONG)baseTableType->getType()->getSize();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 void Symbol::getValueImpl(IDiaSymbol *_symbol, VARIANT &vtValue)
 {
     HRESULT hres = _symbol->get_value(&vtValue);
diff --git a/pykd/diawrapper.h b/pykd/diawrapper.h
index f40e6a7..4b8c090 100644
--- a/pykd/diawrapper.h
+++ b/pykd/diawrapper.h
@@ -162,6 +162,10 @@ public:
 
     int getVirtualBasePointerOffset();
 
+    ULONG getVirtualBaseDispIndex();
+
+    ULONG getVirtualBaseDispSize();
+
 public:
     typedef std::pair<ULONG, const char *> ValueNameEntry;
 
diff --git a/pykd/typedvar.cpp b/pykd/typedvar.cpp
index c0343d9..3ea6395 100644
--- a/pykd/typedvar.cpp
+++ b/pykd/typedvar.cpp
@@ -238,7 +238,34 @@ UdtTypedVar::getField( const std::string &fieldName )
         return  TypedVar::getTypedVar( m_client, fieldType, VarDataMemory::factory(m_dataSpaces, fieldType->getStaticOffset() ) );
     }
 
-    return  TypedVar::getTypedVar( m_client, fieldType, m_varData->fork(fieldType->getOffset()) );
+    ULONG   fieldOffset = 0;
+
+    fieldOffset = fieldType->getOffset();
+
+    if ( fieldType->isVirtualMember() )
+    {
+        fieldOffset += getVirtualBaseDisplacement( fieldType );
+    }
+
+    return  TypedVar::getTypedVar( m_client, fieldType, m_varData->fork(fieldOffset) );
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
+LONG UdtTypedVar::getVirtualBaseDisplacement( TypeInfoPtr& typeInfo )
+{
+    ULONG virtualBasePtr, virtualDispIndex, virtualDispSize;
+    typeInfo->getVirtualDisplacement( virtualBasePtr, virtualDispIndex, virtualDispSize );
+
+    ULONG64     vbtableOffset = m_varData->fork( virtualBasePtr )->readPtr();
+
+    VarDataPtr   vbtable = VarDataMemory::factory(m_dataSpaces, vbtableOffset);
+
+    LONG   displacement = 0;
+
+    vbtable->read( &displacement, sizeof(displacement), virtualDispIndex*virtualDispSize );
+
+    return virtualBasePtr + displacement;
 }
 
 ///////////////////////////////////////////////////////////////////////////////////
@@ -264,8 +291,15 @@ std::string UdtTypedVar::print()
         }
         else
         {
-            fieldVar = TypedVar::getTypedVar( m_client, fieldType, m_varData->fork(fieldType->getOffset()) );
-            sstr << "   +" << std::right << std::setw(4) << std::setfill('0') << std::hex << fieldType->getOffset();
+            ULONG   fieldOffset = fieldType->getOffset();
+
+            if ( fieldType->isVirtualMember() )
+            {
+                fieldOffset += getVirtualBaseDisplacement( fieldType );
+            }
+
+            fieldVar = TypedVar::getTypedVar( m_client, fieldType, m_varData->fork(fieldOffset) );
+            sstr << "   +" << std::right << std::setw(4) << std::setfill('0') << std::hex << fieldOffset;
             sstr << " " << std::left << std::setw(24) << std::setfill(' ') << m_typeInfo->getFieldNameByIndex(i) << ':';
         }
 
diff --git a/pykd/typedvar.h b/pykd/typedvar.h
index 01313cf..acb32ff 100644
--- a/pykd/typedvar.h
+++ b/pykd/typedvar.h
@@ -177,6 +177,8 @@ public:
     virtual std::string  printValue();
 
     virtual TypedVarPtr getField( const std::string &fieldName );
+
+    LONG getVirtualBaseDisplacement( TypeInfoPtr& typeInfo );
 };
 
 ///////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/typeinfo.cpp b/pykd/typeinfo.cpp
index 1ae8024..1f50114 100644
--- a/pykd/typeinfo.cpp
+++ b/pykd/typeinfo.cpp
@@ -475,10 +475,39 @@ TypeInfoPtr TypeInfo::getRecurciveComplexType( TypeInfoPtr &lowestType, std::str
 
 /////////////////////////////////////////////////////////////////////////////////////
 
+ULONG64 TypeInfo::getStaticOffset() {
+    if ( !m_staticMember )
+        throw TypeException( getName(), "This is not a static member" );
+
+    return m_staticOffset;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+ULONG TypeInfo::getOffset() {
+
+   if ( m_staticOffset )
+       throw TypeException( getName(), "This is a static member" );
+
+    return m_offset;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+ULONG64 TypeInfo::getTypeOffset()
+{
+   return m_staticMember ? m_staticOffset : m_offset;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
 TypeInfoPtr UdtTypeInfo::getField( const std::string &fieldName )
 {
     if ( m_fields.empty() )
-        getFields( m_dia );
+    {
+        getFields( m_dia, pyDia::SymbolPtr() );
+        getVirtualFields();
+    }
 
     FieldList::reverse_iterator  it;
         
@@ -495,7 +524,10 @@ TypeInfoPtr UdtTypeInfo::getField( const std::string &fieldName )
 TypeInfoPtr UdtTypeInfo::getFieldByIndex( ULONG index )
 {
     if ( m_fields.empty() )
-        getFields( m_dia );
+    {
+        getFields( m_dia, pyDia::SymbolPtr() );
+        getVirtualFields();
+    }
 
     return m_fields[ index ].second;
 }
@@ -505,7 +537,10 @@ TypeInfoPtr UdtTypeInfo::getFieldByIndex( ULONG index )
 std::string UdtTypeInfo::getFieldNameByIndex( ULONG index )
 {
     if ( m_fields.empty() )
-        getFields( m_dia);
+    {
+        getFields( m_dia, pyDia::SymbolPtr() );
+        getVirtualFields();
+    }
 
     return m_fields[ index ].first;
 }
@@ -515,14 +550,23 @@ std::string UdtTypeInfo::getFieldNameByIndex( ULONG index )
 ULONG UdtTypeInfo::getFieldCount()
 {
     if ( m_fields.empty() )
-        getFields( m_dia );
+    {
+        getFields( m_dia, pyDia::SymbolPtr() );
+        getVirtualFields();
+    }
 
     return (ULONG)m_fields.size();
 }
 
 /////////////////////////////////////////////////////////////////////////////////////
 
-void UdtTypeInfo::getFields( pyDia::SymbolPtr &rootSym, ULONG startOffset )
+void UdtTypeInfo::getFields( 
+        pyDia::SymbolPtr &rootSym, 
+        pyDia::SymbolPtr &baseVirtualSym,
+        ULONG startOffset,        
+        LONG virtualBasePtr,
+        ULONG virtualDispIndex,
+        ULONG virtualDispSize )
 {
     ULONG   childCount = rootSym->getChildCount();  
 
@@ -536,18 +580,29 @@ void UdtTypeInfo::getFields( pyDia::SymbolPtr &rootSym, ULONG startOffset )
         {
             if ( !childSym->isVirtualBaseClass() )
             {
-                getFields( childSym, startOffset + childSym->getOffset() );
+                getFields( childSym, pyDia::SymbolPtr(), startOffset + childSym->getOffset() );
             }
         }
         else
         if ( symTag == SymTagData )
         {
-            TypeInfoPtr     ti = TypeInfo::getTypeInfo( m_dia, childSym );
+            TypeInfoPtr     ti = TypeInfo::getTypeInfo( rootSym, childSym );
 
             switch ( childSym->getDataKind() )
             {
             case DataIsMember:
+
+                if ( baseVirtualSym  )
+                {
+                    ti->setVirtualBase( 
+                        TypeInfo::getTypeInfo(baseVirtualSym),
+                        virtualBasePtr,
+                        virtualDispIndex, 
+                        virtualDispSize );
+                }
+
                 ti->setOffset( startOffset + childSym->getOffset() );
+
                 break;
 
             case DataIsStaticMember:
@@ -560,15 +615,41 @@ void UdtTypeInfo::getFields( pyDia::SymbolPtr &rootSym, ULONG startOffset )
         else
         if ( symTag == SymTagVTable )
         {
-            TypeInfoPtr     ti = TypeInfo::getTypeInfo( m_dia, childSym );
+            if ( !baseVirtualSym )
+            {
+                TypeInfoPtr     ti = TypeInfo::getTypeInfo( rootSym, childSym );
 
-            m_fields.push_back( std::make_pair( "__VFN_table", ti ) );            
+                m_fields.push_back( std::make_pair( "__VFN_table", ti ) ); 
+            }
         }
     }  
 }
 
 /////////////////////////////////////////////////////////////////////////////////////
 
+void UdtTypeInfo::getVirtualFields()
+{
+    ULONG   childCount = m_dia->getChildCount<SymTagBaseClass>();  
+
+    for ( ULONG i = 0; i < childCount; ++i )
+    {
+        pyDia::SymbolPtr  childSym = m_dia->getChildByIndex( i );
+
+        if ( !childSym->isVirtualBaseClass() )
+            continue;
+
+        getFields( 
+            childSym,
+            childSym,
+            0,
+            childSym->getVirtualBasePointerOffset(),
+            childSym->getVirtualBaseDispIndex(),
+            childSym->getVirtualBaseDispSize() );
+    }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
 std::string UdtTypeInfo::print()
 {
     std::stringstream  sstr;
@@ -587,6 +668,16 @@ std::string UdtTypeInfo::print()
             sstr << " " << std::left << std::setw(18) << std::setfill(' ') << getFieldNameByIndex(i) << ':';
         }
         else
+        if ( fieldType->isVirtualMember() )
+        {           
+            ULONG virtualBasePtr, virtualDispIndex, virtualDispSize;
+            fieldType->getVirtualDisplacement( virtualBasePtr, virtualDispIndex, virtualDispSize );
+
+            sstr << "   virtual base " <<  fieldType->getVirtualBase()->getName();
+            sstr << " +" << std::right << std::setw(4) << std::setfill('0') << std::hex << fieldType->getOffset();
+            sstr << " " << getFieldNameByIndex(i) << ':';
+        }
+        else
         {
             sstr << "   +" << std::right << std::setw(4) << std::setfill('0') << std::hex << fieldType->getOffset();
             sstr << " " << std::left << std::setw(24) << std::setfill(' ') << getFieldNameByIndex(i) << ':';
@@ -644,7 +735,7 @@ std::string EnumTypeInfo::getFieldNameByIndex( ULONG index )
 
 ULONG EnumTypeInfo::getFieldCount()
 {
-    return m_dia->getChildCount();    
+    return m_dia->getChildCount();
 }
 
 /////////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/typeinfo.h b/pykd/typeinfo.h
index 488dcd0..320b545 100644
--- a/pykd/typeinfo.h
+++ b/pykd/typeinfo.h
@@ -42,12 +42,15 @@ public:
         m_offset( 0 ),
         m_staticOffset( 0 ),
         m_constant( false ),
-        m_staticMember( false )
+        m_staticMember( false ),
+        m_virtualMember( false ),
+        m_virtualBasePtr( 0 ),
+        m_virtualDispIndex( 0 ),
+        m_virtualDispSize( 0 )
         {
             m_constantValue.vt = VT_EMPTY;
         }
 
-
     virtual std::string print() {
         std::stringstream   sstr;
         sstr << "Type name: " << getName();
@@ -125,10 +128,6 @@ public:
         throw TypeException( getName(), "type is not a pointer" );
     }
 
-    ULONG getOffset() const {
-        return (ULONG)m_offset;
-    }
-
     void setOffset( ULONG offset ) {
         m_offset = offset;
     }
@@ -138,7 +137,6 @@ public:
         m_constant = true;
         m_constantValue = var;
     }
-
     bool isConstant() const
     {
        return  m_constant == true;
@@ -149,19 +147,40 @@ public:
        return  m_staticMember == true;
     }
 
+    bool isVirtualMember() const 
+    {
+        return m_virtualMember == true;
+    }
+
     void setStaticOffset( ULONG64 offset ) {
-        m_staticOffset = offset;     
+        m_staticOffset = offset; 
         m_staticMember = true;
     }
 
-    ULONG64 getStaticOffset() const {
-        return m_staticOffset;
+    void setVirtualBase( TypeInfoPtr virtualBase, LONG virtualBasePtr, ULONG virtualDispIndex, ULONG virtualDispSize )
+    {
+        m_virtualMember = true;
+        m_virtualBaseType = virtualBase;
+        m_virtualBasePtr = virtualBasePtr;
+        m_virtualDispIndex = virtualDispIndex;
+        m_virtualDispSize = virtualDispSize;
     }
 
-    ULONG64 getTypeOffset() const {
-        return m_staticMember ? m_staticOffset : m_offset;
-    }
+    ULONG64 getTypeOffset();
 
+    ULONG getOffset();
+
+    ULONG64 getStaticOffset();
+
+    void getVirtualDisplacement( ULONG &virtualBasePtr, ULONG &virtualDispIndex, ULONG &virtualDispSize ) {
+        virtualBasePtr = m_virtualBasePtr;
+        virtualDispIndex = m_virtualDispIndex;
+        virtualDispSize = m_virtualDispSize;
+    };
+
+    TypeInfoPtr getVirtualBase() {
+        return m_virtualBaseType;
+    }
 
 protected:
 
@@ -181,7 +200,17 @@ protected:
 
     bool        m_staticMember;
 
+    bool        m_virtualMember;
+
     VARIANT     m_constantValue;
+
+    LONG        m_virtualBasePtr;
+
+    ULONG       m_virtualDispIndex;
+
+    ULONG       m_virtualDispSize;
+
+    TypeInfoPtr m_virtualBaseType;    
 };
 
 ///////////////////////////////////////////////////////////////////////////////////
@@ -290,7 +319,16 @@ protected:
     
     FieldList           m_fields;
 
-    void getFields( pyDia::SymbolPtr &rootSym, ULONG startOffset = 0 );
+    void getFields( 
+        pyDia::SymbolPtr &rootSym, 
+        pyDia::SymbolPtr &baseVirtualSym,
+        ULONG startOffset = 0,
+        LONG virtualBasePtr = 0,
+        ULONG virtualDispIndex = 0,
+        ULONG m_virtualDispSize = 0 );
+
+
+    void getVirtualFields();
 };
 
 ///////////////////////////////////////////////////////////////////////////////////
diff --git a/test/scripts/typedvar.py b/test/scripts/typedvar.py
index 53437a5..7ee527f 100644
--- a/test/scripts/typedvar.py
+++ b/test/scripts/typedvar.py
@@ -248,7 +248,6 @@ class TypedVarTest( unittest.TestCase ):
         
     def testDiamondVirtualInherit(self):
         tv = pykd.typedVar( "g_virtChild" )
-        print tv
         self.assertEqual( -100, tv.m_baseField )
     
     def testDinkumwareMap(self):
diff --git a/test/targetapp/targetapp.cpp b/test/targetapp/targetapp.cpp
index ee92d37..62e5dbb 100644
--- a/test/targetapp/targetapp.cpp
+++ b/test/targetapp/targetapp.cpp
@@ -335,10 +335,12 @@ public:
     virtual void virtFunc2() {}
 };
 
-class VirtualChildClass : public VirtualBaseClass1, public  VirtualBaseClass2, public virtual classBase
+class VirtualChildClass : public VirtualBaseClass1, public  VirtualBaseClass2
 {
     void virtFunc() {}
     void virtFunc2() {}
+
+    void virtual virtFunc3() {}
 };
 
 VirtualChildClass       g_virtChild;
@@ -426,7 +428,7 @@ void FuncWithName0()
 
     std::cout << g_structTypeDef.m_field0;
 
-    std::cout << g_virtChild.VirtualBaseClass1::m_baseField;
+    //std::cout << g_virtChild.VirtualBaseClass1::m_baseField;
 }
 
 ////////////////////////////////////////////////////////////////////////////////