~ 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
//
#pragma once
#include "dbgclient.h"
////////////////////////////////////////////////////////////////////////////////

View File

@ -4,6 +4,7 @@
#include <boost\python\tuple.hpp>
#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) );
switch (m_processorType)
{
case IMAGE_FILE_MACHINE_I386:
newContext->m_regValues[CV_REG_EIP] = frame.InstructionOffset;
newContext->m_regValues[CV_REG_EBP] = frame.FrameOffset;
newContext->m_regValues[CV_REG_ESP] = frame.StackOffset;
newContext->m_regValues[CV_REG_EIP] = stkFrmae.m_instructionOffset;
newContext->m_regValues[CV_REG_EBP] = stkFrmae.m_frameOffset;
newContext->m_regValues[CV_REG_ESP] = stkFrmae.m_stackOffset;
return newContext;
case IMAGE_FILE_MACHINE_AMD64:
newContext->m_regValues[CV_AMD64_RIP] = frame.InstructionOffset;
newContext->m_regValues[CV_AMD64_RBP] = frame.FrameOffset;
newContext->m_regValues[CV_AMD64_RSP] = frame.StackOffset;
newContext->m_regValues[CV_AMD64_RIP] = stkFrmae.m_instructionOffset;
newContext->m_regValues[CV_AMD64_RBP] = stkFrmae.m_frameOffset;
newContext->m_regValues[CV_AMD64_RSP] = stkFrmae.m_stackOffset;
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;
typedef boost::shared_ptr< ThreadContext > ContextPtr;
class StackFrame;
////////////////////////////////////////////////////////////////////////////////
std::string processorToStr(ULONG processorMode);
@ -52,7 +54,7 @@ public:
return pykd::processorToStr(m_processorType);
}
ContextPtr forkByStackFrame(DEBUG_STACK_FRAME &frame) const;
ContextPtr forkByStackFrame(const StackFrame &stkFrmae) const;
private:
@ -76,9 +78,5 @@ private:
////////////////////////////////////////////////////////////////////////////////
std::string printStackFrame(DEBUG_STACK_FRAME &frame);
////////////////////////////////////////////////////////////////////////////////
}

View File

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

View File

@ -5,6 +5,9 @@
#include <dbghelp.h>
#include <boost\smart_ptr\scoped_ptr.hpp>
#include <boost\enable_shared_from_this.hpp>
/////////////////////////////////////////////////////////////////////////////////
#include "dbgobj.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:
// simple IDebugControl4 call wrapper

View File

@ -19,6 +19,7 @@
#include "intbase.h"
#include "process.h"
#include "bpoint.h"
#include "stkframe.h"
#include "pykdver.h"
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( DebugClient_setSoftwareBp, DebugClient::setSoftwareBp, 1, 2 );
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) \
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( "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 )
.def_readonly( "instructionOffset", &DEBUG_STACK_FRAME::InstructionOffset,
.def_readonly( "instructionOffset", &StackFrame::m_instructionOffset,
"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" )
.def_readonly( "frameOffset", &DEBUG_STACK_FRAME::FrameOffset,
.def_readonly( "frameOffset", &StackFrame::m_frameOffset,
"Return a frame's offset" )
.def_readonly( "stackOffset", &DEBUG_STACK_FRAME::StackOffset,
.def_readonly( "stackOffset", &StackFrame::m_stackOffset,
"Return a frame's stack offset" )
.def_readonly( "frameNumber", &DEBUG_STACK_FRAME::FrameNumber,
.def_readonly( "frameNumber", &StackFrame::m_frameNumber,
"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");
python::class_<ThreadContext, ContextPtr>(

View File

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

View File

@ -465,6 +465,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath=".\stkframe.cpp"
>
</File>
<File
RelativePath=".\synsymbol.cpp"
>
@ -583,6 +587,10 @@
RelativePath=".\stdafx.h"
>
</File>
<File
RelativePath=".\stkframe.h"
>
</File>
<File
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
# get local variables from previous stack frame
prevStackThreadCtx = newClnt.getContext().fork( newClnt.getCurrentStack()[1] )
prevLocals = newClnt.getLocals( prevStackThreadCtx )
prevLocals = newClnt.getCurrentStack()[1].getLocals()
self.assertEqual( len(prevLocals), len(locals) )
for varName in locals.iterkeys():