~ bind stack frame to debug client
 + get local vars from stack frame

git-svn-id: https://pykd.svn.codeplex.com/svn@73631 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2012-01-25 14:34:18 +00:00 committed by Mikhail I. Izmestev
parent bbe357cf31
commit b7addbf064
11 changed files with 136 additions and 42 deletions

View File

@ -2,6 +2,8 @@
// Breakpoints management // Breakpoints management
// //
#pragma once
#include "dbgclient.h" #include "dbgclient.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -4,6 +4,7 @@
#include <boost\python\tuple.hpp> #include <boost\python\tuple.hpp>
#include "context.h" #include "context.h"
#include "stkframe.h"
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
@ -188,21 +189,21 @@ ULONG64 ThreadContext::getSp() const
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
ContextPtr ThreadContext::forkByStackFrame(DEBUG_STACK_FRAME &frame) const ContextPtr ThreadContext::forkByStackFrame(const StackFrame &stkFrmae) const
{ {
ContextPtr newContext( new ThreadContext(*this) ); ContextPtr newContext( new ThreadContext(*this) );
switch (m_processorType) switch (m_processorType)
{ {
case IMAGE_FILE_MACHINE_I386: case IMAGE_FILE_MACHINE_I386:
newContext->m_regValues[CV_REG_EIP] = frame.InstructionOffset; newContext->m_regValues[CV_REG_EIP] = stkFrmae.m_instructionOffset;
newContext->m_regValues[CV_REG_EBP] = frame.FrameOffset; newContext->m_regValues[CV_REG_EBP] = stkFrmae.m_frameOffset;
newContext->m_regValues[CV_REG_ESP] = frame.StackOffset; newContext->m_regValues[CV_REG_ESP] = stkFrmae.m_stackOffset;
return newContext; return newContext;
case IMAGE_FILE_MACHINE_AMD64: case IMAGE_FILE_MACHINE_AMD64:
newContext->m_regValues[CV_AMD64_RIP] = frame.InstructionOffset; newContext->m_regValues[CV_AMD64_RIP] = stkFrmae.m_instructionOffset;
newContext->m_regValues[CV_AMD64_RBP] = frame.FrameOffset; newContext->m_regValues[CV_AMD64_RBP] = stkFrmae.m_frameOffset;
newContext->m_regValues[CV_AMD64_RSP] = frame.StackOffset; newContext->m_regValues[CV_AMD64_RSP] = stkFrmae.m_stackOffset;
return newContext; return newContext;
} }
@ -375,20 +376,4 @@ void ThreadContext::throwUnsupportedProcessor(PCSTR szFunction) const
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
std::string printStackFrame(DEBUG_STACK_FRAME &frame)
{
std::stringstream sstream;
sstream << std::dec << "(" << frame.FrameNumber << ")";
sstream << " ip= 0x" << std::hex << frame.InstructionOffset;
sstream << ", ret= 0x" << std::hex << frame.ReturnOffset;
sstream << ", frame= 0x" << std::hex << frame.FrameOffset;
sstream << ", stack= 0x" << std::hex << frame.StackOffset;
return sstream.str();
}
/////////////////////////////////////////////////////////////////////////////////
} }

View File

@ -16,6 +16,8 @@ namespace pykd {
class ThreadContext; class ThreadContext;
typedef boost::shared_ptr< ThreadContext > ContextPtr; typedef boost::shared_ptr< ThreadContext > ContextPtr;
class StackFrame;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string processorToStr(ULONG processorMode); std::string processorToStr(ULONG processorMode);
@ -52,7 +54,7 @@ public:
return pykd::processorToStr(m_processorType); return pykd::processorToStr(m_processorType);
} }
ContextPtr forkByStackFrame(DEBUG_STACK_FRAME &frame) const; ContextPtr forkByStackFrame(const StackFrame &stkFrmae) const;
private: private:
@ -76,9 +78,5 @@ private:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string printStackFrame(DEBUG_STACK_FRAME &frame);
////////////////////////////////////////////////////////////////////////////////
} }

View File

