Commit 33121b43 authored by ussrhero's avatar ussrhero
Browse files

Merge branch 'vtbl' into 'dev-1.0'

Vtbl

See merge request !33
parents 274e95ec 966e0767
......@@ -107,6 +107,8 @@ bool getArrayExpression( std::wstring &suffix, size_t &arraySize )
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
} // end nameless namespace
namespace kdlib {
......@@ -564,6 +566,153 @@ bool isPrototypeMatch(TypeInfoPtr& methodType, const std::wstring& methodProtot
///////////////////////////////////////////////////////////////////////////////
std::vector<TypeFieldPtr> enumFields(
const SymbolPtr &rootSym,
const SymbolPtr &parentSym,
MEMOFFSET_32 startOffset = 0,
MEMOFFSET_32 virtualBasePtr = 0,
size_t virtualDispIndex = 0,
size_t virtualDispSize = 0)
{
std::vector<TypeFieldPtr> fields;
bool firstVtbl = true;
size_t childCount = parentSym->getChildCount();
for (unsigned long i = 0; i < childCount; ++i)
{
SymbolPtr childSym = parentSym->getChildByIndex(i);
SymTags symTag = childSym->getSymTag();
if (symTag == SymTagBaseClass)
{
if (childSym->isVirtualBaseClass() )
{
if (rootSym != parentSym)
continue;
auto childFields = enumFields(
rootSym,
childSym,
0,
childSym->getVirtualBasePointerOffset(),
childSym->getVirtualBaseDispIndex(),
childSym->getVirtualBaseDispSize());
for (const auto& childField : childFields)
{
fields.push_back(childField);
}
}
else
{
auto childFields = enumFields(
rootSym,
childSym,
startOffset + childSym->getOffset(),
virtualBasePtr,
virtualDispIndex,
virtualDispSize);
for (const auto& childField : childFields)
{
if (childField->isVtbl() && firstVtbl)
{
firstVtbl = false;
auto vtblField = SymbolUdtField::getVtblField(
parentSym->getVirtualTableShape(),
L"__VFN_table",
startOffset + childSym->getOffset(),
virtualBasePtr,
virtualDispIndex,
virtualDispSize);
fields.push_back(vtblField);
}
else
{
fields.push_back(childField);
}
}
}
}
else
if (symTag == SymTagData)
{
TypeFieldPtr fieldPtr;
auto dataKind = childSym->getDataKind();
switch (dataKind)
{
case DataIsMember:
fieldPtr = SymbolUdtField::getField(
childSym,
childSym->getName(),
startOffset + childSym->getOffset(),
virtualBasePtr,
virtualDispIndex,
virtualDispSize);
break;
case DataIsStaticMember:
{
MEMOFFSET_64 staticOffset = 0L;
try
{
staticOffset = childSym->getVa();
}
catch (SymbolException&)
{
}
fieldPtr = SymbolUdtField::getStaticField(childSym, childSym->getName(), staticOffset);
}
break;
case DataIsConstant:
fieldPtr = SymbolUdtField::getConstField(childSym, childSym->getName());
break;
default:
continue;
}
if (rootSym != parentSym)
fieldPtr->setMemberInherited();
fields.push_back(fieldPtr);
}
else
if (symTag == SymTagVTable)
{
TypeFieldPtr fieldPtr;
fieldPtr = SymbolUdtField::getVtblField(
parentSym->getVirtualTableShape(),
L"__VFN_table",
startOffset + childSym->getOffset(),
virtualBasePtr,
virtualDispIndex,
virtualDispSize);
fields.push_back( fieldPtr );
}
else
if (symTag == SymTagEnum)
{
auto childFields = enumFields(rootSym, childSym, startOffset);
for (const auto& childField : childFields)
fields.push_back(childField);
}
}
return fields;
}
///////////////////////////////////////////////////////////////////////////////
static const std::wregex baseMatch(L"^(Char)|(WChar)|(Int1B)|(UInt1B)|(Int2B)|(UInt2B)|(Int4B)|(UInt4B)|(Int8B)|(UInt8B)|(Long)|(ULong)|(Float)|(Bool)|(Double)|(Void)|(Hresult)|(NoType)$" );
bool TypeInfo::isBaseType( const std::wstring &typeName )
......@@ -1047,8 +1196,14 @@ TypeInfoPtr TypeInfoFields::getElement( const std::wstring &name )
TypeInfoPtr fieldType = m_fields.lookup( std::wstring( name, 0, pos) )->getTypeInfo();
if ( pos == std::wstring::npos )
if (pos == std::wstring::npos)
{
if (fieldType->isVtbl())
{
return fieldType->ptrTo(fieldType->getPtrSize());
}
return fieldType;
}
return fieldType->getElement( std::wstring( name, pos + 1 ) );
}
......@@ -1059,7 +1214,12 @@ TypeInfoPtr TypeInfoFields::getElement(size_t index )
{
checkFields();
return m_fields.lookup(index)->getTypeInfo();
auto typeInfo = m_fields.lookup(index)->getTypeInfo();
if (typeInfo->isVtbl())
{
return typeInfo->ptrTo(typeInfo->getPtrSize());
}
return typeInfo;
}
///////////////////////////////////////////////////////////////////////////////
......@@ -1542,135 +1702,10 @@ TypeInfoPtr TypeInfoUdt::getVTBL()
void TypeInfoUdt::getFields()
{
getFields( m_symbol, SymbolPtr() );
getVirtualFields();
}
///////////////////////////////////////////////////////////////////////////////
void TypeInfoUdt::getFields(
const SymbolPtr &rootSym,
const SymbolPtr &baseVirtualSym,
MEMOFFSET_32 startOffset,
MEMOFFSET_32 virtualBasePtr,
size_t virtualDispIndex,
size_t virtualDispSize )
{
size_t childCount = rootSym->getChildCount();
for ( unsigned long i = 0; i < childCount; ++i )
{
SymbolPtr childSym = rootSym->getChildByIndex( i );
SymTags symTag = childSym->getSymTag();
if ( symTag == SymTagBaseClass )
{
if ( !childSym->isVirtualBaseClass() )
{
getFields( childSym, SymbolPtr(), startOffset + childSym->getOffset() );
}
}
else
if ( symTag == SymTagData )
{
TypeFieldPtr fieldPtr;
auto dataKind = childSym->getDataKind();
switch (dataKind )
{
case DataIsMember:
if ( baseVirtualSym )
{
fieldPtr = SymbolUdtField::getVirtualField( childSym, childSym->getName(), startOffset + childSym->getOffset(), virtualBasePtr, virtualDispIndex, virtualDispSize );
}
else
{
fieldPtr = SymbolUdtField::getField( childSym, childSym->getName(), startOffset + childSym->getOffset() );
}
break;
case DataIsStaticMember:
{
std::wstring fieldName = childSym->getName();
MEMOFFSET_64 staticOffset = 0L;
try
{
staticOffset = childSym->getVa();
}
catch (SymbolException&)
{
}
fieldPtr = SymbolUdtField::getStaticField(childSym, fieldName, staticOffset);
}
break;
case DataIsConstant:
fieldPtr = SymbolUdtField::getConstField(childSym, childSym->getName());
break;
default:
throw TypeException(m_name, L"Unsupported field type");
}
if (rootSym != m_symbol)
fieldPtr->setMemberInherited();
m_fields.push_back( fieldPtr );
}
else
if ( symTag == SymTagVTable )
{
TypeFieldPtr fieldPtr;
if ( baseVirtualSym )
{
fieldPtr = SymbolUdtField::getVirtualField( childSym, L"__VFN_table", startOffset + childSym->getOffset(), virtualBasePtr, virtualDispIndex, virtualDispSize );
}
else
{
fieldPtr = SymbolUdtField::getField( childSym, L"__VFN_table", startOffset + childSym->getOffset() );
}
m_fields.push_back( fieldPtr );
}
else
if (symTag == SymTagEnum)
{
getFields(childSym, SymbolPtr(), startOffset);
}
}
}
///////////////////////////////////////////////////////////////////////////////
void TypeInfoUdt::getVirtualFields()
{
SymbolPtrList baseClasses = m_symbol->findChildren(SymTagBaseClass);
for ( SymbolPtrList::iterator baseClass = baseClasses.begin(); baseClass != baseClasses.end(); ++baseClass)
{
SymbolPtr childSym = *baseClass;
std::wstring baseClassName = childSym->getName();
auto fields = kdlib::enumFields(m_symbol, m_symbol);
if ( !childSym->isVirtualBaseClass() )
continue;
getFields(
childSym,
childSym,
0,
childSym->getVirtualBasePointerOffset(),
childSym->getVirtualBaseDispIndex(),
childSym->getVirtualBaseDispSize() );
}
for (auto& field : fields)
m_fields.push_back(field);
}
///////////////////////////////////////////////////////////////////////////////
......
......@@ -542,17 +542,6 @@ protected:
virtual void getVirtualDisplacement( const std::wstring& fieldName, MEMOFFSET_32 &virtualBasePtr, size_t &virtualDispIndex, size_t &virtualDispSize );
virtual void getVirtualDisplacement( size_t fieldIndex, MEMOFFSET_32 &virtualBasePtr, size_t &virtualDispIndex, size_t &virtualDispSize );
void getFields(
const SymbolPtr &rootSym,
const SymbolPtr &baseVirtualSym,
MEMOFFSET_32 startOffset = 0,
MEMOFFSET_32 virtualBasePtr = 0,
size_t virtualDispIndex = 0,
size_t m_virtualDispSize = 0 );
void getVirtualFields();
};
///////////////////////////////////////////////////////////////////////////////
......
......@@ -88,6 +88,11 @@ public:
return m_inheritedMember;
}
bool isVtbl() const
{
return m_vtblMember;
}
void setMemberInherited()
{
m_inheritedMember = true;
......@@ -130,7 +135,8 @@ protected:
m_virtualMember( false ),
m_methodMember(false),
m_constMember(false),
m_inheritedMember(false)
m_inheritedMember(false),
m_vtblMember(false)
{}
std::wstring m_name;
......@@ -150,6 +156,7 @@ protected:
bool m_methodMember;
bool m_constMember;
bool m_inheritedMember;
bool m_vtblMember;
};
///////////////////////////////////////////////////////////////////////////////////
......@@ -161,10 +168,18 @@ public:
static TypeFieldPtr getField(
const SymbolPtr &sym,
const std::wstring& name,
MEMOFFSET_32 offset )
MEMOFFSET_32 offset,
MEMOFFSET_32 virtualBasePtr,
size_t virtualDispIndex,
size_t virtualDispSize)
{
SymbolUdtField *p = new SymbolUdtField( sym, name );
p->m_offset = offset;
p->m_virtualBasePtr = virtualBasePtr;
p->m_virtualDispIndex = virtualDispIndex;
p->m_virtualDispSize = virtualDispSize;
p->m_virtualMember = virtualBasePtr != 0;
return TypeFieldPtr(p);
}
......@@ -188,23 +203,6 @@ public:
return TypeFieldPtr(p);
}
static TypeFieldPtr getVirtualField(
const SymbolPtr &sym,
const std::wstring& name,
MEMOFFSET_32 offset,
MEMOFFSET_32 virtualBasePtr,
size_t virtualDispIndex,
size_t virtualDispSize )
{
SymbolUdtField *p = new SymbolUdtField( sym, name );
p->m_offset = offset;
p->m_virtualBasePtr = virtualBasePtr;
p->m_virtualDispIndex = virtualDispIndex;
p->m_virtualDispSize = virtualDispSize;
p->m_virtualMember = true;
return TypeFieldPtr(p);
}
static TypeFieldPtr getVirtualMethodField(
const SymbolPtr& sym,
const std::wstring& name
......@@ -216,6 +214,24 @@ public:
return TypeFieldPtr(p);
}
static TypeFieldPtr getVtblField(
const SymbolPtr& sym,
const std::wstring& name,
MEMOFFSET_32 offset,
MEMOFFSET_32 virtualBasePtr,
size_t virtualDispIndex,
size_t virtualDispSize
)
{
SymbolUdtField *p = new SymbolUdtField(sym, name);
p->m_vtblMember = true;
p->m_offset = offset;
p->m_virtualBasePtr = virtualBasePtr;
p->m_virtualDispIndex = virtualDispIndex;
p->m_virtualDispSize = virtualDispSize;
p->m_virtualMember = virtualBasePtr != 0;
return TypeFieldPtr(p);
}
public:
......
......@@ -12,8 +12,8 @@ namespace kdlib {
const TypeFieldPtr& FieldCollection::lookup(const std::wstring &name) const
{
FieldList::const_reverse_iterator it;
for ( it = m_fields.rbegin(); it != m_fields.rend(); ++it )
FieldList::const_iterator it;
for (it = m_fields.begin(); it != m_fields.end(); ++it)
{
if ( (*it)->getName() == name )
return *it;
......
......@@ -303,16 +303,67 @@ TEST_F( TypedVarTest, FunctionDebugRange )
ASSERT_LE(std::ptrdiff_t(funcptr->getDebugEnd()), static_cast<std::ptrdiff_t>(std::ptrdiff_t(funcptr->getAddress()) + funcptr->getSize()));
}
TEST_F(TypedVarTest, getVTBL)
{
// vtbl#1:
// classProBase1::virtMethod1 ( int virtMethod1(float a)
// classChild::virtMethod1 ( inherited from classBase1 int virtMethod1(int a) )
// classBase1::virtMethod2
TypedVarPtr var;
ASSERT_NO_THROW(var = loadTypedVar(L"g_classChild"));
ASSERT_TRUE(var->getElement(0)->getType()->deref()->isVtbl());
TypedVarPtr vtbl = var->getElement(0)->deref();
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(0)).find(L"classProBase1"));
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(1)).find(L"virtMethod1"));
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(2)).find(L"virtMethod2"));
EXPECT_THROW(vtbl->getElement(3), kdlib::IndexException);
}
TEST_F(TypedVarTest, getVTBLByName)
{
TypedVarPtr var;
ASSERT_NO_THROW(var = loadTypedVar(L"g_classChild"));
ASSERT_TRUE(var->getElement(L"__VFN_table")->getType()->deref()->isVtbl());
ASSERT_EQ(3, var->getElement(L"__VFN_table")->getType()->deref()->getElementCount());
}
TEST_F(TypedVarTest, getSecondVTBL)
{
// vtbl #2
// classChild::virtMethod3
// classChild::virtMethod4
TypedVarPtr var;
ASSERT_NO_THROW(var = loadTypedVar(L"g_classChild"));
TEST_F(TypedVarTest, DISABLED_getVTBL)
ASSERT_TRUE(var->getElement(2)->getType()->deref()->isVtbl());
TypedVarPtr vtbl = var->getElement(2)->deref();
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(0)).find(L"virtMethod3"));
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(1)).find(L"virtMethod4"));
EXPECT_THROW(vtbl->getElement(2), kdlib::IndexException);
}
TEST_F(TypedVarTest, getVirtualVTBL)
{
TypedVarPtr var;
ASSERT_NO_THROW(var = loadTypedVar(L"g_virtChild"));
auto s = var->str();
TypedVarPtr vtbl;
ASSERT_NO_THROW(vtbl = loadTypedVar(L"g_virtChild")->getElement(2)->deref());
ASSERT_NO_THROW(vtbl = loadTypedVar(L"g_virtChild")->getElement(4)->deref());
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(0)).find(L"virtChildMethod"));
EXPECT_THROW(vtbl->getElement(1), kdlib::IndexException);
ASSERT_NO_THROW(vtbl = loadTypedVar(L"g_virtChild")->getElement(4)->deref());
ASSERT_NO_THROW(vtbl = loadTypedVar(L"g_virtChild")->getElement(2)->deref());
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(0)).find(L"virtMethod1"));
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(1)).find(L"virtMethod2"));
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(1)).find(L"virtMethod1"));
EXPECT_NE(std::wstring::npos, findSymbol((MEMOFFSET_64)*vtbl->getElement(2)).find(L"virtMethod2"));
EXPECT_THROW(vtbl->getElement(3), kdlib::IndexException);
}
TEST_F(TypedVarTest, FunctionCall)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment