mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-19 19:13: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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dbgclient.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "dbgclient.h"
|
||||
|
||||
#include "stkframe.h"
|
||||
|
||||
namespace pykd {
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>(
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
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
|
||||
|
||||
# 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():
|
||||
|
Loading…
Reference in New Issue
Block a user