[0.2.x] added : loadDump, isKernelDebugging, isDumpAnalyzing routines

git-svn-id: https://pykd.svn.codeplex.com/svn@78810 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\kernelnet_cp 2012-08-13 11:34:26 +00:00 committed by Mikhail I. Izmestev
parent ced206cc0a
commit 02228e6714
13 changed files with 784 additions and 830 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,9 @@
#pragma once #pragma once
#include <map> #include <map>
#include <CvConst.h> //#include <CvConst.h>
#include "context.h" #include "context.h"
#include "dbgobj.h"
#include "dbgexcept.h" #include "dbgexcept.h"
namespace pykd { namespace pykd {
@ -24,72 +23,77 @@ std::string processorToStr(ULONG processorMode);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
class ThreadContext : private DbgObject class ThreadContext
{ {
public: //public:
typedef std::map<ULONG, ULONG64> RegValues; //typedef std::map<ULONG, ULONG64> RegValues;
ThreadContext( IDebugClient4 *client ); //ThreadContext();
static ContextPtr getWow64Context( IDebugClient4 *client ); ////static ContextPtr getWow64Context();
// get register value by ID //// get register value by ID
ULONG64 getValue(ULONG cvRegId) const; //ULONG64 getValue(ULONG cvRegId) const;
ULONG64 getValueByName( const std::string &regName ) const; //ULONG64 getValueByName( const std::string &regName ) const;
bool getValueNoThrow(ULONG cvRegId, ULONG64 &val) const; //bool getValueNoThrow(ULONG cvRegId, ULONG64 &val) const;
// get @$ip pseudo register //// get @$ip pseudo register
ULONG64 getIp() const; //ULONG64 getIp() const;
// get @$retreg pseudo register //// get @$retreg pseudo register
ULONG64 getRetReg() const; //ULONG64 getRetReg() const;
// get @$csp pseudo register //// get @$csp pseudo register
ULONG64 getSp() const; //ULONG64 getSp() const;
// enumerate register values: tuple<CV_REG_ID, VALUE> //// enumerate register values: tuple<CV_REG_ID, VALUE>
ULONG getCount() const { //ULONG getCount() const {
return static_cast<ULONG>( m_regValues.size() ); // return static_cast<ULONG>( m_regValues.size() );
} //}
python::object getByIndex(ULONG ind) const; //python::object getByIndex(ULONG ind) const;
// get processor type //// get processor type
std::string getProcessorType() const { //std::string getProcessorType() const {
return pykd::processorToStr(m_processorType); // return pykd::processorToStr(m_processorType);
} //}
ContextPtr forkByStackFrame(const StackFrame &stkFrmae) const; //ContextPtr forkByStackFrame(const StackFrame &stkFrmae) const;
std::string print() const; //std::string print() const;
protected: //protected:
ThreadContext( //ThreadContext(
IDebugClient4 *client, // ULONG processorType
ULONG processorType //);
);
void queryRegisters( //void queryRegisters(
const CvRegName *regs, // const CvRegName *regs,
ULONG countOfRegs // ULONG countOfRegs
); //);
// query i386 registers //// query i386 registers
void getI386Context(); //void getI386Context();
// query AMD64 registers //// query AMD64 registers
void getAmd64Context(); //void getAmd64Context();
// 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; //void __declspec(noreturn) throwUnsupportedProcessor(PCSTR szFunction) const;
private: //private:
RegValues m_regValues; //RegValues m_regValues;
ULONG m_processorType; //ULONG m_processorType;
}; };
////////////////////////////////////////////////////////////////////////////////
//
//ContextPtr getThreadContext();
//
//python::dict getLocals( ContextPtr ctx = getThreadContext() );
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
} }

View File

@ -10,6 +10,11 @@ ULONG startProcess( const std::wstring &processName );
void detachProcess( ULONG processId = -1); void detachProcess( ULONG processId = -1);
void terminateProcess( ULONG processId = -1); void terminateProcess( ULONG processId = -1);
void loadDump( const std::wstring &fileName );
bool isDumpAnalyzing();
bool isKernelDebugging();
void debugGo(); void debugGo();
// system properties // system properties

View File

