mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-29 20:03:33 +08:00
[0.1.x]
+ 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:
parent
da5633cc12
commit
bbe357cf31
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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 )
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user