diff --git a/pykd/bpoint.h b/pykd/bpoint.h index cfd9128..693ac1c 100644 --- a/pykd/bpoint.h +++ b/pykd/bpoint.h @@ -2,6 +2,8 @@ // Breakpoints management // +#pragma once + #include "dbgclient.h" //////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/context.cpp b/pykd/context.cpp index 1d3dca9..b90b75f 100644 --- a/pykd/context.cpp +++ b/pykd/context.cpp @@ -4,6 +4,7 @@ #include #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(); -} - -///////////////////////////////////////////////////////////////////////////////// - } diff --git a/pykd/context.h b/pykd/context.h index 327157f..2196bd1 100644 --- a/pykd/context.h +++ b/pykd/context.h @@ -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); - -//////////////////////////////////////////////////////////////////////////////// - } diff --git a/pykd/dbgclient.cpp b/pykd/dbgclient.cpp index bab0f5f..6f5fe44 100644 --- a/pykd/dbgclient.cpp +++ b/pykd/dbgclient.cpp @@ -2,7 +2,7 @@ #include #include "dbgclient.h" - +#include "stkframe.h" namespace pykd { diff --git a/pykd/dbgclient.h b/pykd/dbgclient.h index f4f9d14..b0fab1e 100644 --- a/pykd/dbgclient.h +++ b/pykd/dbgclient.h @@ -5,6 +5,9 @@ #include #include +#include + +///////////////////////////////////////////////////////////////////////////////// #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 { private: // simple IDebugControl4 call wrapper diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index 4cb3a14..762b9c5 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -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_( "stackFrame", + python::class_( "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_( diff --git a/pykd/process.cpp b/pykd/process.cpp index ac6a817..1a9115a 100644 --- a/pykd/process.cpp +++ b/pykd/process.cpp @@ -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; } diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index 86fddea..30db6c7 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -465,6 +465,10 @@ /> + + @@ -583,6 +587,10 @@ RelativePath=".\stdafx.h" > + + diff --git a/pykd/stkframe.cpp b/pykd/stkframe.cpp new file mode 100644 index 0000000..639da60 --- /dev/null +++ b/pykd/stkframe.cpp @@ -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 + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/pykd/stkframe.h b/pykd/stkframe.h new file mode 100644 index 0000000..7f1b712 --- /dev/null +++ b/pykd/stkframe.h @@ -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 + +//////////////////////////////////////////////////////////////////////////////// diff --git a/test/scripts/localstest.py b/test/scripts/localstest.py index 5a2ad6a..79cc7a6 100644 --- a/test/scripts/localstest.py +++ b/test/scripts/localstest.py @@ -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():