mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-05-13 14:03:22 +08:00
[0.1.x]
~ 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:
parent
bbe357cf31
commit
b7addbf064
@ -2,6 +2,8 @@
|
|||||||
// Breakpoints management
|
// Breakpoints management
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include "dbgclient.h"
|
#include "dbgclient.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "dbgclient.h"
|
#include "dbgclient.h"
|
||||||
|
#include "stkframe.h"
|
||||||
|
|
||||||
namespace pykd {
|
namespace pykd {
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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>(
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
55
pykd/stkframe.cpp
Normal 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
38
pykd/stkframe.h
Normal 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
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
@ -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():
|
||||||
|
Loading…
Reference in New Issue
Block a user