[0.2.x] updated : working with local vars

git-svn-id: https://pykd.svn.codeplex.com/svn@81665 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\kernelnet_cp 2012-12-06 06:28:59 +00:00 committed by Mikhail I. Izmestev
parent 6dc5ac2f20
commit a1a69b9826
10 changed files with 458 additions and 259 deletions

View File

@ -1,209 +0,0 @@
#include <stdafx.h>
#include "localvar.h"
#include "module.h"
#include "symengine.h"
#include "dbgengine.h"
#include "typedvar.h"
namespace pykd {
///////////////////////////////////////////////////////////////////////////////
python::dict getLocals()
{
return getLocalsByFrame( getCurrentStackFrame() );
}
///////////////////////////////////////////////////////////////////////////////
class BuildLocals
{
public:
BuildLocals( ModulePtr mod, const StackFrame &frame )
: m_mod(mod), m_frame(frame), m_formalGen(0)
{
m_ipRva = static_cast<ULONG>(m_frame.m_instructionOffset - m_mod->getBase());
}
void process( SymbolPtr symParent );
python::dict &getResult() {
return m_dct;
}
protected:
void addVar(SymbolPtr symVar);
private:
ModulePtr m_mod;
const StackFrame &m_frame;
python::dict m_dct;
size_t m_formalGen;
ULONG m_ipRva;
};
///////////////////////////////////////////////////////////////////////////////
void BuildLocals::process(
SymbolPtr symParent
)
{
// add vars from current scope
SymbolPtrList symList = symParent->findChildren(SymTagData);
SymbolPtrList::iterator itVar = symList.begin();
for (; itVar != symList.end(); ++itVar)
addVar(*itVar);
// find inners scopes
symList = symParent->findChildren(SymTagBlock);
SymbolPtrList::iterator itScope = symList.begin();
for (; itScope != symList.end(); ++itScope)
{
SymbolPtr scope = *itScope;
ULONG scopeRva = scope->getRva();
if (scopeRva <= m_ipRva && (scopeRva + scope->getSize()) > m_ipRva)
process(scope);
}
}
///////////////////////////////////////////////////////////////////////////////
void BuildLocals::addVar(SymbolPtr symVar)
{
std::string name;
try
{
name = symVar->getName();
if (name.empty())
return;
}
catch (const SymbolException &except)
{
DBG_UNREFERENCED_PARAMETER(except);
return;
}
if (m_dct.has_key(name))
{
std::stringstream sstream;
sstream << name << "#" << std::dec << ++m_formalGen;
name = sstream.str();
}
BOOST_ASSERT(!m_dct.has_key(name));
if (m_dct.has_key(name))
return;
ULONG64 varAddr;
const LocationType locType = static_cast<LocationType>(symVar->getLocType());
switch (locType)
{
case LocIsStatic:
varAddr = m_mod->getBase() + symVar->getRva();
break;
case LocIsRegRel:
{
RegRealativeId rri;
try
{
rri = static_cast<RegRealativeId>(symVar->getRegRealativeId());
}
catch (const DbgException &except)
{
DBG_UNREFERENCED_PARAMETER(except);
return;
}
varAddr = m_frame.getValue(rri, symVar->getOffset());
}
break;
default:
BOOST_ASSERT(LocIsEnregistered == locType);
return;
}
TypeInfoPtr typeInfo = TypeInfo::getTypeInfo(symVar);
TypedVarPtr typedVar = TypedVar::getTypedVarByTypeInfo(typeInfo, varAddr);
typedVar->setDataKind( symVar->getDataKind() );
m_dct[name] = typedVar;
}
///////////////////////////////////////////////////////////////////////////////
static bool IsInDebugRange(
SymbolPtr func,
ULONG ipRva
)
{
SymbolPtrList lstFuncDebugStart;
SymbolPtrList lstFuncDebugEnd;
try
{
lstFuncDebugStart = func->findChildren(SymTagFuncDebugStart);
if (1 != lstFuncDebugStart.size())
{
BOOST_ASSERT(lstFuncDebugStart.empty());
return true;
}
lstFuncDebugEnd = func->findChildren(SymTagFuncDebugEnd);
if (1 != lstFuncDebugEnd.size())
{
BOOST_ASSERT(lstFuncDebugEnd.empty());
return true;
}
}
catch (const SymbolException &except)
{
DBG_UNREFERENCED_PARAMETER(except);
return true;
}
return
((*lstFuncDebugStart.begin())->getRva() <= ipRva) &&
((*lstFuncDebugEnd.begin())->getRva() >= ipRva);
}
///////////////////////////////////////////////////////////////////////////////
python::dict getLocalsByFrame( const StackFrame &frame )
{
// query target fuction by $ip register
ModulePtr mod;
SymbolPtr func;
try
{
mod = Module::loadModuleByOffset(frame.m_instructionOffset);
LONG displacemnt;
func = mod->getSymbolByVa(frame.m_instructionOffset, SymTagFunction, &displacemnt );
}
catch (const DbgException &except)
{
DBG_UNREFERENCED_PARAMETER(except);
return python::dict();
}
#ifdef _DEBUG
std::string funcName;
funcName = func->getName();
#endif // _DEBUG
if (!IsInDebugRange(func, static_cast<ULONG>(frame.m_instructionOffset - mod->getBase())))
{
// not in debug range
return python::dict();
}
BuildLocals buildLocals(mod, frame);
buildLocals.process(func);
return buildLocals.getResult();
}
///////////////////////////////////////////////////////////////////////////////
} //end pykd namespace

