[0.2.x] + custom types

git-svn-id: https://pykd.svn.codeplex.com/svn@79382 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2012-09-05 14:55:29 +00:00 committed by Mikhail I. Izmestev
parent 77b1eee2f4
commit 70747aac37
11 changed files with 377 additions and 82 deletions

98
pykd/customtypes.cpp Normal file
View File

@ -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
////////////////////////////////////////////////////////////////////////////////

69
pykd/customtypes.h Normal file
View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -361,6 +361,10 @@
RelativePath=".\cpureg.cpp"
>
</File>
<File
RelativePath=".\customtypes.cpp"
>
</File>
<File
RelativePath=".\dbgexcept.cpp"
>
@ -467,6 +471,10 @@
RelativePath=".\cpureg.h"
>
</File>
<File
RelativePath=".\customtypes.h"
>
</File>
<File
RelativePath=".\dbgengine.h"
>

View File

@ -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", "intBase", python::no_init )
.def( python::init<python::object&>() )
.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 )

View File

@ -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 );

View File

@ -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 <typename T>
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 <typename T>
const UdtUtils::Field &lookupField( T index) {
refreshFields();
return m_fields.lookup(index);
}
SymbolPtr m_dia;
};
///////////////////////////////////////////////////////////////////////////////////

View File

@ -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<char> CharSep;

View File

@ -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);
///////////////////////////////////////////////////////////////////////////////////

View File

@ -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)

View File

@ -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 ),

View File

@ -408,6 +408,10 @@
RelativePath="..\scripts\clienttest.py"
>
</File>
<File
RelativePath="..\scripts\customtypestest.py"
>
</File>
<File
RelativePath="..\scripts\dbgcmd.py"
>