diff --git a/pykd/customtypes.cpp b/pykd/customtypes.cpp
new file mode 100644
index 0000000..9ae22ac
--- /dev/null
+++ b/pykd/customtypes.cpp
@@ -0,0 +1,98 @@
+
+#include "stdafx.h"
+#include "customtypes.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace pykd {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TypeInfoPtr CustomStruct::create(const std::string &name, ULONG alignReq /*= 0*/)
+{
+ return TypeInfoPtr( new CustomStruct(name, alignReq) );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ULONG CustomStruct::getSize()
+{
+ if (UdtFieldColl::empty())
+ return 0;
+
+ UdtUtils::Field &field = UdtFieldColl::last();
+ return field.m_offset + field.m_type->getSize();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void CustomStruct::appendField(const std::string &fieldName, TypeInfoPtr fieldType)
+{
+ bool fieldExist = false;
+ try
+ {
+ lookupField(fieldName);
+ fieldExist = true;
+ }
+ catch (const TypeException &except)
+ {
+ DBG_UNREFERENCED_PARAMETER(except);
+ }
+ if (fieldExist)
+ throw TypeException(getName(), "duplicate field name: " + fieldName);
+
+ ULONG offset = getSize();
+ offset += (offset % m_alignReq);
+ UdtFieldColl::push_back(
+ UdtUtils::Field(offset, fieldName, fieldType)
+ );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TypeInfoPtr CustomUnion::create(const std::string &name)
+{
+ return TypeInfoPtr( new CustomUnion(name) );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ULONG CustomUnion::getSize()
+{
+ ULONG size = 0;
+ for (ULONG i = 0; i < getFieldCount(); ++i)
+ {
+ ULONG fieldSize = lookupField(i).m_type->getSize();
+ if (fieldSize > size)
+ size = fieldSize;
+ }
+ return size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void CustomUnion::appendField(const std::string &fieldName, TypeInfoPtr fieldType)
+{
+ bool fieldExist = false;
+ try
+ {
+ lookupField(fieldName);
+ fieldExist = true;
+ }
+ catch (const TypeException &except)
+ {
+ DBG_UNREFERENCED_PARAMETER(except);
+ }
+ if (fieldExist)
+ throw TypeException(getName(), "duplicate field name: " + fieldName);
+
+ UdtFieldColl::push_back(
+ UdtUtils::Field(0, fieldName, fieldType)
+ );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace pykd
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/customtypes.h b/pykd/customtypes.h
new file mode 100644
index 0000000..199f559
--- /dev/null
+++ b/pykd/customtypes.h
@@ -0,0 +1,69 @@
+
+#pragma once
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "typeinfo.h"
+#include "win\dbgeng.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace pykd {
+
+////////////////////////////////////////////////////////////////////////////////
+
+class CustomStruct : public UdtFieldColl
+{
+public:
+ static TypeInfoPtr create(const std::string &name, ULONG alignReq = 0);
+
+protected:
+ CustomStruct(const std::string &name, ULONG alignReq)
+ : UdtFieldColl(name), m_name(name), m_alignReq(alignReq ? alignReq : ptrSize())
+ {
+ }
+
+ virtual std::string getName() override {
+ return m_name;
+ }
+
+ virtual ULONG getSize() override;
+
+ virtual void appendField(const std::string &fieldName, TypeInfoPtr fieldType) override;
+
+ virtual std::string getTypeString() const override {
+ return "custom struct";
+ }
+
+private:
+ std::string m_name;
+ ULONG m_alignReq;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class CustomUnion : public UdtFieldColl
+{
+public:
+ static TypeInfoPtr create(const std::string &name);
+
+protected:
+ CustomUnion(const std::string &name) : UdtFieldColl(name) {}
+
+ virtual ULONG getSize() override;
+
+ virtual void appendField(const std::string &fieldName, TypeInfoPtr fieldType) override;
+
+ virtual std::string getTypeString() const override {
+ return "custom union";
+ }
+
+private:
+ std::string m_name;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace pykd
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj
index 24fdecb..b9f14b2 100644
--- a/pykd/pykd_2008.vcproj
+++ b/pykd/pykd_2008.vcproj
@@ -361,6 +361,10 @@
RelativePath=".\cpureg.cpp"
>
+
+
@@ -467,6 +471,10 @@
RelativePath=".\cpureg.h"
>
+
+
diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp
index b2e8fad..d43e39b 100644
--- a/pykd/pymod.cpp
+++ b/pykd/pymod.cpp
@@ -14,6 +14,7 @@
#include "dbgexcept.h"
#include "dbgmem.h"
#include "typeinfo.h"
+#include "customtypes.h"
#include "typedvar.h"
#include "cpureg.h"
#include "disasm.h"
@@ -59,6 +60,8 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( getSourceFile_, getSourceFile, 0, 1 );
BOOST_PYTHON_FUNCTION_OVERLOADS( setSoftwareBp_, setSoftwareBp, 1, 2 );
BOOST_PYTHON_FUNCTION_OVERLOADS( setHardwareBp_, setHardwareBp, 3, 4 );
+BOOST_PYTHON_FUNCTION_OVERLOADS( CustomStruct_create, CustomStruct::create, 1, 2 );
+
BOOST_PYTHON_MODULE( pykd )
{
python::scope().attr("version") = pykdVersion;
@@ -231,6 +234,12 @@ BOOST_PYTHON_MODULE( pykd )
python::def( "removeAllBp", &breakPointRemoveAll,
"Remove all breapoints" );
+ // custom types
+ python::def( "createStruct", &CustomStruct::create, CustomStruct_create( python::args( "name", "alignReq" ),
+ "Create empty structure. Use append() method for building" ) );
+ python::def( "createUnion", &CustomUnion::create,
+ "Create empty union. Use append() method for building" );
+
python::class_( "intBase", "intBase", python::no_init )
.def( python::init() )
.def( "__eq__", &intBase::eq )
@@ -334,6 +343,7 @@ BOOST_PYTHON_MODULE( pykd )
.def( "field", &TypeInfo::getField )
.def( "asMap", &TypeInfo::asMap )
.def( "deref", &TypeInfo::deref )
+ .def( "append", &TypeInfo::appendField )
.def( "__str__", &TypeInfo::print )
.def( "__getattr__", &TypeInfo::getField )
.def("__len__", &TypeInfo::getElementCount )
diff --git a/pykd/typeinfo.cpp b/pykd/typeinfo.cpp
index 965e583..95b3544 100644
--- a/pykd/typeinfo.cpp
+++ b/pykd/typeinfo.cpp
@@ -557,10 +557,45 @@ ULONG64 TypeInfo::getStaticOffset()
/////////////////////////////////////////////////////////////////////////////////////
-ULONG UdtTypeInfo::getFieldCount()
+std::string UdtFieldColl::print()
{
- refreshFields();
- return (ULONG)m_fields.size();
+ std::stringstream sstr;
+
+ sstr << getTypeString() << ": " << getName() << " Size: 0x" << std::hex << getSize() << " (" << std::dec << getSize() << ")" << std::endl;
+
+ ULONG fieldCount = getFieldCount();
+
+ for ( ULONG i = 0; i < fieldCount; ++i )
+ {
+ const UdtUtils::Field &udtField = lookupField(i);
+ TypeInfoPtr fieldType = udtField.m_type;
+
+ if ( fieldType->isStaticMember() )
+ {
+ sstr << " =" << std::right << std::setw(10) << std::setfill('0') << std::hex << fieldType->getStaticOffset();
+ sstr << " " << std::left << std::setw(18) << std::setfill(' ') << udtField.m_name << ':';
+ }
+ 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 << udtField.m_offset;
+ sstr << " " << udtField.m_name << ':';
+ }
+ else
+ {
+ sstr << " +" << std::right << std::setw(4) << std::setfill('0') << std::hex << udtField.m_offset;
+ sstr << " " << std::left << std::setw(24) << std::setfill(' ') << udtField.m_name << ':';
+ }
+
+ sstr << " " << std::left << fieldType->getName();
+ sstr << std::endl;
+ }
+
+ return sstr.str();
}
/////////////////////////////////////////////////////////////////////////////////////
@@ -615,7 +650,9 @@ void UdtTypeInfo::getFields(
break;
}
- m_fields.push_back( UdtUtils::Field( fieldOffset, childSym->getName(), ti ) );
+ UdtFieldColl::push_back(
+ UdtUtils::Field( fieldOffset, childSym->getName(), ti )
+ );
}
else
if ( symTag == SymTagVTable )
@@ -632,7 +669,7 @@ void UdtTypeInfo::getFields(
}
- m_fields.push_back(
+ UdtFieldColl::push_back(
UdtUtils::Field( startOffset + childSym->getOffset(), "__VFN_table", ti )
);
}
@@ -666,7 +703,7 @@ void UdtTypeInfo::getVirtualFields()
void UdtTypeInfo::refreshFields()
{
- if ( m_fields.empty() )
+ if ( UdtFieldColl::empty() )
{
getFields( m_dia, SymbolPtr() );
getVirtualFields();
@@ -675,49 +712,6 @@ void UdtTypeInfo::refreshFields()
/////////////////////////////////////////////////////////////////////////////////////
-std::string UdtTypeInfo::print()
-{
- std::stringstream sstr;
-
- sstr << "struct/class: " << getName() << " Size: 0x" << std::hex << getSize() << " (" << std::dec << getSize() << ")" << std::endl;
-
- ULONG fieldCount = getFieldCount();
-
- for ( ULONG i = 0; i < fieldCount; ++i )
- {
- const UdtUtils::Field &udtField = lookupField(i);
- TypeInfoPtr fieldType = udtField.m_type;
-
- if ( fieldType->isStaticMember() )
- {
- sstr << " =" << std::right << std::setw(10) << std::setfill('0') << std::hex << fieldType->getStaticOffset();
- sstr << " " << std::left << std::setw(18) << std::setfill(' ') << udtField.m_name << ':';
- }
- 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 << udtField.m_offset;
- sstr << " " << udtField.m_name << ':';
- }
- else
- {
- sstr << " +" << std::right << std::setw(4) << std::setfill('0') << std::hex << udtField.m_offset;
- sstr << " " << std::left << std::setw(24) << std::setfill(' ') << udtField.m_name << ':';
- }
-
- sstr << " " << std::left << fieldType->getName();
- sstr << std::endl;
- }
-
- return sstr.str();
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-
TypeInfoPtr EnumTypeInfo::getField( const std::string &fieldName )
{
return TypeInfo::getTypeInfo( m_dia, fieldName );
diff --git a/pykd/typeinfo.h b/pykd/typeinfo.h
index 9a627eb..d3fe052 100644
--- a/pykd/typeinfo.h
+++ b/pykd/typeinfo.h
@@ -157,6 +157,10 @@ public:
throw PyException( PyExc_TypeError, "object is unsubscriptable");
}
+ virtual void appendField(const std::string &fieldName, TypeInfoPtr fieldType) {
+ throw TypeException( getName(), "type is not is not extensible" );
+ }
+
void setConstant( const BaseTypeVariant& var )
{
m_constant = true;
@@ -298,24 +302,11 @@ private:
///////////////////////////////////////////////////////////////////////////////////
-class UdtTypeInfo : public TypeInfo
+class UdtFieldColl : public TypeInfo
{
-public:
-
- UdtTypeInfo (SymbolPtr &symbol ) :
- m_dia( symbol ),
- m_fields( symbol->getName() )
- {
- }
-
protected:
-
virtual std::string getName() {
- return m_dia->getName();
- }
-
- virtual ULONG getSize() {
- return (ULONG)m_dia->getSize();
+ return m_fields.getName();
}
virtual TypeInfoPtr getField( const std::string &fieldName ) {
@@ -331,7 +322,7 @@ protected:
}
virtual ULONG getFieldOffsetByNameRecirsive( const std::string &fieldName ) {
- return UdtUtils::getFiledOffsetRecirsive( shared_from_this(), fieldName );
+ return UdtUtils::getFieldOffsetRecirsive( shared_from_this(), fieldName );
}
virtual ULONG getFieldOffsetByNameNotRecursively( const std::string &fieldName ) {
@@ -342,10 +333,9 @@ protected:
return lookupField(index).m_offset;
}
- virtual ULONG getFieldCount();
-
- virtual bool isUserDefined() {
- return true;
+ virtual ULONG getFieldCount() {
+ refreshFields();
+ return (ULONG)m_fields.size();
}
virtual ULONG getElementCount() {
@@ -358,9 +348,61 @@ protected:
virtual std::string print();
- SymbolPtr m_dia;
+ virtual bool isUserDefined() {
+ return true;
+ }
- UdtUtils::FieldCollection m_fields;
+protected:
+ UdtFieldColl(const std::string &typeName) : m_fields(typeName) {}
+
+ virtual void refreshFields() {}
+ virtual std::string getTypeString() const = 0;
+
+ bool empty() const {
+ return m_fields.empty();
+ }
+
+ void push_back(const UdtUtils::Field &field) {
+ m_fields.push_back(field);
+ }
+
+ template
+ const UdtUtils::Field &lookupField( T index) {
+ refreshFields();
+ return m_fields.lookup(index);
+ }
+
+ UdtUtils::Field &last(){
+ return *m_fields.rbegin();
+ }
+
+private:
+ UdtUtils::FieldCollection m_fields;
+};
+
+///////////////////////////////////////////////////////////////////////////////////
+
+class UdtTypeInfo : public UdtFieldColl
+{
+public:
+
+ UdtTypeInfo (SymbolPtr &symbol ) :
+ UdtFieldColl( symbol->getName() ),
+ m_dia( symbol )
+ {
+ }
+
+protected:
+ virtual ULONG getSize() {
+ return (ULONG)m_dia->getSize();
+ }
+ void getVirtualFields();
+
+ virtual void refreshFields() override;
+
+ virtual std::string getTypeString() const override {
+ return "struct/class";
+ }
void getFields(
SymbolPtr &rootSym,
@@ -371,16 +413,8 @@ protected:
ULONG m_virtualDispSize = 0 );
- void getVirtualFields();
-
private:
- void refreshFields();
-
- template
- const UdtUtils::Field &lookupField( T index) {
- refreshFields();
- return m_fields.lookup(index);
- }
+ SymbolPtr m_dia;
};
///////////////////////////////////////////////////////////////////////////////////
diff --git a/pykd/udtutils.cpp b/pykd/udtutils.cpp
index 7ff0efe..5b8fc01 100644
--- a/pykd/udtutils.cpp
+++ b/pykd/udtutils.cpp
@@ -36,7 +36,7 @@ const Field &FieldCollection::lookup(const std::string &name) const
///////////////////////////////////////////////////////////////////////////////////
-ULONG getFiledOffsetRecirsive(TypeInfoPtr typeInfo, const std::string &fieldName)
+ULONG getFieldOffsetRecirsive(TypeInfoPtr typeInfo, const std::string &fieldName)
{
// "m_field1.m_field2" -> ["m_field1", "m_field2"]
typedef boost::char_separator CharSep;
diff --git a/pykd/udtutils.h b/pykd/udtutils.h
index b32a818..29aec43 100644
--- a/pykd/udtutils.h
+++ b/pykd/udtutils.h
@@ -46,13 +46,17 @@ public:
const Field &lookup(ULONG index) const;
const Field &lookup(const std::string &name) const;
+ const std::string &getName() const {
+ return m_baseTypeName;
+ }
+
private:
std::string m_baseTypeName;
};
///////////////////////////////////////////////////////////////////////////////////
-ULONG getFiledOffsetRecirsive(TypeInfoPtr typeInfo, const std::string &fieldName);
+ULONG getFieldOffsetRecirsive(TypeInfoPtr typeInfo, const std::string &fieldName);
///////////////////////////////////////////////////////////////////////////////////
diff --git a/test/scripts/customtypestest.py b/test/scripts/customtypestest.py
new file mode 100644
index 0000000..750d824
--- /dev/null
+++ b/test/scripts/customtypestest.py
@@ -0,0 +1,72 @@
+"""Custom types tests"""
+
+import unittest
+import target
+import pykd
+
+class CustomTypesTest(unittest.TestCase):
+ def testCommonStruct(self):
+ mySubStruct = pykd.createStruct("MySubCustomStruct")
+ mySubStruct.append( "m_uint1", pykd.typeInfo("UInt1B") )
+ mySubStruct.append( "m_uint2", pykd.typeInfo("UInt2B") )
+
+ mySubUnion = pykd.createUnion("MySubCustomUnion")
+ mySubUnion.append( "m_uint1", pykd.typeInfo("UInt1B") )
+ mySubUnion.append( "m_uint2", pykd.typeInfo("UInt2B") )
+
+ myType = pykd.createStruct("MyCustomStruct")
+ myType.append( "m_uint1", pykd.typeInfo("UInt1B") )
+ myType.append( "m_uint4", pykd.typeInfo("UInt4B") )
+ myType.append( "m_uint2", pykd.typeInfo("UInt2B") )
+ myType.append( "m_struct", mySubStruct )
+ myType.append( "m_union", mySubUnion )
+ myType.append( "m_uint8", pykd.typeInfo("UInt8B") )
+
+ self.assertTrue( myType.size() != 0 )
+ self.assertTrue( myType.size() >= myType.fieldOffset("m_uint8") + myType.m_uint8.size() )
+
+ self.assertTrue( myType.fieldOffset("m_uint1") == 0 )
+
+ self.assertTrue( myType.fieldOffset("m_uint1") < myType.fieldOffset("m_uint4") )
+ self.assertTrue( myType.fieldOffset("m_uint1") + myType.m_uint1.size() <= myType.fieldOffset("m_uint4") )
+
+ self.assertTrue( myType.fieldOffset("m_uint4") < myType.fieldOffset("m_uint2") )
+ self.assertTrue( myType.fieldOffset("m_uint4") + myType.m_uint4.size() <= myType.fieldOffset("m_uint2") )
+
+ self.assertTrue( myType.fieldOffset("m_uint2") < myType.fieldOffset("m_struct") )
+ self.assertTrue( myType.fieldOffset("m_uint2") + myType.m_uint2.size() <= myType.fieldOffset("m_struct") )
+
+ self.assertTrue( myType.fieldOffset("m_struct") < myType.fieldOffset("m_union") )
+ self.assertTrue( myType.fieldOffset("m_struct") + myType.m_struct.size() <= myType.fieldOffset("m_union") )
+
+ # print myType
+
+ def testCommonUnion(self):
+ myType = pykd.createUnion("MyCustomStruct")
+ myType.append( "m_uint1", pykd.typeInfo("UInt1B") )
+ myType.append( "m_uint4", pykd.typeInfo("UInt4B") )
+ myType.append( "m_uint2", pykd.typeInfo("UInt2B") )
+
+ self.assertFalse( myType.size() == 0 )
+ self.assertTrue( myType.fieldOffset("m_uint1") == 0 )
+ self.assertTrue( myType.fieldOffset("m_uint4") == 0 )
+ self.assertTrue( myType.fieldOffset("m_uint2") == 0 )
+
+ def testDupFieldName(self):
+ myType = pykd.createStruct("MyCustomStruct")
+ exceptionRised = False
+ myType.append( "m_uint1", pykd.typeInfo("UInt1B") )
+ try:
+ myType.append( "m_uint1", pykd.typeInfo("UInt1B") )
+ except pykd.TypeException:
+ exceptionRised = True
+ self.assertTrue(exceptionRised)
+
+ myType = pykd.createUnion("MyCustomStruct")
+ exceptionRised = False
+ myType.append( "m_uint1", pykd.typeInfo("UInt1B") )
+ try:
+ myType.append( "m_uint1", pykd.typeInfo("UInt1B") )
+ except pykd.TypeException:
+ exceptionRised = True
+ self.assertTrue(exceptionRised)
diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py
index f32efe2..d2cd68c 100644
--- a/test/scripts/pykdtest.py
+++ b/test/scripts/pykdtest.py
@@ -20,6 +20,7 @@ import typeinfo
import typedvar
import regtest
import localstest
+import customtypestest
class StartProcessWithoutParamsTest(unittest.TestCase):
def testStart(self):
@@ -45,6 +46,7 @@ def getTestSuite( singleName = "" ):
unittest.TestLoader().loadTestsFromTestCase( typeinfo.TypeInfoTest ),
unittest.TestLoader().loadTestsFromTestCase( typedvar.TypedVarTest ),
unittest.TestLoader().loadTestsFromTestCase( regtest.CpuRegTest ),
+ unittest.TestLoader().loadTestsFromTestCase( customtypestest.CustomTypesTest ),
# ^^^
unittest.TestLoader().loadTestsFromTestCase( TerminateProcessTest ),
diff --git a/test/targetapp/targetapp.vcproj b/test/targetapp/targetapp.vcproj
index ec9f910..226ad86 100644
--- a/test/targetapp/targetapp.vcproj
+++ b/test/targetapp/targetapp.vcproj
@@ -408,6 +408,10 @@
RelativePath="..\scripts\clienttest.py"
>
+
+