[0.2.x] + locals

git-svn-id: https://pykd.svn.codeplex.com/svn@79357 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2012-09-04 14:58:50 +00:00 committed by Mikhail I. Izmestev
parent 71b3f0df9e
commit 77b1eee2f4
18 changed files with 381 additions and 130 deletions

View File

@ -59,8 +59,7 @@ struct STACK_FRAME_DESC {
ULONG64 stackOffset; ULONG64 stackOffset;
}; };
ULONG getStackTraceFrameCount(); void getStackTrace(std::vector<STACK_FRAME_DESC> &frames);
void getStackTrace( STACK_FRAME_DESC* frames, ULONG frameCount, ULONG* frameReturned = NULL );
//breakpoints //breakpoints
ULONG breakPointSet( ULONG64 offset, bool hardware = false, ULONG size = 0, ULONG accessType = 0 ); ULONG breakPointSet( ULONG64 offset, bool hardware = false, ULONG size = 0, ULONG accessType = 0 );

View File

@ -8,6 +8,36 @@ namespace pykd {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static const struct DiaRegToRegRelativeAmd64 : DiaRegToRegRelativeBase
{
typedef std::map<ULONG, ULONG> Base;
DiaRegToRegRelativeAmd64();
} g_DiaRegToRegRelativeAmd64;
DiaRegToRegRelativeAmd64::DiaRegToRegRelativeAmd64()
{
(*this)[CV_AMD64_RIP] = rriInstructionPointer;
(*this)[CV_AMD64_RBP] = rriStackFrame;
(*this)[CV_AMD64_RSP] = rriStackPointer;
}
///////////////////////////////////////////////////////////////////////////////
static const struct DiaRegToRegRelativeI386 : DiaRegToRegRelativeBase
{
typedef std::map<ULONG, ULONG> Base;
DiaRegToRegRelativeI386();
} g_DiaRegToRegRelativeI386;
DiaRegToRegRelativeI386::DiaRegToRegRelativeI386()
{
(*this)[CV_REG_EIP] = rriInstructionPointer;
(*this)[CV_REG_EBP] = rriStackFrame;
(*this)[CV_REG_ESP] = rriStackPointer;
}
///////////////////////////////////////////////////////////////////////////////
const std::string DiaException::descPrefix("pyDia: "); const std::string DiaException::descPrefix("pyDia: ");
std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres) std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres)
@ -96,18 +126,21 @@ std::string getBasicTypeName( ULONG basicType )
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
DiaSymbol::DiaSymbol(__inout DiaSymbolPtr &_symbol ) DiaSymbol::DiaSymbol(__inout DiaSymbolPtr &_symbol, DWORD machineType )
: m_symbol(_symbol), m_machineType(machineType)
{ {
m_symbol = _symbol;
m_symbol->get_machineType(&m_machineType);
} }
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
DiaSymbol::DiaSymbol( IDiaSymbol *_symbol ) SymbolPtr DiaSymbol::fromGlobalScope( IDiaSymbol *_symbol )
{ {
m_symbol = _symbol; DWORD machineType;
m_symbol->get_machineType(&m_machineType); HRESULT hres = _symbol->get_machineType(&machineType);
if (S_OK != hres)
throw DiaException("IDiaSymbol::get_machineType", hres);
return SymbolPtr( new DiaSymbol(DiaSymbolPtr(_symbol), machineType) );
} }
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
@ -148,7 +181,7 @@ SymbolPtrList DiaSymbol::findChildren(
ULONG celt; ULONG celt;
while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) ) while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) )
{ {
childList.push_back( SymbolPtr( new DiaSymbol(child) ) ); childList.push_back( SymbolPtr( new DiaSymbol(child, m_machineType) ) );
child = NULL; child = NULL;
} }
@ -220,7 +253,7 @@ SymbolPtr DiaSymbol::getChildByIndex(ULONG symTag, ULONG _index )
if (S_OK != hres) if (S_OK != hres)
throw DiaException("Call IDiaEnumSymbols::Item", hres); throw DiaException("Call IDiaEnumSymbols::Item", hres);
return SymbolPtr( new DiaSymbol(child) ); return SymbolPtr( new DiaSymbol(child, m_machineType) );
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -247,7 +280,7 @@ SymbolPtr DiaSymbol::getChildByName(const std::string &name )
if (S_OK != hres) if (S_OK != hres)
throw DiaException("Call IDiaEnumSymbols::Item", hres); throw DiaException("Call IDiaEnumSymbols::Item", hres);
return SymbolPtr( new DiaSymbol(child) ); return SymbolPtr( new DiaSymbol(child, m_machineType) );
} }
std::string pattern = "*"; std::string pattern = "*";
@ -279,7 +312,7 @@ SymbolPtr DiaSymbol::getChildByName(const std::string &name )
if (S_OK != hres) if (S_OK != hres)
throw DiaException("Call IDiaEnumSymbols::Item", hres); throw DiaException("Call IDiaEnumSymbols::Item", hres);
SymbolPtr symPtr = SymbolPtr( new DiaSymbol(child) ); SymbolPtr symPtr = SymbolPtr( new DiaSymbol(child, m_machineType) );
if ( name == symPtr->getName() ) if ( name == symPtr->getName() )
return symPtr; return symPtr;
@ -304,6 +337,33 @@ ULONG DiaSymbol::getDataKind()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ULONG DiaSymbol::getRegRealativeId()
{
switch (m_machineType)
{
case IMAGE_FILE_MACHINE_AMD64:
return getRegRealativeIdImpl(g_DiaRegToRegRelativeAmd64);
case IMAGE_FILE_MACHINE_I386:
return getRegRealativeIdImpl(g_DiaRegToRegRelativeI386);
}
throw DiaException("Unsupported machine type");
}
////////////////////////////////////////////////////////////////////////////////
ULONG DiaSymbol::getRegRealativeIdImpl(const DiaRegToRegRelativeBase &DiaRegToRegRelative)
{
DiaRegToRegRelativeBase::const_iterator it =
DiaRegToRegRelative.find(callSymbol(get_registerId));
if (it == DiaRegToRegRelative.end())
throw DiaException("Cannot convert DAI register ID to relative register ID");
return it->second;
}
////////////////////////////////////////////////////////////////////////////////
ULONG DiaSymbol::getIndexId() ULONG DiaSymbol::getIndexId()
{ {
return callSymbol(get_symIndexId); return callSymbol(get_symIndexId);
@ -313,7 +373,8 @@ ULONG DiaSymbol::getIndexId()
SymbolPtr DiaSymbol::getIndexType() SymbolPtr DiaSymbol::getIndexType()
{ {
return SymbolPtr( new DiaSymbol(callSymbol(get_arrayIndexType) ) ); DiaSymbolPtr diaSymbol(callSymbol(get_arrayIndexType));
return SymbolPtr( new DiaSymbol(diaSymbol, m_machineType) );
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -381,7 +442,8 @@ ULONG DiaSymbol::getSymTag()
SymbolPtr DiaSymbol::getType() SymbolPtr DiaSymbol::getType()
{ {
return SymbolPtr( new DiaSymbol( callSymbol(get_type) ) ); DiaSymbolPtr diaSymbol(callSymbol(get_type));
return SymbolPtr( new DiaSymbol( diaSymbol, m_machineType ) );
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -480,9 +542,10 @@ ULONG DiaSymbol::getVirtualBaseDispIndex()
ULONG DiaSymbol::getVirtualBaseDispSize() ULONG DiaSymbol::getVirtualBaseDispSize()
{ {
SymbolPtr baseTableType = SymbolPtr( new DiaSymbol( callSymbol(get_virtualBaseTableType) ) ); DiaSymbolPtr diaSymbol(callSymbol(get_virtualBaseTableType));
SymbolPtr baseTableType = SymbolPtr( new DiaSymbol( diaSymbol, m_machineType ) );
return (ULONG)baseTableType->getType()->getSize(); return (ULONG)baseTableType->getType()->getSize();
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -534,10 +597,13 @@ SymbolPtr DiaSession::findByRva( ULONG rva, ULONG symTag, LONG* pdisplacement )
throw DiaException("Call IDiaSession::findSymbolByRVAEx", hres); throw DiaException("Call IDiaSession::findSymbolByRVAEx", hres);
if (!child) if (!child)
throw DiaException("Call IDiaSession::findSymbolByRVAEx", E_UNEXPECTED); throw DiaException("Call IDiaSession::findSymbolByRVAEx", E_UNEXPECTED);
if ( pdisplacement == NULL && displacement != 0 ) if ( !pdisplacement && displacement)
throw DiaException("Call IDiaSession::findSymbolByRVAEx failed to find suymbol" ); throw DiaException("Call IDiaSession::findSymbolByRVAEx failed to find suymbol" );
return SymbolPtr( new DiaSymbol(child) ); if (pdisplacement)
*pdisplacement = displacement;
return SymbolPtr( new DiaSymbol(child, m_globalSymbol->getMachineType() ) );
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -19,6 +19,8 @@ typedef CComPtr< IDiaEnumLineNumbers > DiaEnumLineNumbersPtr;
typedef CComPtr< IDiaLineNumber> DiaLineNumberPtr; typedef CComPtr< IDiaLineNumber> DiaLineNumberPtr;
typedef CComPtr< IDiaSourceFile > DiaSourceFilePtr; typedef CComPtr< IDiaSourceFile > DiaSourceFilePtr;
typedef std::map<ULONG, ULONG> DiaRegToRegRelativeBase;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
class DiaException : public SymbolException { class DiaException : public SymbolException {
@ -51,10 +53,9 @@ private:
class DiaSymbol : public Symbol { class DiaSymbol : public Symbol {
public: public:
DiaSymbol( DiaSymbolPtr &_symbol, DWORD machineType );
DiaSymbol( DiaSymbolPtr &_symbol ); static SymbolPtr fromGlobalScope( IDiaSymbol *_symbol );
DiaSymbol( IDiaSymbol *_symbol );
SymbolPtr getChildByName(const std::string &_name ); SymbolPtr getChildByName(const std::string &_name );
@ -105,6 +106,7 @@ public:
ULONG getDataKind(); ULONG getDataKind();
//ULONG getRegisterId(); //ULONG getRegisterId();
virtual ULONG getRegRealativeId() override;
ULONG getMachineType() { ULONG getMachineType() {
return m_machineType; return m_machineType;
@ -195,6 +197,8 @@ protected:
// const char *prefix = NULL // const char *prefix = NULL
//); //);
ULONG getRegRealativeIdImpl(const DiaRegToRegRelativeBase &DiaRegToRegRelative);
template <typename TRet> template <typename TRet>
TRet callSymbolT( TRet callSymbolT(
HRESULT(STDMETHODCALLTYPE IDiaSymbol::*method)(TRet *), HRESULT(STDMETHODCALLTYPE IDiaSymbol::*method)(TRet *),
@ -222,8 +226,8 @@ public:
DiaSession( IDiaSession* session, IDiaSymbol *globalScope ) : DiaSession( IDiaSession* session, IDiaSymbol *globalScope ) :
m_globalScope( globalScope ), m_globalScope( globalScope ),
m_session( session ), m_globalSymbol( DiaSymbol::fromGlobalScope( globalScope ) ),
m_globalSymbol( new DiaSymbol( globalScope ) ) m_session( session )
{} {}
SymbolPtr& getSymbolScope() { SymbolPtr& getSymbolScope() {

View File

@ -18,10 +18,189 @@ python::dict getLocals()
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
python::dict getLocalsByFrame( StackFrame &frame ) class BuildLocals
{ {
python::dict dct; public:
return dct; 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();
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -8,7 +8,7 @@ namespace pykd {
python::dict getLocals(); python::dict getLocals();
python::dict getLocalsByFrame( StackFrame &frame ); python::dict getLocalsByFrame( const StackFrame &frame );
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -220,10 +220,10 @@ std::string Module::getSymbolNameByVa( ULONG64 offset )
sstr << sym->getName(); sstr << sym->getName();
if ( displacement > 0 ) if ( displacement > 0 && displacement )
sstr << '+' << std::hex << displacement; sstr << '+' << std::hex << displacement;
else if ( displacement < 0 ) else if ( displacement < 0 )
sstr << '-' << std::hex << -displacement; sstr << '-' << std::hex << -displacement;
return sstr.str(); return sstr.str();
} }

View File

@ -94,7 +94,7 @@ public:
ULONG64 getSymbolSize( const std::string &symName ); ULONG64 getSymbolSize( const std::string &symName );
SymbolPtr getSymbolByVa( ULONG64 offset, ULONG symTag, LONG* displacemnt ); SymbolPtr getSymbolByVa( ULONG64 offset, ULONG symTag, LONG* displacemnt = NULL );
std::string getSymbolNameByVa( ULONG64 offset ); std::string getSymbolNameByVa( ULONG64 offset );

View File

@ -1,10 +1,14 @@
<?xml version="1.0" encoding="windows-1251"?> <?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject <VisualStudioProject
ProjectType="Visual C++" ProjectType="Visual C++"
Version="9,00" Version="9.00"
Name="pykd" Name="pykd"
ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}" ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}"
RootNamespace="pykd" RootNamespace="pykd"
SccProjectName="$/pykd/branch/0.2.x/pykd"
SccAuxPath="https://tfs.codeplex.com/tfs/TFS08"
SccLocalPath="."
SccProvider="{4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}"
Keyword="Win32Proj" Keyword="Win32Proj"
TargetFrameworkVersion="0" TargetFrameworkVersion="0"
> >

View File

@ -295,7 +295,7 @@ BOOST_PYTHON_MODULE( pykd )
.def("offset", &Module::getSymbolOffset, .def("offset", &Module::getSymbolOffset,
"Return offset of the symbol" ) "Return offset of the symbol" )
.def("findSymbol", &Module::getSymbolNameByVa, .def("findSymbol", &Module::getSymbolNameByVa,
"Return symbol name by offset" ) "Return symbol name by virtual address" )
.def("rva", &Module::getSymbolRva, .def("rva", &Module::getSymbolRva,
"Return rva of the symbol" ) "Return rva of the symbol" )
.def("sizeof", &Module::getSymbolSize, .def("sizeof", &Module::getSymbolSize,
@ -382,8 +382,8 @@ BOOST_PYTHON_MODULE( pykd )
"Return a frame's stack offset" ) "Return a frame's stack offset" )
.def_readonly( "frameNumber", &StackFrame::m_frameNumber, .def_readonly( "frameNumber", &StackFrame::m_frameNumber,
"Return a frame's number" ) "Return a frame's number" )
//.def( "getLocals", &StackFrame::getLocals, StackFrame_getLocals( python::args( "ctx" ), .def( "getLocals", &StackFrame::getLocals,
// "Get list of local variables for this stack frame" ) ) "Get list of local variables for this stack frame" )
.def( "__str__", &StackFrame::print, .def( "__str__", &StackFrame::print,
"Return stacks frame as a string"); "Return stacks frame as a string");

View File

@ -41,27 +41,38 @@ std::string StackFrame::print() const
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
python::dict StackFrame::getLocals() python::dict StackFrame::getLocals() const
{ {
return getLocalsByFrame( *this ); return getLocalsByFrame( *this );
} }
///////////////////////////////////////////////////////////////////////////////
ULONG64 StackFrame::getValue(RegRealativeId rri, LONG64 offset /*= 0*/) const
{
switch (rri)
{
case rriInstructionPointer: return m_instructionOffset + offset;
case rriStackFrame: return m_frameOffset + offset;
case rriStackPointer: return m_stackOffset + offset;
}
BOOST_ASSERT(!"Unexcepted error");
throw DbgException(__FUNCTION__ " Unexcepted error" );
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
python::list getCurrentStack() python::list getCurrentStack()
{ {
ULONG frameCount = getStackTraceFrameCount(); std::vector<STACK_FRAME_DESC> frames;
getStackTrace( frames );
std::vector<STACK_FRAME_DESC> frames(frameCount); python::list frameList;
getStackTrace( &frames[0], frameCount ); for ( ULONG i = 0; i < frames.size(); ++i )
python::list frameList;
for ( ULONG i = 0; i < frameCount; ++i )
{ {
python::object frameObj( StackFrame( frames.at(i) ) ); python::object frameObj( StackFrame( frames.at(i) ) );
frameList.append( frameObj ); frameList.append( frameObj );
} }
@ -72,12 +83,8 @@ python::list getCurrentStack()
StackFrame getCurrentStackFrame() StackFrame getCurrentStackFrame()
{ {
ULONG frameCount = getStackTraceFrameCount(); std::vector<STACK_FRAME_DESC> frames;
getStackTrace( frames );
std::vector<STACK_FRAME_DESC> frames(frameCount);
getStackTrace( &frames[0], frameCount );
return frames[0]; return frames[0];
} }

View File

@ -6,6 +6,7 @@
#include "dbgengine.h" #include "dbgengine.h"
#include "context.h" #include "context.h"
#include "symengine.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -18,10 +19,12 @@ class StackFrame
public: public:
StackFrame( const STACK_FRAME_DESC& desc ); StackFrame( const STACK_FRAME_DESC& desc );
python::dict getLocals(); python::dict getLocals() const;
std::string print() const; std::string print() const;
ULONG64 getValue(RegRealativeId rri, LONG64 offset = 0) const;
public: public:
ULONG m_frameNumber; ULONG m_frameNumber;

View File

@ -111,6 +111,15 @@ enum BasicType
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
enum RegRealativeId
{
rriInstructionPointer,
rriStackFrame,
rriStackPointer
};
////////////////////////////////////////////////////////////////////////////////
class Symbol { class Symbol {
public: public:
@ -144,7 +153,7 @@ public:
virtual bool isConstant() = 0; virtual bool isConstant() = 0;
virtual bool isIndirectVirtualBaseClass() = 0; virtual bool isIndirectVirtualBaseClass() = 0;
virtual bool isVirtualBaseClass() = 0; virtual bool isVirtualBaseClass() = 0;
virtual ULONG getRegRealativeId() = 0; // <- RegRealativeId
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -673,46 +673,26 @@ ULONG64 getRegInstructionPointer()
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
ULONG getStackTraceFrameCount() void getStackTrace(std::vector<STACK_FRAME_DESC> &frames)
{ {
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres; HRESULT hres;
ULONG filledFrames; ULONG filledFrames = 1024;
std::vector<DEBUG_STACK_FRAME> dbgFrames(filledFrames);
hres = g_dbgEng->control->GetStackTrace( 0, 0, 0, NULL, 0, &filledFrames ); hres = g_dbgEng->control->GetStackTrace( 0, 0, 0, &dbgFrames[0], filledFrames, &filledFrames);
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetStackTrace failed" );
return filledFrames;
}
///////////////////////////////////////////////////////////////////////////////
void getStackTrace( STACK_FRAME_DESC* frames, ULONG frameCount, ULONG* frameReturned )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG filledFrames;
std::vector<DEBUG_STACK_FRAME> stack(frameCount);
hres = g_dbgEng->control->GetStackTrace( 0, 0, 0, &stack[0], frameCount, &filledFrames);
if ( FAILED( hres ) ) if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetStackTrace failed" ); throw DbgException( "IDebugControl::GetStackTrace failed" );
frames.resize(filledFrames);
for ( ULONG i = 0; i < filledFrames; ++i ) for ( ULONG i = 0; i < filledFrames; ++i )
{ {
frames[i].number = stack[i].FrameNumber; frames[i].number = dbgFrames[i].FrameNumber;
frames[i].instructionOffset = stack[i].InstructionOffset; frames[i].instructionOffset = dbgFrames[i].InstructionOffset;
frames[i].returnOffset = stack[i].ReturnOffset; frames[i].returnOffset = dbgFrames[i].ReturnOffset;
frames[i].frameOffset = stack[i].FrameOffset; frames[i].frameOffset = dbgFrames[i].FrameOffset;
frames[i].stackOffset = stack[i].StackOffset; frames[i].stackOffset = dbgFrames[i].StackOffset;
} }
if ( frameReturned )
*frameReturned = filledFrames;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -3,47 +3,42 @@
import unittest import unittest
import target import target
import pykd import pykd
import testutils
def testEnumWindowsProc1Locals(testCase, locals):
testCase.assertNotEqual( 0, locals["hWindow"] )
DataIsParam = 3
testCase.assertEqual( DataIsParam, locals["hWindow"].dataKind() )
testCase.assertEqual( 6, locals["lParam"] )
testCase.assertEqual( DataIsParam, locals["lParam"].dataKind() )
DataIsLocal = 1
testCase.assertNotEqual( 0, locals["dwProccessId"] )
testCase.assertEqual( DataIsLocal, locals["dwProccessId"].dataKind() )
DataIsStaticLocal = 2
testCase.assertNotEqual( 0, locals["staticVar"] )
testCase.assertEqual( DataIsStaticLocal, locals["staticVar"].dataKind() )
testCase.assertEqual( locals["dwProccessId"] + 1, locals["staticVar"] )
class LocalVarsTest(unittest.TestCase): class LocalVarsTest(unittest.TestCase):
def testLocalVariable(self): def testLocalVariable(self):
"""Start new process and test local variables""" """Start new process and test local variables"""
_locProcessId = pykd.startProcess( target.appPath + " -testEnumWindows" )
with testutils.ContextCallIt( testutils.KillProcess(_locProcessId) ) as killStartedProcess :
pykd.go() # initial breakpoint -> wmain
pykd.go() # wmain -> targetapp!EnumWindowsProc1
newClnt = pykd.createDbgClient() testEnumWindowsProc1Locals(self, pykd.getLocals())
newClnt.startProcess( target.appPath + " -testEnumWindows" )
newClnt.go() # initial breakpoint -> wmain
newClnt.go() # wmain -> targetapp!EnumWindowsProc1
# pykd.dprint( "\n" + newClnt.dbgCommand("u") )
locals = newClnt.getLocals()
self.assertNotEqual( 0, locals["hWindow"] )
self.assertEqual( pykd.DataIsParam, locals["hWindow"].dataKind() )
self.assertEqual( 6, locals["lParam"] )
self.assertEqual( pykd.DataIsParam, locals["lParam"].dataKind() )
self.assertNotEqual( 0, locals["dwProccessId"] )
self.assertEqual( pykd.DataIsLocal, locals["dwProccessId"].dataKind() )
self.assertNotEqual( 0, locals["staticVar"] )
self.assertEqual( pykd.DataIsStaticLocal, locals["staticVar"].dataKind() )
self.assertEqual( locals["dwProccessId"] + 1, locals["staticVar"] )
newClnt.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1
# get local variables from previous stack frame
prevLocals = newClnt.getCurrentStack()[1].getLocals()
self.assertEqual( len(prevLocals), len(locals) )
for varName in locals.iterkeys():
self.assertEqual( prevLocals[varName], locals[varName] )
newClnt.go() # targetapp!EnumWindowsProc1 -> targetapp!EnumWindowsProc2
locals = newClnt.getLocals()
self.assertEqual( len(locals), 2 )
locValues = locals.values()
self.assertTrue( locValues[0] == 7 or locValues[1] == 7 )
pykd.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1
testEnumWindowsProc1Locals(self, pykd.getCurrentStack()[1].getLocals())
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 )

View File

@ -61,6 +61,6 @@ class ModuleTest( unittest.TestCase ):
self.assertTrue( re.search('targetapp\\.cpp', fileName ) ) self.assertTrue( re.search('targetapp\\.cpp', fileName ) )
self.assertEqual( 2, displacement ) self.assertEqual( 2, displacement )
fileName, lineNo, displacement = pykd.getSourceLine() fileName, lineNo, displacement = pykd.getSourceLine()
self.assertEqual( 636, lineNo ) self.assertEqual( 616, lineNo )

View File

@ -19,6 +19,7 @@ import moduletest
import typeinfo import typeinfo
import typedvar import typedvar
import regtest import regtest
import localstest
class StartProcessWithoutParamsTest(unittest.TestCase): class StartProcessWithoutParamsTest(unittest.TestCase):
def testStart(self): def testStart(self):
@ -30,13 +31,13 @@ class StartProcessWithoutParamsTest(unittest.TestCase):
class TerminateProcessTest(unittest.TestCase): class TerminateProcessTest(unittest.TestCase):
def testKill(self): def testKill(self):
pykd.killProcess( target.processId ) pykd.killProcess( target.processId )
pykd.detachProcess( target.processId )
def getTestSuite( singleName = "" ): def getTestSuite( singleName = "" ):
if singleName == "": if singleName == "":
return unittest.TestSuite( return unittest.TestSuite(
[ [
unittest.TestLoader().loadTestsFromTestCase( StartProcessWithoutParamsTest ), unittest.TestLoader().loadTestsFromTestCase( StartProcessWithoutParamsTest ),
unittest.TestLoader().loadTestsFromTestCase( target.TargetTest ),
# *** Test without start/kill new processes # *** Test without start/kill new processes
unittest.TestLoader().loadTestsFromTestCase( intbase.IntBaseTest ), unittest.TestLoader().loadTestsFromTestCase( intbase.IntBaseTest ),
unittest.TestLoader().loadTestsFromTestCase( moduletest.ModuleTest ), unittest.TestLoader().loadTestsFromTestCase( moduletest.ModuleTest ),
@ -44,8 +45,10 @@ def getTestSuite( singleName = "" ):
unittest.TestLoader().loadTestsFromTestCase( typeinfo.TypeInfoTest ), unittest.TestLoader().loadTestsFromTestCase( typeinfo.TypeInfoTest ),
unittest.TestLoader().loadTestsFromTestCase( typedvar.TypedVarTest ), unittest.TestLoader().loadTestsFromTestCase( typedvar.TypedVarTest ),
unittest.TestLoader().loadTestsFromTestCase( regtest.CpuRegTest ), unittest.TestLoader().loadTestsFromTestCase( regtest.CpuRegTest ),
# *** # ^^^
unittest.TestLoader().loadTestsFromTestCase( TerminateProcessTest ), unittest.TestLoader().loadTestsFromTestCase( TerminateProcessTest ),
unittest.TestLoader().loadTestsFromTestCase( localstest.LocalVarsTest ),
] ) ] )
else: else:
return unittest.TestSuite( unittest.TestLoader().loadTestsFromName( singleName ) ) return unittest.TestSuite( unittest.TestLoader().loadTestsFromName( singleName ) )
@ -53,7 +56,7 @@ def getTestSuite( singleName = "" ):
if __name__ == "__main__": if __name__ == "__main__":
print "\nTesting PyKd ver. " + pykd.version print "\nTesting PyKd ver. " + pykd.version
target.appPath = sys.argv[1] target.appPath = sys.argv[1]
target.moduleName = os.path.splitext(os.path.basename(target.appPath))[0] target.moduleName = os.path.splitext(os.path.basename(target.appPath))[0]
#print "Test module: %s" % target.appPath #print "Test module: %s" % target.appPath

View File

@ -10,13 +10,6 @@ module = None
moduleName = None moduleName = None
processId = None processId = None
class TargetTest( unittest.TestCase ):
def testStartStop(self):
_locProcessId = pykd.startProcess( appPath )
pykd.killProcess( _locProcessId )
#module = None #module = None
#moduleName = None #moduleName = None

View File

@ -14,3 +14,12 @@ class ContextCallIt:
try: self.callIt() try: self.callIt()
except: pass except: pass
class KillProcess:
"""Kill process"""
def __init__(self, processId):
self.processId = processId
def __call__(self):
pykd.killProcess( self.processId )
pykd.detachProcess( self.processId )