mirror of
https://github.com/ivellioscolin/pykd.git
synced 2025-04-20 03:23:23 +08:00
[0.2.x] + locals
git-svn-id: https://pykd.svn.codeplex.com/svn@79357 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
parent
71b3f0df9e
commit
77b1eee2f4
@ -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<STACK_FRAME_DESC> &frames);
|
||||
|
||||
//breakpoints
|
||||
ULONG breakPointSet( ULONG64 offset, bool hardware = false, ULONG size = 0, ULONG accessType = 0 );
|
||||
|
@ -8,6 +8,36 @@ namespace pykd {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const struct DiaRegToRegRelativeAmd64 : DiaRegToRegRelativeBase
|
||||
{
|
||||
typedef std::map<ULONG, ULONG> 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<ULONG, ULONG> 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() ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -19,6 +19,8 @@ typedef CComPtr< IDiaEnumLineNumbers > DiaEnumLineNumbersPtr;
|
||||
typedef CComPtr< IDiaLineNumber> DiaLineNumberPtr;
|
||||
typedef CComPtr< IDiaSourceFile > DiaSourceFilePtr;
|
||||
|
||||
typedef std::map<ULONG, ULONG> 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 <typename TRet>
|
||||
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() {
|
||||
|
@ -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<ULONG>(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<LocationType>(symVar->getLocType());
|
||||
switch (locType)
|
||||
{
|
||||
case LocIsStatic:
|
||||
varAddr = m_mod->getBase() + symVar->getRva();
|
||||
break;
|
||||
|
||||
case LocIsRegRel:
|
||||
{
|
||||
RegRealativeId rri;
|
||||
try
|
||||
{
|
||||
rri = static_cast<RegRealativeId>(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<ULONG>(frame.m_instructionOffset - mod->getBase())))
|
||||
{
|
||||
// not in debug range
|
||||
return python::dict();
|
||||
}
|
||||
|
||||
BuildLocals buildLocals(mod, frame);
|
||||
buildLocals.process(func);
|
||||
return buildLocals.getResult();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -8,7 +8,7 @@ namespace pykd {
|
||||
|
||||
python::dict getLocals();
|
||||
|
||||
python::dict getLocalsByFrame( StackFrame &frame );
|
||||
python::dict getLocalsByFrame( const StackFrame &frame );
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -220,7 +220,7 @@ 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;
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -1,10 +1,14 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Version="9.00"
|
||||
Name="pykd"
|
||||
ProjectGUID="{FE961905-666F-4908-A212-961465F46F13}"
|
||||
RootNamespace="pykd"
|
||||
SccProjectName="$/pykd/branch/0.2.x/pykd"
|
||||
SccAuxPath="https://tfs.codeplex.com/tfs/TFS08"
|
||||
SccLocalPath="."
|
||||
SccProvider="{4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="0"
|
||||
>
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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<STACK_FRAME_DESC> frames;
|
||||
getStackTrace( frames );
|
||||
|
||||
std::vector<STACK_FRAME_DESC> 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<STACK_FRAME_DESC> frames(frameCount);
|
||||
|
||||
getStackTrace( &frames[0], frameCount );
|
||||
|
||||
std::vector<STACK_FRAME_DESC> frames;
|
||||
getStackTrace( frames );
|
||||
return frames[0];
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -673,46 +673,26 @@ ULONG64 getRegInstructionPointer()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ULONG getStackTraceFrameCount()
|
||||
void getStackTrace(std::vector<STACK_FRAME_DESC> &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<DEBUG_STACK_FRAME> stack(frameCount);
|
||||
|
||||
hres = g_dbgEng->control->GetStackTrace( 0, 0, 0, &stack[0], frameCount, &filledFrames);
|
||||
HRESULT hres;
|
||||
ULONG filledFrames = 1024;
|
||||
std::vector<DEBUG_STACK_FRAME> 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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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 )
|
||||
|
@ -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 )
|
||||
|
||||
|
||||
|
@ -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 ) )
|
||||
|
@ -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
|
||||
|
@ -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 )
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user