@ -1,214 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
#include <stdafx.h>
#include "dbgclient.h"
////////////////////////////////////////////////////////////////////////////////
namespace pykd {
////////////////////////////////////////////////////////////////////////////////
namespace impl {
////////////////////////////////////////////////////////////////////////////////
struct addLocals {
python::dict &m_locals;
const ModulePtr m_module;
ULONG m_rva;
ContextPtr m_ctx;
IDebugClient4 *m_client;
ULONG m_formalNameCounter;
CComPtr< IDebugDataSpaces4 > m_dataSpaces;
void append(pyDia::SymbolPtr symParent);
private:
void appendVar(pyDia::SymbolPtr symData);
void generateUniqueName(std::string &varName);
TypedVarPtr getTypeVarByOffset(
pyDia::SymbolPtr symData,
ULONG64 varOffset
);
};
////////////////////////////////////////////////////////////////////////////////
struct Exception : public DbgException {
Exception() : DbgException("build list of locals: internal exception")
{
}
};
////////////////////////////////////////////////////////////////////////////////
void addLocals::append(pyDia::SymbolPtr symParent)
{
// add all local variables
pyDia::SymbolPtrList lstLocals = symParent->findChildrenImpl(SymTagData);
pyDia::SymbolPtrList::iterator it = lstLocals.begin();
while (it != lstLocals.end())
{
try
{
appendVar(*it);
}
catch (const DbgException &e)
{
DBG_UNREFERENCED_LOCAL_VARIABLE(e);
}
++it;
}
// process all scopes
pyDia::SymbolPtrList lstScopes = symParent->findChildrenImpl(SymTagBlock);
it = lstScopes.begin();
while ( it != lstScopes.end() )
{
const ULONG scopeRva = (*it)->getRva();
if ( (scopeRva <= m_rva) && (scopeRva + (*it)->getSize() > m_rva) )
append(*it);
++it;
}
}
////////////////////////////////////////////////////////////////////////////////
void addLocals::appendVar(pyDia::SymbolPtr symData)
{
TypedVarPtr typedVar;
std::string varName = symData->getName();
// check name for unique. f.e. may be may be somewhat parameters
// with name "__formal"
generateUniqueName(varName);
switch (symData->getLocType())
{
case LocIsStatic:
typedVar =
getTypeVarByOffset(
symData,
m_module->getBase() + symData->getRva() );
break;
case LocIsRegRel:
typedVar =
getTypeVarByOffset(
symData,
m_ctx->getValue( symData->getRegisterId() )+ symData->getOffset() );
break;
case LocIsEnregistered: // FIXME
default:
throw ImplementException(__FILE__,__LINE__,"Fix ME");
}
typedVar->setDataKind( symData->getDataKind() );
m_locals[varName] = typedVar;
}
////////////////////////////////////////////////////////////////////////////////
void addLocals::generateUniqueName(std::string &varName)
{
if ( !m_locals.has_key(varName) )
return;
std::string origVarName = varName;
while ( m_locals.has_key(varName) )
{
std::stringstream sstream;
sstream << origVarName << ++m_formalNameCounter;
varName = sstream.str();
}
}
////////////////////////////////////////////////////////////////////////////////
TypedVarPtr addLocals::getTypeVarByOffset(
pyDia::SymbolPtr symData,
ULONG64 varOffset
)
{
pyDia::SymbolPtr symType = symData->getType();
TypeInfoPtr typeInfo = TypeInfo::getTypeInfo( symType );
return TypedVar::getTypedVar( m_client, typeInfo, VarDataMemory::factory(m_dataSpaces, varOffset) );
}
////////////////////////////////////////////////////////////////////////////////
static ULONG getUnnamedChildRva(
pyDia::SymbolPtr symParent,
ULONG SymTag
)
{
pyDia::SymbolPtrList childs = symParent->findChildrenImpl(SymTag);
if (childs.empty())
throw Exception();
return (*childs.begin())->getRva();
}
////////////////////////////////////////////////////////////////////////////////
static bool isOutOfDebugRange(
ULONG rva,
pyDia::SymbolPtr symFunc
)
{
try
{
if (rva < getUnnamedChildRva(symFunc, SymTagFuncDebugStart))
return true;
if (rva > getUnnamedChildRva(symFunc, SymTagFuncDebugEnd))
return true;
}
catch (const DbgException &)
{
}
return false;
}
}
////////////////////////////////////////////////////////////////////////////////
python::dict DebugClient::getLocals(ContextPtr ctx OPTIONAL)
{
if (!ctx)
ctx = getThreadContext();
const ULONG64 instrPtr = ctx->getIp();
ModulePtr mod = loadModuleByOffset( instrPtr );
const ULONG rva = static_cast<ULONG>( instrPtr - mod->getBase() );
pyDia::GlobalScopePtr globScope = mod->getDia();
LONG funcDispl;
pyDia::SymbolPtr symFunc =
globScope->findByRvaImpl(rva, SymTagFunction, funcDispl);
if (impl::isOutOfDebugRange(rva, symFunc))
return python::dict(); // out of function debug range
python::dict locals;
impl::addLocals Locals = { locals, mod, rva, ctx, m_client, 0, m_dataSpaces };
Locals.append(symFunc);
return locals;
}
////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////

30
pykd/localvar.cpp Normal file
View File

@ -0,0 +1,30 @@
#include <stdafx.h>
#include "localvar.h"
#include "module.h"
#include "symengine.h"
#include "dbgengine.h"
#include "typedvar.h"
namespace pykd {
///////////////////////////////////////////////////////////////////////////////
python::dict getLocals()
{
return getLocalsByFrame( getCurrentStackFrame() );
}
///////////////////////////////////////////////////////////////////////////////
python::dict getLocalsByFrame( StackFrame &frame )
{
python::dict dct;
return dct;
}
///////////////////////////////////////////////////////////////////////////////
} //end pykd namespace

View File

@ -193,4 +193,16 @@ python::list Module::getTypedVarListByTypeName( ULONG64 listHeadAddress, const s
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
SymbolPtr Module::getSymbolByVa( ULONG64 offset, ULONG symTag, LONG* displacment )
{
offset = addr64(offset);
if ( offset < m_base || offset > getEnd() )
throw DbgException( "address is out of the module space" );
return getSymSession()->findByRva( (ULONG)(offset - m_base ), symTag, displacment );
}
///////////////////////////////////////////////////////////////////////////////////
}; // end of namespace pykd }; // end of namespace pykd

View File

@ -93,6 +93,8 @@ public:
ULONG64 getSymbolSize( const std::string &symName ); ULONG64 getSymbolSize( const std::string &symName );
SymbolPtr getSymbolByVa( ULONG64 offset, ULONG symTag, LONG* displacemnt );
std::string print(); std::string print();
private: private:

View File

@ -369,6 +369,10 @@
RelativePath=".\disasm.cpp" RelativePath=".\disasm.cpp"
> >
</File> </File>
<File
RelativePath=".\localvar.cpp"
>
</File>
<File <File
RelativePath=".\module.cpp" RelativePath=".\module.cpp"
> >
@ -467,6 +471,10 @@
RelativePath=".\disasmengine.h" RelativePath=".\disasmengine.h"
> >
</File> </File>
<File
RelativePath=".\localvar.h"
>
</File>
<File <File
RelativePath=".\module.h" RelativePath=".\module.h"
> >

View File

@ -18,6 +18,7 @@
#include "cpureg.h" #include "cpureg.h"
#include "disasm.h" #include "disasm.h"
#include "stkframe.h" #include "stkframe.h"
#include "localvar.h"
using namespace pykd; using namespace pykd;
@ -44,8 +45,6 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignDWords_, loadSignDWords, 2, 3 );
BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignQWords_, loadSignQWords, 2, 3 ); BOOST_PYTHON_FUNCTION_OVERLOADS( loadSignQWords_, loadSignQWords, 2, 3 );
BOOST_PYTHON_FUNCTION_OVERLOADS( compareMemory_, compareMemory, 3, 4 ); BOOST_PYTHON_FUNCTION_OVERLOADS( compareMemory_, compareMemory, 3, 4 );
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( StackFrame_getLocals, StackFrame::getLocals, 0, 1 );
BOOST_PYTHON_MODULE( pykd ) BOOST_PYTHON_MODULE( pykd )
{ {
python::scope().attr("version") = pykdVersion; python::scope().attr("version") = pykdVersion;
@ -58,6 +57,12 @@ BOOST_PYTHON_MODULE( pykd )
"Stop process debugging"); "Stop process debugging");
python::def( "killProcess", &terminateProcess, python::def( "killProcess", &terminateProcess,
"Stop debugging and terminate current process" ); "Stop debugging and terminate current process" );
python::def( "loadDump", &loadDump,
"Load crash dump");
python::def( "isDumpAnalyzing", &isDumpAnalyzing,
"Check if it is a dump analyzing ( not living debuggee )" );
python::def( "isKernelDebugging", &isKernelDebugging,
"Check if kernel dubugging is running" );
python::def( "go", &debugGo, python::def( "go", &debugGo,
"Go debugging" ); "Go debugging" );
@ -162,7 +167,7 @@ BOOST_PYTHON_MODULE( pykd )
// stack and local variables // stack and local variables
python::def( "getCurrentStack", &getCurrentStack, python::def( "getCurrentStack", &getCurrentStack,
"Return a current stack as a list of stackFrame objects" ); "Return a current stack as a list of stackFrame objects" );
python::def( "getLocals", &getLocals, "Get list of local variables" );
python::class_<intBase>( "intBase", "intBase", python::no_init ) python::class_<intBase>( "intBase", "intBase", python::no_init )
.def( python::init<python::object&>() ) .def( python::init<python::object&>() )
@ -318,6 +323,33 @@ BOOST_PYTHON_MODULE( pykd )
.def( "__str__", &StackFrame::print, .def( "__str__", &StackFrame::print,
"Return stacks frame as a string"); "Return stacks frame as a string");
//python::class_<ThreadContext, ContextPtr>(
// "Context", "Context of thread (register values)", python::no_init )
// .def( "ip", &ThreadContext::getIp,
// "Get instruction pointer register" )
// .def( "retreg", &ThreadContext::getRetReg,
// "Get primary return value register" )
// .def( "csp", &ThreadContext::getSp,
// "Get current stack pointer" )
// .def( "get", &ThreadContext::getValue,
// "Get register value by ID (CV_REG_XXX)" )
// .def( "get", &ThreadContext::getValueByName,
// "Get register value by name" )
// .def( "processorType", &ThreadContext::getProcessorType,
// "Get processor ThreadContext as string")
// .def( "fork", &ThreadContext::forkByStackFrame,
// "Create new thread context by stackFrame")
// .def("__len__", &ThreadContext::getCount,
// "Return count of registers")
// .def("__getitem__", &ThreadContext::getByIndex,
// "Return tuple<ID, NAME, VALUE> by index")
// .def("__getitem__", &ThreadContext::getValueByName,
// "Return register value by name" )
// .def("__getattr__", &ThreadContext::getValueByName,
// "Return register value as a attribute of the Context" )
// .def("__str__", &ThreadContext::print,
// "Return context as a string" );
python::class_<Disasm>("disasm", "Class disassemble a processor instructions" ) python::class_<Disasm>("disasm", "Class disassemble a processor instructions" )
.def( python::init<>( "constructor" ) ) .def( python::init<>( "constructor" ) )
.def( python::init<ULONG64>( boost::python::args("offset"), "constructor" ) ) .def( python::init<ULONG64>( boost::python::args("offset"), "constructor" ) )

