From 77b1eee2f4cfa42881959f1ab1f4bae1ab0299f7 Mon Sep 17 00:00:00 2001 From: "SND\\EreTIk_cp" Date: Tue, 4 Sep 2012 14:58:50 +0000 Subject: [PATCH] [0.2.x] + locals git-svn-id: https://pykd.svn.codeplex.com/svn@79357 9b283d60-5439-405e-af05-b73fd8c4d996 --- pykd/dbgengine.h | 3 +- pykd/dia/diawrapper.cpp | 98 ++++++++++++++++---- pykd/dia/diawrapper.h | 14 ++- pykd/localvar.cpp | 185 ++++++++++++++++++++++++++++++++++++- pykd/localvar.h | 2 +- pykd/module.cpp | 4 +- pykd/module.h | 2 +- pykd/pykd_2008.vcproj | 6 +- pykd/pymod.cpp | 6 +- pykd/stkframe.cpp | 37 +++++--- pykd/stkframe.h | 5 +- pykd/symengine.h | 11 ++- pykd/win/dbgeng.cpp | 42 +++------ test/scripts/localstest.py | 69 +++++++------- test/scripts/moduletest.py | 2 +- test/scripts/pykdtest.py | 9 +- test/scripts/target.py | 7 -- test/scripts/testutils.py | 9 ++ 18 files changed, 381 insertions(+), 130 deletions(-) diff --git a/pykd/dbgengine.h b/pykd/dbgengine.h index cc644b5..7d1dde3 100644 --- a/pykd/dbgengine.h +++ b/pykd/dbgengine.h @@ -59,8 +59,7 @@ struct STACK_FRAME_DESC { ULONG64 stackOffset; }; -ULONG getStackTraceFrameCount(); -void getStackTrace( STACK_FRAME_DESC* frames, ULONG frameCount, ULONG* frameReturned = NULL ); +void getStackTrace(std::vector &frames); //breakpoints ULONG breakPointSet( ULONG64 offset, bool hardware = false, ULONG size = 0, ULONG accessType = 0 ); diff --git a/pykd/dia/diawrapper.cpp b/pykd/dia/diawrapper.cpp index 62b94b2..f5ee616 100644 --- a/pykd/dia/diawrapper.cpp +++ b/pykd/dia/diawrapper.cpp @@ -8,6 +8,36 @@ namespace pykd { /////////////////////////////////////////////////////////////////////////////// +static const struct DiaRegToRegRelativeAmd64 : DiaRegToRegRelativeBase +{ + typedef std::map Base; + DiaRegToRegRelativeAmd64(); +} g_DiaRegToRegRelativeAmd64; + +DiaRegToRegRelativeAmd64::DiaRegToRegRelativeAmd64() +{ + (*this)[CV_AMD64_RIP] = rriInstructionPointer; + (*this)[CV_AMD64_RBP] = rriStackFrame; + (*this)[CV_AMD64_RSP] = rriStackPointer; +} + +/////////////////////////////////////////////////////////////////////////////// + +static const struct DiaRegToRegRelativeI386 : DiaRegToRegRelativeBase +{ + typedef std::map Base; + DiaRegToRegRelativeI386(); +} g_DiaRegToRegRelativeI386; + +DiaRegToRegRelativeI386::DiaRegToRegRelativeI386() +{ + (*this)[CV_REG_EIP] = rriInstructionPointer; + (*this)[CV_REG_EBP] = rriStackFrame; + (*this)[CV_REG_ESP] = rriStackPointer; +} + +/////////////////////////////////////////////////////////////////////////////// + const std::string DiaException::descPrefix("pyDia: "); std::string DiaException::makeFullDesc(const std::string &desc, HRESULT hres) @@ -96,18 +126,21 @@ std::string getBasicTypeName( ULONG basicType ) //////////////////////////////////////////////////////////////////////////////// -DiaSymbol::DiaSymbol(__inout DiaSymbolPtr &_symbol ) +DiaSymbol::DiaSymbol(__inout DiaSymbolPtr &_symbol, DWORD machineType ) + : m_symbol(_symbol), m_machineType(machineType) { - m_symbol = _symbol; - m_symbol->get_machineType(&m_machineType); } ////////////////////////////////////////////////////////////////////////////////// -DiaSymbol::DiaSymbol( IDiaSymbol *_symbol ) +SymbolPtr DiaSymbol::fromGlobalScope( IDiaSymbol *_symbol ) { - m_symbol = _symbol; - m_symbol->get_machineType(&m_machineType); + DWORD machineType; + HRESULT hres = _symbol->get_machineType(&machineType); + if (S_OK != hres) + throw DiaException("IDiaSymbol::get_machineType", hres); + + return SymbolPtr( new DiaSymbol(DiaSymbolPtr(_symbol), machineType) ); } ////////////////////////////////////////////////////////////////////////////////// @@ -148,7 +181,7 @@ SymbolPtrList DiaSymbol::findChildren( ULONG celt; while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) ) { - childList.push_back( SymbolPtr( new DiaSymbol(child) ) ); + childList.push_back( SymbolPtr( new DiaSymbol(child, m_machineType) ) ); child = NULL; } @@ -220,7 +253,7 @@ SymbolPtr DiaSymbol::getChildByIndex(ULONG symTag, ULONG _index ) if (S_OK != hres) throw DiaException("Call IDiaEnumSymbols::Item", hres); - return SymbolPtr( new DiaSymbol(child) ); + return SymbolPtr( new DiaSymbol(child, m_machineType) ); } //////////////////////////////////////////////////////////////////////////////// @@ -247,7 +280,7 @@ SymbolPtr DiaSymbol::getChildByName(const std::string &name ) if (S_OK != hres) throw DiaException("Call IDiaEnumSymbols::Item", hres); - return SymbolPtr( new DiaSymbol(child) ); + return SymbolPtr( new DiaSymbol(child, m_machineType) ); } std::string pattern = "*"; @@ -279,7 +312,7 @@ SymbolPtr DiaSymbol::getChildByName(const std::string &name ) if (S_OK != hres) throw DiaException("Call IDiaEnumSymbols::Item", hres); - SymbolPtr symPtr = SymbolPtr( new DiaSymbol(child) ); + SymbolPtr symPtr = SymbolPtr( new DiaSymbol(child, m_machineType) ); if ( name == symPtr->getName() ) return symPtr; @@ -304,6 +337,33 @@ ULONG DiaSymbol::getDataKind() //////////////////////////////////////////////////////////////////////////////// +ULONG DiaSymbol::getRegRealativeId() +{ + switch (m_machineType) + { + case IMAGE_FILE_MACHINE_AMD64: + return getRegRealativeIdImpl(g_DiaRegToRegRelativeAmd64); + case IMAGE_FILE_MACHINE_I386: + return getRegRealativeIdImpl(g_DiaRegToRegRelativeI386); + } + throw DiaException("Unsupported machine type"); +} + +//////////////////////////////////////////////////////////////////////////////// + +ULONG DiaSymbol::getRegRealativeIdImpl(const DiaRegToRegRelativeBase &DiaRegToRegRelative) +{ + DiaRegToRegRelativeBase::const_iterator it = + DiaRegToRegRelative.find(callSymbol(get_registerId)); + + if (it == DiaRegToRegRelative.end()) + throw DiaException("Cannot convert DAI register ID to relative register ID"); + + return it->second; +} + +//////////////////////////////////////////////////////////////////////////////// + ULONG DiaSymbol::getIndexId() { return callSymbol(get_symIndexId); @@ -313,7 +373,8 @@ ULONG DiaSymbol::getIndexId() SymbolPtr DiaSymbol::getIndexType() { - return SymbolPtr( new DiaSymbol(callSymbol(get_arrayIndexType) ) ); + DiaSymbolPtr diaSymbol(callSymbol(get_arrayIndexType)); + return SymbolPtr( new DiaSymbol(diaSymbol, m_machineType) ); } //////////////////////////////////////////////////////////////////////////////// @@ -381,7 +442,8 @@ ULONG DiaSymbol::getSymTag() SymbolPtr DiaSymbol::getType() { - return SymbolPtr( new DiaSymbol( callSymbol(get_type) ) ); + DiaSymbolPtr diaSymbol(callSymbol(get_type)); + return SymbolPtr( new DiaSymbol( diaSymbol, m_machineType ) ); } //////////////////////////////////////////////////////////////////////////////// @@ -480,9 +542,10 @@ ULONG DiaSymbol::getVirtualBaseDispIndex() ULONG DiaSymbol::getVirtualBaseDispSize() { - SymbolPtr baseTableType = SymbolPtr( new DiaSymbol( callSymbol(get_virtualBaseTableType) ) ); + DiaSymbolPtr diaSymbol(callSymbol(get_virtualBaseTableType)); + SymbolPtr baseTableType = SymbolPtr( new DiaSymbol( diaSymbol, m_machineType ) ); - return (ULONG)baseTableType->getType()->getSize(); + return (ULONG)baseTableType->getType()->getSize(); } ////////////////////////////////////////////////////////////////////////////// @@ -534,10 +597,13 @@ SymbolPtr DiaSession::findByRva( ULONG rva, ULONG symTag, LONG* pdisplacement ) throw DiaException("Call IDiaSession::findSymbolByRVAEx", hres); if (!child) throw DiaException("Call IDiaSession::findSymbolByRVAEx", E_UNEXPECTED); - if ( pdisplacement == NULL && displacement != 0 ) + if ( !pdisplacement && displacement) throw DiaException("Call IDiaSession::findSymbolByRVAEx failed to find suymbol" ); - return SymbolPtr( new DiaSymbol(child) ); + if (pdisplacement) + *pdisplacement = displacement; + + return SymbolPtr( new DiaSymbol(child, m_globalSymbol->getMachineType() ) ); } /////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dia/diawrapper.h b/pykd/dia/diawrapper.h index bd40afa..a42053e 100644 --- a/pykd/dia/diawrapper.h +++ b/pykd/dia/diawrapper.h @@ -19,6 +19,8 @@ typedef CComPtr< IDiaEnumLineNumbers > DiaEnumLineNumbersPtr; typedef CComPtr< IDiaLineNumber> DiaLineNumberPtr; typedef CComPtr< IDiaSourceFile > DiaSourceFilePtr; +typedef std::map DiaRegToRegRelativeBase; + ////////////////////////////////////////////////////////////////////////////// class DiaException : public SymbolException { @@ -51,10 +53,9 @@ private: class DiaSymbol : public Symbol { public: + DiaSymbol( DiaSymbolPtr &_symbol, DWORD machineType ); - DiaSymbol( DiaSymbolPtr &_symbol ); - - DiaSymbol( IDiaSymbol *_symbol ); + static SymbolPtr fromGlobalScope( IDiaSymbol *_symbol ); SymbolPtr getChildByName(const std::string &_name ); @@ -105,6 +106,7 @@ public: ULONG getDataKind(); //ULONG getRegisterId(); + virtual ULONG getRegRealativeId() override; ULONG getMachineType() { return m_machineType; @@ -195,6 +197,8 @@ protected: // const char *prefix = NULL //); + ULONG getRegRealativeIdImpl(const DiaRegToRegRelativeBase &DiaRegToRegRelative); + template TRet callSymbolT( HRESULT(STDMETHODCALLTYPE IDiaSymbol::*method)(TRet *), @@ -222,8 +226,8 @@ public: DiaSession( IDiaSession* session, IDiaSymbol *globalScope ) : m_globalScope( globalScope ), - m_session( session ), - m_globalSymbol( new DiaSymbol( globalScope ) ) + m_globalSymbol( DiaSymbol::fromGlobalScope( globalScope ) ), + m_session( session ) {} SymbolPtr& getSymbolScope() { diff --git a/pykd/localvar.cpp b/pykd/localvar.cpp index 66d563f..1658eb6 100644 --- a/pykd/localvar.cpp +++ b/pykd/localvar.cpp @@ -18,10 +18,189 @@ python::dict getLocals() /////////////////////////////////////////////////////////////////////////////// -python::dict getLocalsByFrame( StackFrame &frame ) +class BuildLocals { - python::dict dct; - return dct; +public: + BuildLocals( ModulePtr mod, const StackFrame &frame ) + : m_mod(mod), m_frame(frame), m_formalGen(0) + { + m_ipRva = static_cast(m_frame.m_instructionOffset - m_mod->getBase()); + } + + void process( SymbolPtr symParent ); + + python::dict &getResult() { + return m_dct; + } + +protected: + void addVar(SymbolPtr symVar); + +private: + ModulePtr m_mod; + const StackFrame &m_frame; + python::dict m_dct; + size_t m_formalGen; + ULONG m_ipRva; +}; + +/////////////////////////////////////////////////////////////////////////////// + +void BuildLocals::process( + SymbolPtr symParent +) +{ + // add vars from current scope + SymbolPtrList symList = symParent->findChildren(SymTagData); + SymbolPtrList::iterator itVar = symList.begin(); + for (; itVar != symList.end(); ++itVar) + addVar(*itVar); + + // find inners scopes + symList = symParent->findChildren(SymTagBlock); + SymbolPtrList::iterator itScope = symList.begin(); + for (; itScope != symList.end(); ++itScope) + { + SymbolPtr scope = *itScope; + ULONG scopeRva = scope->getRva(); + if (scopeRva <= m_ipRva && (scopeRva + scope->getSize()) > m_ipRva) + process(scope); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void BuildLocals::addVar(SymbolPtr symVar) +{ + std::string name; + try + { + name = symVar->getName(); + if (name.empty()) + return; + } + catch (const SymbolException &except) + { + DBG_UNREFERENCED_PARAMETER(except); + return; + } + + if (m_dct.has_key(name)) + { + std::stringstream sstream; + sstream << name << "#" << std::dec << ++m_formalGen; + name = sstream.str(); + } + + BOOST_ASSERT(!m_dct.has_key(name)); + if (m_dct.has_key(name)) + return; + + ULONG64 varAddr; + const LocationType locType = static_cast(symVar->getLocType()); + switch (locType) + { + case LocIsStatic: + varAddr = m_mod->getBase() + symVar->getRva(); + break; + + case LocIsRegRel: + { + RegRealativeId rri; + try + { + rri = static_cast(symVar->getRegRealativeId()); + } + catch (const DbgException &except) + { + DBG_UNREFERENCED_PARAMETER(except); + return; + } + varAddr = m_frame.getValue(rri, symVar->getOffset()); + } + break; + + default: + BOOST_ASSERT(LocIsEnregistered == locType); + return; + } + + TypeInfoPtr typeInfo = TypeInfo::getTypeInfo(symVar); + TypedVarPtr typedVar = TypedVar::getTypedVarByTypeInfo(typeInfo, varAddr); + typedVar->setDataKind( symVar->getDataKind() ); + m_dct[name] = typedVar; +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool IsInDebugRange( + SymbolPtr func, + ULONG ipRva +) +{ + SymbolPtrList lstFuncDebugStart; + SymbolPtrList lstFuncDebugEnd; + + try + { + lstFuncDebugStart = func->findChildren(SymTagFuncDebugStart); + if (1 != lstFuncDebugStart.size()) + { + BOOST_ASSERT(lstFuncDebugStart.empty()); + return true; + } + + lstFuncDebugEnd = func->findChildren(SymTagFuncDebugEnd); + if (1 != lstFuncDebugEnd.size()) + { + BOOST_ASSERT(lstFuncDebugEnd.empty()); + return true; + } + } + catch (const SymbolException &except) + { + DBG_UNREFERENCED_PARAMETER(except); + return true; + } + + return + ((*lstFuncDebugStart.begin())->getRva() <= ipRva) && + ((*lstFuncDebugEnd.begin())->getRva() >= ipRva); +} + +/////////////////////////////////////////////////////////////////////////////// + +python::dict getLocalsByFrame( const StackFrame &frame ) +{ + // query target fuction by $ip register + ModulePtr mod; + SymbolPtr func; + try + { + mod = Module::loadModuleByOffset(frame.m_instructionOffset); + LONG displacemnt; + func = mod->getSymbolByVa(frame.m_instructionOffset, SymTagFunction, &displacemnt ); + } + catch (const DbgException &except) + { + DBG_UNREFERENCED_PARAMETER(except); + return python::dict(); + } + +#ifdef _DEBUG + std::string funcName; + funcName = func->getName(); +#endif // _DEBUG + + if (!IsInDebugRange(func, static_cast(frame.m_instructionOffset - mod->getBase()))) + { + // not in debug range + return python::dict(); + } + + BuildLocals buildLocals(mod, frame); + buildLocals.process(func); + return buildLocals.getResult(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/localvar.h b/pykd/localvar.h index 35ebdcc..f4ae3c2 100644 --- a/pykd/localvar.h +++ b/pykd/localvar.h @@ -8,7 +8,7 @@ namespace pykd { python::dict getLocals(); -python::dict getLocalsByFrame( StackFrame &frame ); +python::dict getLocalsByFrame( const StackFrame &frame ); /////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/module.cpp b/pykd/module.cpp index bb61b9b..3d01402 100644 --- a/pykd/module.cpp +++ b/pykd/module.cpp @@ -220,10 +220,10 @@ std::string Module::getSymbolNameByVa( ULONG64 offset ) sstr << sym->getName(); - if ( displacement > 0 ) + if ( displacement > 0 && displacement ) sstr << '+' << std::hex << displacement; else if ( displacement < 0 ) - sstr << '-' << std::hex << -displacement; + sstr << '-' << std::hex << -displacement; return sstr.str(); } diff --git a/pykd/module.h b/pykd/module.h index e0c8cd5..12d2abf 100644 --- a/pykd/module.h +++ b/pykd/module.h @@ -94,7 +94,7 @@ public: ULONG64 getSymbolSize( const std::string &symName ); - SymbolPtr getSymbolByVa( ULONG64 offset, ULONG symTag, LONG* displacemnt ); + SymbolPtr getSymbolByVa( ULONG64 offset, ULONG symTag, LONG* displacemnt = NULL ); std::string getSymbolNameByVa( ULONG64 offset ); diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index 49ca1f4..24fdecb 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -1,10 +1,14 @@ diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index 796aa7f..b2e8fad 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -295,7 +295,7 @@ BOOST_PYTHON_MODULE( pykd ) .def("offset", &Module::getSymbolOffset, "Return offset of the symbol" ) .def("findSymbol", &Module::getSymbolNameByVa, - "Return symbol name by offset" ) + "Return symbol name by virtual address" ) .def("rva", &Module::getSymbolRva, "Return rva of the symbol" ) .def("sizeof", &Module::getSymbolSize, @@ -382,8 +382,8 @@ BOOST_PYTHON_MODULE( pykd ) "Return a frame's stack offset" ) .def_readonly( "frameNumber", &StackFrame::m_frameNumber, "Return a frame's number" ) - //.def( "getLocals", &StackFrame::getLocals, StackFrame_getLocals( python::args( "ctx" ), - // "Get list of local variables for this stack frame" ) ) + .def( "getLocals", &StackFrame::getLocals, + "Get list of local variables for this stack frame" ) .def( "__str__", &StackFrame::print, "Return stacks frame as a string"); diff --git a/pykd/stkframe.cpp b/pykd/stkframe.cpp index e3b43fb..7e4b19f 100644 --- a/pykd/stkframe.cpp +++ b/pykd/stkframe.cpp @@ -41,27 +41,38 @@ std::string StackFrame::print() const //////////////////////////////////////////////////////////////////////////////// -python::dict StackFrame::getLocals() +python::dict StackFrame::getLocals() const { return getLocalsByFrame( *this ); } +/////////////////////////////////////////////////////////////////////////////// + +ULONG64 StackFrame::getValue(RegRealativeId rri, LONG64 offset /*= 0*/) const +{ + switch (rri) + { + case rriInstructionPointer: return m_instructionOffset + offset; + case rriStackFrame: return m_frameOffset + offset; + case rriStackPointer: return m_stackOffset + offset; + } + + BOOST_ASSERT(!"Unexcepted error"); + throw DbgException(__FUNCTION__ " Unexcepted error" ); +} + //////////////////////////////////////////////////////////////////////////////// python::list getCurrentStack() { - ULONG frameCount = getStackTraceFrameCount(); + std::vector frames; + getStackTrace( frames ); - std::vector frames(frameCount); + python::list frameList; - getStackTrace( &frames[0], frameCount ); - - python::list frameList; - - for ( ULONG i = 0; i < frameCount; ++i ) + for ( ULONG i = 0; i < frames.size(); ++i ) { python::object frameObj( StackFrame( frames.at(i) ) ); - frameList.append( frameObj ); } @@ -72,12 +83,8 @@ python::list getCurrentStack() StackFrame getCurrentStackFrame() { - ULONG frameCount = getStackTraceFrameCount(); - - std::vector frames(frameCount); - - getStackTrace( &frames[0], frameCount ); - + std::vector frames; + getStackTrace( frames ); return frames[0]; } diff --git a/pykd/stkframe.h b/pykd/stkframe.h index 3bd2c22..d9af538 100644 --- a/pykd/stkframe.h +++ b/pykd/stkframe.h @@ -6,6 +6,7 @@ #include "dbgengine.h" #include "context.h" +#include "symengine.h" //////////////////////////////////////////////////////////////////////////////// @@ -18,10 +19,12 @@ class StackFrame public: StackFrame( const STACK_FRAME_DESC& desc ); - python::dict getLocals(); + python::dict getLocals() const; std::string print() const; + ULONG64 getValue(RegRealativeId rri, LONG64 offset = 0) const; + public: ULONG m_frameNumber; diff --git a/pykd/symengine.h b/pykd/symengine.h index 1bb85d6..385453d 100644 --- a/pykd/symengine.h +++ b/pykd/symengine.h @@ -111,6 +111,15 @@ enum BasicType //////////////////////////////////////////////////////////////////////////////// +enum RegRealativeId +{ + rriInstructionPointer, + rriStackFrame, + rriStackPointer +}; + +//////////////////////////////////////////////////////////////////////////////// + class Symbol { public: @@ -144,7 +153,7 @@ public: virtual bool isConstant() = 0; virtual bool isIndirectVirtualBaseClass() = 0; virtual bool isVirtualBaseClass() = 0; - + virtual ULONG getRegRealativeId() = 0; // <- RegRealativeId }; /////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/win/dbgeng.cpp b/pykd/win/dbgeng.cpp index da8bc38..6185322 100644 --- a/pykd/win/dbgeng.cpp +++ b/pykd/win/dbgeng.cpp @@ -673,46 +673,26 @@ ULONG64 getRegInstructionPointer() /////////////////////////////////////////////////////////////////////////////// -ULONG getStackTraceFrameCount() +void getStackTrace(std::vector &frames) { PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - HRESULT hres; - ULONG filledFrames; - - hres = g_dbgEng->control->GetStackTrace( 0, 0, 0, NULL, 0, &filledFrames ); - if ( FAILED( hres ) ) - throw DbgException( "IDebugControl::GetStackTrace failed" ); - - return filledFrames; -} - -/////////////////////////////////////////////////////////////////////////////// - -void getStackTrace( STACK_FRAME_DESC* frames, ULONG frameCount, ULONG* frameReturned ) -{ - PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); - - HRESULT hres; - - ULONG filledFrames; - std::vector stack(frameCount); - - hres = g_dbgEng->control->GetStackTrace( 0, 0, 0, &stack[0], frameCount, &filledFrames); + HRESULT hres; + ULONG filledFrames = 1024; + std::vector dbgFrames(filledFrames); + hres = g_dbgEng->control->GetStackTrace( 0, 0, 0, &dbgFrames[0], filledFrames, &filledFrames); if ( FAILED( hres ) ) throw DbgException( "IDebugControl::GetStackTrace failed" ); + frames.resize(filledFrames); for ( ULONG i = 0; i < filledFrames; ++i ) { - frames[i].number = stack[i].FrameNumber; - frames[i].instructionOffset = stack[i].InstructionOffset; - frames[i].returnOffset = stack[i].ReturnOffset; - frames[i].frameOffset = stack[i].FrameOffset; - frames[i].stackOffset = stack[i].StackOffset; + frames[i].number = dbgFrames[i].FrameNumber; + frames[i].instructionOffset = dbgFrames[i].InstructionOffset; + frames[i].returnOffset = dbgFrames[i].ReturnOffset; + frames[i].frameOffset = dbgFrames[i].FrameOffset; + frames[i].stackOffset = dbgFrames[i].StackOffset; } - - if ( frameReturned ) - *frameReturned = filledFrames; } /////////////////////////////////////////////////////////////////////////////// diff --git a/test/scripts/localstest.py b/test/scripts/localstest.py index 79cc7a6..d955af2 100644 --- a/test/scripts/localstest.py +++ b/test/scripts/localstest.py @@ -3,47 +3,42 @@ import unittest import target import pykd +import testutils + + +def testEnumWindowsProc1Locals(testCase, locals): + testCase.assertNotEqual( 0, locals["hWindow"] ) + DataIsParam = 3 + testCase.assertEqual( DataIsParam, locals["hWindow"].dataKind() ) + + testCase.assertEqual( 6, locals["lParam"] ) + testCase.assertEqual( DataIsParam, locals["lParam"].dataKind() ) + + DataIsLocal = 1 + testCase.assertNotEqual( 0, locals["dwProccessId"] ) + testCase.assertEqual( DataIsLocal, locals["dwProccessId"].dataKind() ) + + DataIsStaticLocal = 2 + testCase.assertNotEqual( 0, locals["staticVar"] ) + testCase.assertEqual( DataIsStaticLocal, locals["staticVar"].dataKind() ) + + testCase.assertEqual( locals["dwProccessId"] + 1, locals["staticVar"] ) class LocalVarsTest(unittest.TestCase): def testLocalVariable(self): """Start new process and test local variables""" + _locProcessId = pykd.startProcess( target.appPath + " -testEnumWindows" ) + with testutils.ContextCallIt( testutils.KillProcess(_locProcessId) ) as killStartedProcess : + pykd.go() # initial breakpoint -> wmain + pykd.go() # wmain -> targetapp!EnumWindowsProc1 - newClnt = pykd.createDbgClient() - newClnt.startProcess( target.appPath + " -testEnumWindows" ) - - newClnt.go() # initial breakpoint -> wmain - newClnt.go() # wmain -> targetapp!EnumWindowsProc1 - # pykd.dprint( "\n" + newClnt.dbgCommand("u") ) - - locals = newClnt.getLocals() - - self.assertNotEqual( 0, locals["hWindow"] ) - self.assertEqual( pykd.DataIsParam, locals["hWindow"].dataKind() ) - - self.assertEqual( 6, locals["lParam"] ) - self.assertEqual( pykd.DataIsParam, locals["lParam"].dataKind() ) - - self.assertNotEqual( 0, locals["dwProccessId"] ) - self.assertEqual( pykd.DataIsLocal, locals["dwProccessId"].dataKind() ) - - self.assertNotEqual( 0, locals["staticVar"] ) - self.assertEqual( pykd.DataIsStaticLocal, locals["staticVar"].dataKind() ) - - self.assertEqual( locals["dwProccessId"] + 1, locals["staticVar"] ) - - newClnt.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1 - - # get local variables from previous stack frame - prevLocals = newClnt.getCurrentStack()[1].getLocals() - - 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 ) - locValues = locals.values() - self.assertTrue( locValues[0] == 7 or locValues[1] == 7 ) + testEnumWindowsProc1Locals(self, pykd.getLocals()) + pykd.go() # targetapp!EnumWindowsProc1 -> targetapp!functionCalledFromEnumWindowsProc1 + testEnumWindowsProc1Locals(self, pykd.getCurrentStack()[1].getLocals()) + pykd.go() # targetapp!EnumWindowsProc1 -> targetapp!EnumWindowsProc2 + locals = pykd.getLocals() + self.assertEqual( len(locals), 2 ) + locValues = locals.values() + self.assertTrue( locValues[0] == 7 or locValues[1] == 7 ) diff --git a/test/scripts/moduletest.py b/test/scripts/moduletest.py index a99960c..e77b060 100644 --- a/test/scripts/moduletest.py +++ b/test/scripts/moduletest.py @@ -61,6 +61,6 @@ class ModuleTest( unittest.TestCase ): self.assertTrue( re.search('targetapp\\.cpp', fileName ) ) self.assertEqual( 2, displacement ) fileName, lineNo, displacement = pykd.getSourceLine() - self.assertEqual( 636, lineNo ) + self.assertEqual( 616, lineNo ) diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index 3ef7b56..f32efe2 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -19,6 +19,7 @@ import moduletest import typeinfo import typedvar import regtest +import localstest class StartProcessWithoutParamsTest(unittest.TestCase): def testStart(self): @@ -30,13 +31,13 @@ class StartProcessWithoutParamsTest(unittest.TestCase): class TerminateProcessTest(unittest.TestCase): def testKill(self): pykd.killProcess( target.processId ) + pykd.detachProcess( target.processId ) def getTestSuite( singleName = "" ): if singleName == "": return unittest.TestSuite( [ unittest.TestLoader().loadTestsFromTestCase( StartProcessWithoutParamsTest ), - unittest.TestLoader().loadTestsFromTestCase( target.TargetTest ), # *** Test without start/kill new processes unittest.TestLoader().loadTestsFromTestCase( intbase.IntBaseTest ), unittest.TestLoader().loadTestsFromTestCase( moduletest.ModuleTest ), @@ -44,8 +45,10 @@ def getTestSuite( singleName = "" ): unittest.TestLoader().loadTestsFromTestCase( typeinfo.TypeInfoTest ), unittest.TestLoader().loadTestsFromTestCase( typedvar.TypedVarTest ), unittest.TestLoader().loadTestsFromTestCase( regtest.CpuRegTest ), - # *** + # ^^^ unittest.TestLoader().loadTestsFromTestCase( TerminateProcessTest ), + + unittest.TestLoader().loadTestsFromTestCase( localstest.LocalVarsTest ), ] ) else: return unittest.TestSuite( unittest.TestLoader().loadTestsFromName( singleName ) ) @@ -53,7 +56,7 @@ def getTestSuite( singleName = "" ): if __name__ == "__main__": print "\nTesting PyKd ver. " + pykd.version - + target.appPath = sys.argv[1] target.moduleName = os.path.splitext(os.path.basename(target.appPath))[0] #print "Test module: %s" % target.appPath diff --git a/test/scripts/target.py b/test/scripts/target.py index 4befd70..a464cfe 100644 --- a/test/scripts/target.py +++ b/test/scripts/target.py @@ -10,13 +10,6 @@ module = None moduleName = None processId = None -class TargetTest( unittest.TestCase ): - - def testStartStop(self): - _locProcessId = pykd.startProcess( appPath ) - pykd.killProcess( _locProcessId ) - - #module = None #moduleName = None diff --git a/test/scripts/testutils.py b/test/scripts/testutils.py index e07d47e..842520b 100644 --- a/test/scripts/testutils.py +++ b/test/scripts/testutils.py @@ -14,3 +14,12 @@ class ContextCallIt: try: self.callIt() except: pass +class KillProcess: + """Kill process""" + def __init__(self, processId): + self.processId = processId + + def __call__(self): + pykd.killProcess( self.processId ) + pykd.detachProcess( self.processId ) +