+ fork new thread context by stack frame
 + test of local variables of previous stack frame

git-svn-id: https://pykd.svn.codeplex.com/svn@73627 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2012-01-25 11:57:47 +00:00 committed by Mikhail I. Izmestev
parent da5633cc12
commit bbe357cf31
5 changed files with 98 additions and 15 deletions

View File

@ -129,10 +129,7 @@ ThreadContext::ThreadContext( IDebugClient4 *client ) :
return; return;
} }
std::stringstream sstream; throwUnsupportedProcessor(__FUNCTION__);
sstream << __FUNCTION__ << ":\n";
sstream << "Unsupported processor type: 0x" << std::hex << m_processorType;
throw DbgException( sstream.str() );
} }
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
@ -191,6 +188,29 @@ ULONG64 ThreadContext::getSp() const
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
ContextPtr ThreadContext::forkByStackFrame(DEBUG_STACK_FRAME &frame) 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;
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;
return newContext;
}
throwUnsupportedProcessor(__FUNCTION__);
}
/////////////////////////////////////////////////////////////////////////////////
python::object ThreadContext::getByIndex(ULONG ind) const python::object ThreadContext::getByIndex(ULONG ind) const
{ {
RegValues::const_iterator it = m_regValues.begin(); RegValues::const_iterator it = m_regValues.begin();
@ -345,4 +365,30 @@ bool ThreadContext::getSubValue(ULONG cvRegId, ULONG64 &val) const
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
void ThreadContext::throwUnsupportedProcessor(PCSTR szFunction) const
{
std::stringstream sstream;
sstream << szFunction << ":\n";
sstream << "Unsupported processor type: 0x" << std::hex << m_processorType;
throw DbgException( sstream.str() );
}
/////////////////////////////////////////////////////////////////////////////////
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

@ -10,6 +10,14 @@
namespace pykd { namespace pykd {
////////////////////////////////////////////////////////////////////////////////
class ThreadContext;
typedef boost::shared_ptr< ThreadContext > ContextPtr;
////////////////////////////////////////////////////////////////////////////////
std::string processorToStr(ULONG processorMode); std::string processorToStr(ULONG processorMode);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -17,7 +25,6 @@ std::string processorToStr(ULONG processorMode);
class ThreadContext : private DbgObject class ThreadContext : private DbgObject
{ {
public: public:
ThreadContext( IDebugClient4 *client ); ThreadContext( IDebugClient4 *client );
// get register value by ID // get register value by ID
@ -45,6 +52,8 @@ public:
return pykd::processorToStr(m_processorType); return pykd::processorToStr(m_processorType);
} }
ContextPtr forkByStackFrame(DEBUG_STACK_FRAME &frame) const;
private: private:
// query i386 registers // query i386 registers
@ -56,6 +65,8 @@ private:
// try query as "sub-register" // try query as "sub-register"
bool getSubValue(ULONG cvRegId, ULONG64 &val) const; bool getSubValue(ULONG cvRegId, ULONG64 &val) const;
void __declspec(noreturn) throwUnsupportedProcessor(PCSTR szFunction) const;
private: private:
typedef std::map<ULONG, ULONG64> RegValues; typedef std::map<ULONG, ULONG64> RegValues;
RegValues m_regValues; RegValues m_regValues;
@ -65,7 +76,7 @@ private:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
typedef boost::shared_ptr< ThreadContext > ContextPtr; std::string printStackFrame(DEBUG_STACK_FRAME &frame);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -632,7 +632,9 @@ BOOST_PYTHON_MODULE( pykd )
.def_readonly( "stackOffset", &DEBUG_STACK_FRAME::StackOffset, .def_readonly( "stackOffset", &DEBUG_STACK_FRAME::StackOffset,
"Return a frame's stack offset" ) "Return a frame's stack offset" )
.def_readonly( "frameNumber", &DEBUG_STACK_FRAME::FrameNumber, .def_readonly( "frameNumber", &DEBUG_STACK_FRAME::FrameNumber,
"Return a frame's number" ); "Return a frame's number" )
.def( "__str__", &printStackFrame,
"Return stacks frame as string");
python::class_<ThreadContext, ContextPtr>( python::class_<ThreadContext, ContextPtr>(
"Context", "Context of thread (register values)", python::no_init ) "Context", "Context of thread (register values)", python::no_init )
@ -646,6 +648,8 @@ BOOST_PYTHON_MODULE( pykd )
"Get register value by ID (CV_REG_XXX)" ) "Get register value by ID (CV_REG_XXX)" )
.def( "processorType", &ThreadContext::getProcessorType, .def( "processorType", &ThreadContext::getProcessorType,
"Get processor ThreadContext as string") "Get processor ThreadContext as string")
.def( "fork", &ThreadContext::forkByStackFrame,
"Create new thread context by stackFrame")
.def("__len__", &ThreadContext::getCount, .def("__len__", &ThreadContext::getCount,
"Return count of registers") "Return count of registers")
.def("__getitem__", &ThreadContext::getByIndex, .def("__getitem__", &ThreadContext::getByIndex,

View File

@ -8,14 +8,14 @@ class LocalVarsTest(unittest.TestCase):
def testLocalVariable(self): def testLocalVariable(self):
"""Start new process and test local variables""" """Start new process and test local variables"""
testClient = pykd.createDbgClient() newClnt = pykd.createDbgClient()
testClient.startProcess( target.appPath + " -testEnumWindows" ) newClnt.startProcess( target.appPath + " -testEnumWindows" )
testClient.go() # initial breakpoint -> wmain newClnt.go() # initial breakpoint -> wmain
testClient.go() # wmain -> targetapp!EnumWindowsProc1 newClnt.go() # wmain -> targetapp!EnumWindowsProc1
# pykd.dprint( "\n" + testClient.dbgCommand("u") ) # pykd.dprint( "\n" + newClnt.dbgCommand("u") )
locals = testClient.getLocals() locals = newClnt.getLocals()
self.assertNotEqual( 0, locals["hWindow"] ) self.assertNotEqual( 0, locals["hWindow"] )
self.assertEqual( pykd.DataIsParam, locals["hWindow"].dataKind() ) self.assertEqual( pykd.DataIsParam, locals["hWindow"].dataKind() )
@ -31,9 +31,20 @@ class LocalVarsTest(unittest.TestCase):
self.assertEqual( locals["dwProccessId"] + 1, locals["staticVar"] ) self.assertEqual( locals["dwProccessId"] + 1, locals["staticVar"] )
testClient.go() # targetapp!EnumWindowsProc1 -> targetapp!EnumWindowsProc2 newClnt.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1
locals = testClient.getLocals()
# get local variables from previous stack frame
prevStackThreadCtx = newClnt.getContext().fork( newClnt.getCurrentStack()[1] )
prevLocals = newClnt.getLocals( prevStackThreadCtx )
self.assertEqual( len(prevLocals), len(locals) )
for varName in locals.iterkeys():
self.assertEqual( prevLocals[varName], locals[varName] )
newClnt.go() # targetapp!EnumWindowsProc1 -> targetapp!EnumWindowsProc2
locals = newClnt.getLocals()
self.assertEqual( len(locals), 2 ) self.assertEqual( len(locals), 2 )
locValues = locals.values() locValues = locals.values()
self.assertTrue( locValues[0] == 7 or locValues[1] == 7 ) self.assertTrue( locValues[0] == 7 or locValues[1] == 7 )

View File

@ -303,6 +303,16 @@ void FuncWithName1(int a)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#pragma optimize("g", off) #pragma optimize("g", off)
VOID functionCalledFromEnumWindowsProc1(DWORD dwProcessId)
{
DWORD dwCurrentProcessId = GetCurrentProcessId();
if (dwCurrentProcessId != dwProcessId)
std::cout << dwCurrentProcessId << dwProcessId;
__debugbreak();
}
////////////////////////////////////////////////////////////////////////////////
BOOL CALLBACK EnumWindowsProc1( BOOL CALLBACK EnumWindowsProc1(
HWND hWindow, HWND hWindow,
const LPARAM lParam const LPARAM lParam
@ -318,6 +328,7 @@ BOOL CALLBACK EnumWindowsProc1(
DWORD dwThreadId = ::GetWindowThreadProcessId(hWindow, &dwProccessId); DWORD dwThreadId = ::GetWindowThreadProcessId(hWindow, &dwProccessId);
staticVar = dwProccessId + 1; staticVar = dwProccessId + 1;
__debugbreak(); __debugbreak();
functionCalledFromEnumWindowsProc1(dwProccessId);
std::cout << dwProccessId << dwThreadId << staticVar; std::cout << dwProccessId << dwThreadId << staticVar;
} }
return hWindow ? FALSE : TRUE; return hWindow ? FALSE : TRUE;