View File

@ -5,6 +5,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "stkframe.h" #include "stkframe.h"
#include "dbgengine.h" #include "dbgengine.h"
#include "localvar.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -40,6 +41,13 @@ std::string StackFrame::print() const
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
python::dict StackFrame::getLocals()
{
return getLocalsByFrame( *this );
}
////////////////////////////////////////////////////////////////////////////////
python::list getCurrentStack() python::list getCurrentStack()
{ {
ULONG frameCount = getStackTraceFrameCount(); ULONG frameCount = getStackTraceFrameCount();
@ -62,6 +70,19 @@ python::list getCurrentStack()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
StackFrame getCurrentStackFrame()
{
ULONG frameCount = getStackTraceFrameCount();
std::vector<STACK_FRAME_DESC> frames(frameCount);
getStackTrace( &frames[0], frameCount );
return frames[0];
}
///////////////////////////////////////////////////////////////////////////////
} // namespace pykd } // namespace pykd

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "dbgengine.h" #include "dbgengine.h"
#include "context.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -17,7 +18,7 @@ class StackFrame
public: public:
StackFrame( const STACK_FRAME_DESC& desc ); StackFrame( const STACK_FRAME_DESC& desc );
// python::dict getLocals(ContextPtr ctx = ContextPtr()); python::dict getLocals();
std::string print() const; std::string print() const;
@ -33,6 +34,8 @@ public:
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
StackFrame getCurrentStackFrame();
python::list getCurrentStack(); python::list getCurrentStack();
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -91,6 +91,58 @@ void terminateProcess( ULONG processId )
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
void loadDump( const std::wstring &fileName )
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
hres = g_dbgEng->client->OpenDumpFileWide( fileName.c_str(), NULL );
if ( FAILED( hres ) )
throw DbgException( "IDebugClient4::OpenDumpFileWide failed" );
hres = g_dbgEng->control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE);
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::WaitForEvent failed" );
}
///////////////////////////////////////////////////////////////////////////////////
bool isDumpAnalyzing()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG debugClass, debugQualifier;
hres = g_dbgEng->control->GetDebuggeeType( &debugClass, &debugQualifier );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetDebuggeeType failed" );
return debugQualifier >= DEBUG_DUMP_SMALL;
}
///////////////////////////////////////////////////////////////////////////////////
bool isKernelDebugging()
{
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );
HRESULT hres;
ULONG debugClass, debugQualifier;
hres = g_dbgEng->control->GetDebuggeeType( &debugClass, &debugQualifier );
if ( FAILED( hres ) )
throw DbgException( "IDebugControl::GetDebuggeeType failed" );
return debugClass == DEBUG_CLASS_KERNEL;
}
///////////////////////////////////////////////////////////////////////////////////
void debugGo() void debugGo()
{ {
PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate );

View File

@ -48,9 +48,7 @@ if __name__ == "__main__":
target.module.reload(); target.module.reload();
pykd.go() pykd.go()
unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run(getTestSuite( "typedvar.TypedVarTest.testPrint" ) )
unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( getTestSuite() ) unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run( getTestSuite() )
pykd.killProcess( processId ) pykd.killProcess( processId )