View File

@ -1,17 +0,0 @@
#pragma once
#include "stkframe.h"
namespace pykd {
///////////////////////////////////////////////////////////////////////////////
python::dict getLocals();
python::dict getLocalsByFrame( const StackFrame &frame );
///////////////////////////////////////////////////////////////////////////////
} // end pykd namespace

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Version="9,00"
Name="pykd"
ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}"
RootNamespace="pykd"
@ -389,10 +389,6 @@
RelativePath=".\eventhandler.cpp"
>
</File>
<File
RelativePath=".\localvar.cpp"
>
</File>
<File
RelativePath=".\module.cpp"
>
@ -507,10 +503,6 @@
RelativePath=".\eventhandler.h"
>
</File>
<File
RelativePath=".\localvar.h"
>
</File>
<File
RelativePath=".\module.h"
>

View File

@ -19,7 +19,6 @@
#include "cpureg.h"
#include "disasm.h"
#include "stkframe.h"
#include "localvar.h"
#include "bpoint.h"
#include "win/dbgio.h"
@ -245,9 +244,14 @@ BOOST_PYTHON_MODULE( pykd )
"Set current processor mode by string (X86, ARM, IA64 or X64)" );
// stack and local variables
python::def( "getCurrentStack", &getCurrentStack,
python::def( "getStack", &getCurrentStack,
"Return a current stack as a list of stackFrame objects" );
python::def( "getLocals", &getLocals, "Get list of local variables" );
python::def( "getFrame", &getCurrentStackFrame,
"Return a current stack frame" );
python::def( "getLocals", &getLocals,
"Get list of local variables" );
python::def( "getParams", &getParams,
"Get list of function arguments" );
// breakpoints
python::def( "setBp", &setSoftwareBp, setSoftwareBp_( python::args( "offset", "callback" ),
@ -426,7 +430,13 @@ BOOST_PYTHON_MODULE( pykd )
.def( "name", &CpuReg::name, "The name of the regsiter" )
.def( "index", &CpuReg::index, "The index of thr register" );
python::class_<StackFrame>( "stackFrame",
python::class_<ScopeVars,ScopeVarsPtr,boost::noncopyable>( "locals",
"Class for access to local vars", python::no_init )
.def("__len__", &ScopeVars::getVarCount )
.def("__getitem__", &ScopeVars::getVarByIndex )
.def("__getitem__", &ScopeVars::getVarByName );
python::class_<StackFrame, StackFramePtr,boost::noncopyable>( "stackFrame",
"Class representing a frame of the call stack", python::no_init )
.def_readonly( "instructionOffset", &StackFrame::m_instructionOffset,
"Return a frame's instruction offset" )
@ -438,8 +448,10 @@ BOOST_PYTHON_MODULE( pykd )
"Return a frame's stack offset" )
.def_readonly( "frameNumber", &StackFrame::m_frameNumber,
"Return a frame's number" )
.def( "getLocals", &StackFrame::getLocals,
.add_property( "locals", &StackFrame::getLocals,
"Get list of local variables for this stack frame" )
.add_property( "params", &StackFrame::getParams,
"Get list of function params" )
.def( "__str__", &StackFrame::print,
"Return stacks frame as a string");

View File

@ -5,7 +5,7 @@
#include "stdafx.h"
#include "stkframe.h"
#include "dbgengine.h"
#include "localvar.h"
#include "module.h"
////////////////////////////////////////////////////////////////////////////////
@ -36,14 +36,21 @@ std::string StackFrame::print() const
sstream << ", stack= 0x" << std::hex << m_stackOffset;
return sstream.str();
}
////////////////////////////////////////////////////////////////////////////////
python::dict StackFrame::getLocals() const
ScopeVarsPtr StackFrame::getLocals()
{
return getLocalsByFrame( *this );
return ScopeVarsPtr( new LocalVars( shared_from_this() ) );
}
///////////////////////////////////////////////////////////////////////////////
ScopeVarsPtr StackFrame::getParams()
{
return ScopeVarsPtr( new FunctionParams( shared_from_this() ) );
}
///////////////////////////////////////////////////////////////////////////////
@ -63,6 +70,283 @@ ULONG64 StackFrame::getValue(RegRealativeId rri, LONG64 offset /*= 0*/) const
////////////////////////////////////////////////////////////////////////////////
static bool IsInDebugRange(
SymbolPtr func,
ULONG ipRva
)
{
SymbolPtrList lstFuncDebugStart;
SymbolPtrList lstFuncDebugEnd;
try
{
lstFuncDebugStart = func->findChildren(SymTagFuncDebugStart);
if (1 != lstFuncDebugStart.size())
{
BOOST_ASSERT(lstFuncDebugStart.empty());
return true;
}
lstFuncDebugEnd = func->findChildren(SymTagFuncDebugEnd);
if (1 != lstFuncDebugEnd.size())
{
BOOST_ASSERT(lstFuncDebugEnd.empty());
return true;
}
}
catch (const SymbolException &except)
{
DBG_UNREFERENCED_PARAMETER(except);
return true;
}
return
((*lstFuncDebugStart.begin())->getRva() <= ipRva) &&
((*lstFuncDebugEnd.begin())->getRva() >= ipRva);
}
python::object StackFrame::getLocalByName( const std::string& name )
{
ModulePtr mod = Module::loadModuleByOffset( m_instructionOffset);
LONG displacemnt;
SymbolPtr func = mod->getSymbolByVa( m_instructionOffset, SymTagFunction, &displacemnt );
#ifdef _DEBUG
std::string funcName;
funcName = func->getName();
#endif // _DEBUG
if (!IsInDebugRange(func, static_cast<ULONG>( m_instructionOffset - mod->getBase())))
{
throw DbgException("is not debug range");
}
// find var in current scope
SymbolPtrList symList = func->findChildren(SymTagData);
SymbolPtrList::iterator itVar = symList.begin();
SymbolPtr symVar;
for (; itVar != symList.end(); ++itVar)
{
if ( (*itVar)->getName() == name )
{
symVar = *itVar;
break;
}
}
if ( itVar == symList.end() )
{
// find inners scopes
SymbolPtrList scopeList = func->findChildren(SymTagBlock);
SymbolPtrList::iterator itScope = scopeList.begin();
ULONG ipRva = static_cast<ULONG>( m_instructionOffset - mod->getBase());
for (; itScope != scopeList.end() && !symVar; ++itScope)
{
SymbolPtr scope = *itScope;
ULONG scopeRva = scope->getRva();
if (scopeRva <= ipRva && (scopeRva + scope->getSize()) > ipRva)
{
SymbolPtrList symList = scope->findChildren(SymTagData);
SymbolPtrList::iterator itVar = symList.begin();
for (; itVar != symList.end(); ++itVar)
{
if ( (*itVar)->getName() == name )
{
symVar = *itVar;
break;
}
}
}
}
}
if ( !symVar )
throw DbgException("local var not found");
ULONG64 varAddr;
const LocationType locType = static_cast<LocationType>(symVar->getLocType());
switch (locType)
{
case LocIsStatic:
varAddr = mod->getBase() + symVar->getRva();
break;
case LocIsRegRel:
{
RegRealativeId rri;
rri = static_cast<RegRealativeId>(symVar->getRegRealativeId());
varAddr = getValue(rri, symVar->getOffset());
}
break;
default:
BOOST_ASSERT(LocIsEnregistered == locType);
throw DbgException("");
}
TypeInfoPtr typeInfo = TypeInfo::getTypeInfo(symVar);
TypedVarPtr typedVar = TypedVar::getTypedVarByTypeInfo(typeInfo, varAddr);
typedVar->setDataKind( symVar->getDataKind() );
return python::object( typedVar );
}
////////////////////////////////////////////////////////////////////////////////
python::object StackFrame::getParamByName( const std::string& name )
{
ModulePtr mod = Module::loadModuleByOffset( m_instructionOffset);
LONG displacemnt;
SymbolPtr func = mod->getSymbolByVa( m_instructionOffset, SymTagFunction, &displacemnt );
#ifdef _DEBUG
std::string funcName;
funcName = func->getName();
#endif // _DEBUG
if (!IsInDebugRange(func, static_cast<ULONG>( m_instructionOffset - mod->getBase())))
{
throw DbgException("is not debug range");
}
// find var in current scope
SymbolPtrList symList = func->findChildren(SymTagData);
SymbolPtrList::iterator itVar = symList.begin();
SymbolPtr symVar;
for (; itVar != symList.end(); ++itVar)
{
if ( (*itVar)->getDataKind() == DataIsParam && (*itVar)->getName() == name )
{
symVar = *itVar;
break;
}
}
if ( !symVar )
throw DbgException("local var not found");
ULONG64 varAddr;
const LocationType locType = static_cast<LocationType>(symVar->getLocType());
switch (locType)
{
case LocIsStatic:
varAddr = mod->getBase() + symVar->getRva();
break;
case LocIsRegRel:
{
RegRealativeId rri;
rri = static_cast<RegRealativeId>(symVar->getRegRealativeId());
varAddr = getValue(rri, symVar->getOffset());
}
break;
default:
BOOST_ASSERT(LocIsEnregistered == locType);
throw DbgException("");
}
TypeInfoPtr typeInfo = TypeInfo::getTypeInfo(symVar);
TypedVarPtr typedVar = TypedVar::getTypedVarByTypeInfo(typeInfo, varAddr);
typedVar->setDataKind( symVar->getDataKind() );
return python::object( typedVar );
}
////////////////////////////////////////////////////////////////////////////////
ULONG StackFrame::getLocalCount()
{
ULONG count = 0;
ModulePtr mod;
mod = Module::loadModuleByOffset( m_instructionOffset);
LONG displacemnt;
SymbolPtr func = mod->getSymbolByVa( m_instructionOffset, SymTagFunction, &displacemnt );
#ifdef _DEBUG
std::string funcName;
funcName = func->getName();
#endif // _DEBUG
if (!IsInDebugRange(func, static_cast<ULONG>( m_instructionOffset - mod->getBase())))
{
throw DbgException("is not debug range");
}
// find var in current scope
SymbolPtrList symList = func->findChildren(SymTagData);
SymbolPtrList::iterator it;
for ( it = symList.begin(); it != symList.end(); it++ )
{
if ( (*it)->getName() != "" )
count++;
}
// find inners scopes
SymbolPtrList scopeList = func->findChildren(SymTagBlock);
SymbolPtrList::iterator itScope = scopeList.begin();
ULONG ipRva = static_cast<ULONG>( m_instructionOffset - mod->getBase());
for (; itScope != scopeList.end(); ++itScope)
{
SymbolPtr scope = *itScope;
ULONG scopeRva = scope->getRva();
if (scopeRva <= ipRva && (scopeRva + scope->getSize()) > ipRva)
{
SymbolPtrList symList = scope->findChildren(SymTagData);
count += (ULONG)symList.size();
}
}
return count;
}
////////////////////////////////////////////////////////////////////////////////
ULONG StackFrame::getParamCount()
{
ULONG count = 0;
ModulePtr mod;
mod = Module::loadModuleByOffset( m_instructionOffset);
LONG displacemnt;
SymbolPtr func = mod->getSymbolByVa( m_instructionOffset, SymTagFunction, &displacemnt );
#ifdef _DEBUG
std::string funcName;
funcName = func->getName();
#endif // _DEBUG
if (!IsInDebugRange(func, static_cast<ULONG>( m_instructionOffset - mod->getBase())))
{
throw DbgException("is not debug range");
}
// find var in current scope
SymbolPtrList symList = func->findChildren(SymTagData);
SymbolPtrList::iterator it;
for ( it = symList.begin(); it != symList.end(); it++ )
{
if ( (*it)->getDataKind() == DataIsParam )
count++;
}
return count;
}
////////////////////////////////////////////////////////////////////////////////
python::list getCurrentStack()
{
std::vector<STACK_FRAME_DESC> frames;
@ -72,7 +356,7 @@ python::list getCurrentStack()
for ( ULONG i = 0; i < frames.size(); ++i )
{
python::object frameObj( StackFrame( frames.at(i) ) );
python::object frameObj( StackFramePtr( new StackFrame( frames.at(i) ) ) );
frameList.append( frameObj );
}
@ -81,11 +365,25 @@ python::list getCurrentStack()
////////////////////////////////////////////////////////////////////////////////
StackFrame getCurrentStackFrame()
StackFramePtr getCurrentStackFrame()
{
std::vector<STACK_FRAME_DESC> frames;
getStackTrace( frames );
return frames[0];
return StackFramePtr( new StackFrame( frames[0] ) );
}
///////////////////////////////////////////////////////////////////////////////
ScopeVarsPtr getLocals()
{
return getCurrentStackFrame()->getLocals();
}
///////////////////////////////////////////////////////////////////////////////
ScopeVarsPtr getParams()
{
return getCurrentStackFrame()->getParams();
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -8,23 +8,52 @@
#include "context.h"
#include "symengine.h"
#include <boost/enable_shared_from_this.hpp>
////////////////////////////////////////////////////////////////////////////////
namespace pykd {
////////////////////////////////////////////////////////////////////////////////
class StackFrame
class StackFrame;
typedef boost::shared_ptr<StackFrame> StackFramePtr;
class ScopeVars;
typedef boost::shared_ptr<ScopeVars> ScopeVarsPtr;
////////////////////////////////////////////////////////////////////////////////
class StackFrame : public boost::enable_shared_from_this<StackFrame>
{
public:
StackFrame( const STACK_FRAME_DESC& desc );
python::dict getLocals() const;
ScopeVarsPtr getLocals();
ScopeVarsPtr getParams();
std::string print() const;
ULONG64 getValue(RegRealativeId rri, LONG64 offset = 0) const;
ULONG getLocalCount();
ULONG getParamCount();
python::object getLocalByName( const std::string& name );
python::object getParamByName( const std::string& name );
python::object getLocalByIndex( ULONG index ){
return python::long_(0);
}
python::object getParamByIndex( ULONG index ){
return python::long_(0);
}
public:
ULONG m_frameNumber;
@ -35,12 +64,82 @@ public:
};
class ScopeVars {
public:
ScopeVars( StackFramePtr &frame ) :
m_frame( frame )
{}
virtual ULONG getVarCount() const = 0;
virtual python::object getVarByName( const std::string &name ) = 0;
virtual python::object getVarByIndex(ULONG index) const = 0 ;
protected:
StackFramePtr m_frame;
};
class LocalVars : public ScopeVars {
public:
LocalVars( StackFramePtr &frame ) :
ScopeVars( frame )
{}
private:
ULONG getVarCount() const {
return m_frame->getLocalCount();
}
python::object getVarByName( const std::string &name ) {
return m_frame->getLocalByName( name );
}
python::object getVarByIndex(ULONG index) const {
return m_frame->getLocalByIndex( index );
}
};
class FunctionParams : public ScopeVars {
public:
FunctionParams( StackFramePtr &frame ) :
ScopeVars( frame )
{}
private:
ULONG getVarCount() const {
return m_frame->getParamCount();
}
python::object getVarByName( const std::string &name ) {
return m_frame->getParamByName( name );
}
python::object getVarByIndex(ULONG index) const {
return python::long_(0L);
}
};
///////////////////////////////////////////////////////////////////////////////
StackFrame getCurrentStackFrame();
StackFramePtr getCurrentStackFrame();
python::list getCurrentStack();
ScopeVarsPtr getLocals();
ScopeVarsPtr getParams();
///////////////////////////////////////////////////////////////////////////////
} // namespace pykd

View File

@ -35,10 +35,9 @@ class LocalVarsTest(unittest.TestCase):
testEnumWindowsProc1Locals(self, pykd.getLocals())
pykd.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1
testEnumWindowsProc1Locals(self, pykd.getCurrentStack()[1].getLocals())
testEnumWindowsProc1Locals(self, pykd.getStack()[1].locals )
pykd.go() # targetapp!EnumWindowsProc1 -> targetapp!EnumWindowsProc2
locals = pykd.getLocals()
self.assertEqual( len(locals), 2 )
locValues = locals.values()
self.assertTrue( locValues[0] == 7 or locValues[1] == 7 )
self.assertTrue( locals[0] == 7 or locals[1] == 7 )

View File

@ -63,11 +63,11 @@ class ModuleTest( unittest.TestCase ):
fileName = pykd.getSourceFile(target.module.FuncWithName0 )
self.assertTrue( re.search('targetapp\\.cpp', fileName ) )
fileName, lineNo, displacement = pykd.getSourceLine( target.module.FuncWithName0 + 2)
self.assertEqual( 382, lineNo )
self.assertEqual( 393, lineNo )
self.assertTrue( re.search('targetapp\\.cpp', fileName ) )
self.assertEqual( 2, displacement )
fileName, lineNo, displacement = pykd.getSourceLine()
self.assertEqual( 624, lineNo )
self.assertEqual( 639, lineNo )
def testEnumSymbols( self ):
lst = target.module.enumSymbols()

View File

@ -81,6 +81,13 @@ class TypeInfoTest( unittest.TestCase ):
except pykd.SymbolException:
pass
def testBaseTypePtr(self):
self.assertEqual("Int1B*", target.module.type( "Int1B*" ).name() )
self.assertEqual("Int1B", target.module.type( "Int1B*" ).deref().name() )
def testBaseTypeArray(self):
self.assertEqual("Int4B[20]", target.module.type( "Int4B[20]" ).name() )
def testName( self ):
ti1 = target.module.type( "classChild" )
self.assertEqual( "classChild", ti1.name() )
@ -198,7 +205,12 @@ class TypeInfoTest( unittest.TestCase ):
self.assertNotEqual( 0, ti.m_stdstr.staticOffset() )
def testUdtSubscribe(self):
tv = pykd.typeInfo( "g_virtChild" )
self.assertEqual( 5, len(tv) )
for field in tv:
ti = pykd.typeInfo( "g_virtChild" )
self.assertEqual( 5, len(ti) )
for field in ti:
str( field )
def testStructNullSize(self):
ti = target.module.type("structNullSize")
self.assertEqual( 0, len(ti) )

View File

@ -84,6 +84,16 @@ struct structTest {
structTest* m_field4;
};
struct structNullSize {
};
structNullSize* g_nullSizeArray = 0;
struct structAbstract;
typedef struct structAbstract *pstructAbstract;
pstructAbstract g_structAbstract = 0;
structWithBits g_structWithBits = { 4, 1, 3};
structTest g_structTest = { 0, 500, true, 1, NULL };
@ -435,6 +445,9 @@ void FuncWithName0()
std::cout << g_structTypeDef.m_field0;
std::cout << g_nullSizeArray;
std::cout << g_structAbstract;
//std::cout << g_virtChild.VirtualBaseClass1::m_baseField;
}