@ -2,7 +2,7 @@
#include <vector> #include <vector>
#include "dbgclient.h" #include "dbgclient.h"
#include "stkframe.h"
namespace pykd { namespace pykd {

View File

@ -5,6 +5,9 @@
#include <dbghelp.h> #include <dbghelp.h>
#include <boost\smart_ptr\scoped_ptr.hpp> #include <boost\smart_ptr\scoped_ptr.hpp>
#include <boost\enable_shared_from_this.hpp>
/////////////////////////////////////////////////////////////////////////////////
#include "dbgobj.h" #include "dbgobj.h"
#include "dbgexcept.h" #include "dbgexcept.h"
@ -41,7 +44,8 @@ struct BpCallbackMap {
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
class DebugClient : private DbgObject { class DebugClient : private DbgObject
, public boost::enable_shared_from_this<DebugClient> {
private: private:
// simple IDebugControl4 call wrapper // simple IDebugControl4 call wrapper

View File

@ -19,6 +19,7 @@
#include "intbase.h" #include "intbase.h"
#include "process.h" #include "process.h"
#include "bpoint.h" #include "bpoint.h"
#include "stkframe.h"
#include "pykdver.h" #include "pykdver.h"
using namespace pykd; using namespace pykd;
@ -103,6 +104,7 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_getLocals, DebugClient::getL
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( pyDia_Symbol_findChildrenEx, pyDia::Symbol::findChildrenEx, 1, 3 ); BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( pyDia_Symbol_findChildrenEx, pyDia::Symbol::findChildrenEx, 1, 3 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_setSoftwareBp, DebugClient::setSoftwareBp, 1, 2 ); BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_setSoftwareBp, DebugClient::setSoftwareBp, 1, 2 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_setHardwareBp, DebugClient::setHardwareBp, 3, 4 ); BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( DebugClient_setHardwareBp, DebugClient::setHardwareBp, 3, 4 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( StackFrame_getLocals, StackFrame::getLocals, 0, 1 );
#define DEF_PY_CONST_ULONG(x) \ #define DEF_PY_CONST_ULONG(x) \
python::scope().attr(#x) = ULONG(##x) python::scope().attr(#x) = ULONG(##x)
@ -621,19 +623,21 @@ BOOST_PYTHON_MODULE( pykd )
.def( "ea", &Disasm::ea, "Return effective address for last disassembled instruction or 0" ) .def( "ea", &Disasm::ea, "Return effective address for last disassembled instruction or 0" )
.def( "reset", &Disasm::reset, "Reset current offset to begin" ); .def( "reset", &Disasm::reset, "Reset current offset to begin" );
python::class_<DEBUG_STACK_FRAME>( "stackFrame", python::class_<StackFrame>( "stackFrame",
"Class representing a frame of the call stack", python::no_init ) "Class representing a frame of the call stack", python::no_init )
.def_readonly( "instructionOffset", &DEBUG_STACK_FRAME::InstructionOffset, .def_readonly( "instructionOffset", &StackFrame::m_instructionOffset,
"Return a frame's instruction offset" ) "Return a frame's instruction offset" )
.def_readonly( "returnOffset", &DEBUG_STACK_FRAME::ReturnOffset, .def_readonly( "returnOffset", &StackFrame::m_returnOffset,
"Return a frame's return offset" ) "Return a frame's return offset" )
.def_readonly( "frameOffset", &DEBUG_STACK_FRAME::FrameOffset, .def_readonly( "frameOffset", &StackFrame::m_frameOffset,
"Return a frame's offset" ) "Return a frame's offset" )
.def_readonly( "stackOffset", &DEBUG_STACK_FRAME::StackOffset, .def_readonly( "stackOffset", &StackFrame::m_stackOffset,
"Return a frame's stack offset" ) "Return a frame's stack offset" )
.def_readonly( "frameNumber", &DEBUG_STACK_FRAME::FrameNumber, .def_readonly( "frameNumber", &StackFrame::m_frameNumber,
"Return a frame's number" ) "Return a frame's number" )
.def( "__str__", &printStackFrame, .def( "getLocals", &StackFrame::getLocals, StackFrame_getLocals( python::args( "ctx" ),
"Get list of local variables for this stack frame" ) )
.def( "__str__", &StackFrame::print,
"Return stacks frame as string"); "Return stacks frame as string");
python::class_<ThreadContext, ContextPtr>( python::class_<ThreadContext, ContextPtr>(

View File

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "dbgclient.h" #include "dbgclient.h"
#include "stkframe.h"
namespace pykd { namespace pykd {
@ -62,10 +63,10 @@ DebugClient::getCurrentStack()
for ( ULONG i = 0; i < filledFrames; ++i ) for ( ULONG i = 0; i < filledFrames; ++i )
{ {
python::object frameObj( frames[i] ); python::object frameObj( StackFrame(shared_from_this(), frames[i]) );
frameList.append( frameObj ); frameList.append( frameObj );
} }
return frameList; return frameList;
} }

View File

@ -465,6 +465,10 @@
/> />
</FileConfiguration> </FileConfiguration>
</File> </File>
<File
RelativePath=".\stkframe.cpp"
>
</File>
<File <File
RelativePath=".\synsymbol.cpp" RelativePath=".\synsymbol.cpp"
> >
@ -583,6 +587,10 @@
RelativePath=".\stdafx.h" RelativePath=".\stdafx.h"
> >
</File> </File>
<File
RelativePath=".\stkframe.h"
>
</File>
<File <File
RelativePath=".\synsymbol.h" RelativePath=".\synsymbol.h"
> >

55
pykd/stkframe.cpp Normal file
View File

@ -0,0 +1,55 @@
//
// Stack frame: DEBUG_STACK_FRAME wrapper
//
#include "stdafx.h"
#include "stkframe.h"
////////////////////////////////////////////////////////////////////////////////
namespace pykd {
////////////////////////////////////////////////////////////////////////////////
StackFrame::StackFrame(DebugClientPtr client, const DEBUG_STACK_FRAME &frame)
: m_client(client)
, m_frameNumber(frame.FrameNumber)
, m_instructionOffset(frame.InstructionOffset)
, m_returnOffset(frame.ReturnOffset)
, m_frameOffset(frame.FrameOffset)
, m_stackOffset(frame.StackOffset)
{
}
////////////////////////////////////////////////////////////////////////////////
std::string StackFrame::print() const
{
std::stringstream sstream;
sstream << std::dec << "(" << m_frameNumber << ")";
sstream << " ip= 0x" << std::hex << m_instructionOffset;
sstream << ", ret= 0x" << std::hex << m_returnOffset;
sstream << ", frame= 0x" << std::hex << m_frameOffset;
sstream << ", stack= 0x" << std::hex << m_stackOffset;
return sstream.str();
}
////////////////////////////////////////////////////////////////////////////////
python::dict StackFrame::getLocals(ContextPtr ctx /*= ContextPtr()*/)
{
ctx = ctx ? ctx->forkByStackFrame(*this)
: m_client->getThreadContext()->forkByStackFrame(*this);
return m_client->getLocals(ctx);
}
////////////////////////////////////////////////////////////////////////////////
} // namespace pykd
////////////////////////////////////////////////////////////////////////////////

38
pykd/stkframe.h Normal file
View File

@ -0,0 +1,38 @@
//
// Stack frame: DEBUG_STACK_FRAME wrapper
//
#pragma once
#include "dbgclient.h"
////////////////////////////////////////////////////////////////////////////////
namespace pykd {
////////////////////////////////////////////////////////////////////////////////
class StackFrame
{
public:
StackFrame(DebugClientPtr client, const DEBUG_STACK_FRAME &frame);
ULONG m_frameNumber;
ULONG64 m_instructionOffset;
ULONG64 m_returnOffset;
ULONG64 m_frameOffset;
ULONG64 m_stackOffset;
python::dict getLocals(ContextPtr ctx = ContextPtr());
std::string print() const;
private:
DebugClientPtr m_client;
};
////////////////////////////////////////////////////////////////////////////////
} // namespace pykd
////////////////////////////////////////////////////////////////////////////////

View File

@ -34,8 +34,7 @@ class LocalVarsTest(unittest.TestCase):
newClnt.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1 newClnt.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1
# get local variables from previous stack frame # get local variables from previous stack frame
prevStackThreadCtx = newClnt.getContext().fork( newClnt.getCurrentStack()[1] ) prevLocals = newClnt.getCurrentStack()[1].getLocals()
prevLocals = newClnt.getLocals( prevStackThreadCtx )
self.assertEqual( len(prevLocals), len(locals) ) self.assertEqual( len(prevLocals), len(locals) )
for varName in locals.iterkeys(): for varName in locals.iterkeys():