From d47d70d71a8cf5bacf620d89844b24af97e97c46 Mon Sep 17 00:00:00 2001 From: ussrhero Date: Mon, 29 Apr 2019 22:07:50 +0300 Subject: [PATCH] fixed: #29 (support for inline in stack) --- pykd/pycpucontext.cpp | 21 +++++++++++++++++++-- pykd/pycpucontext.h | 4 +++- pykd/pymod.cpp | 15 ++++++++++++--- test/scripts/stacktest.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/pykd/pycpucontext.cpp b/pykd/pycpucontext.cpp index 516ddc1..f93cfef 100644 --- a/pykd/pycpucontext.cpp +++ b/pykd/pycpucontext.cpp @@ -69,14 +69,14 @@ std::wstring getRegisterName(unsigned long index) /////////////////////////////////////////////////////////////////////////////// -python::list getCurrentStack() +python::list getStack(bool inlineFrames) { kdlib::StackPtr stack; unsigned long numberFrames; do { AutoRestorePyState pystate; - stack = kdlib::getStack(); + stack = kdlib::getStack(inlineFrames); numberFrames = stack->getFrameCount(); } while(false); @@ -242,6 +242,23 @@ python::dict StackFrameAdapter::getLocalsDict(kdlib::StackFramePtr& frame) /////////////////////////////////////////////////////////////////////////////// +python::tuple StackFrameAdapter::findSymbol(kdlib::StackFramePtr& frame) +{ + kdlib::MEMDISPLACEMENT displacement; + std::wstring symbolName; + std::wstring moduleName; + + { + AutoRestorePyState pystate; + symbolName = frame->findSymbol(displacement); + moduleName = kdlib::getModuleName(kdlib::findModuleBase(frame->getIP())); + } + + return python::make_tuple(moduleName, symbolName, displacement); +} + +/////////////////////////////////////////////////////////////////////////////// + python::tuple CPUContextAdapter::getRegisterByIndex(unsigned long index) { diff --git a/pykd/pycpucontext.h b/pykd/pycpucontext.h index 0fb60bd..63fbd41 100644 --- a/pykd/pycpucontext.h +++ b/pykd/pycpucontext.h @@ -70,6 +70,8 @@ public: AutoRestorePyState pystate; frame->switchTo(); } + + static python::tuple findSymbol(kdlib::StackFramePtr& frame); }; ///////////////////////////////////////////////////////////////////////////////// @@ -157,7 +159,7 @@ inline void switchProcessorMode() { kdlib::switchCPUMode(); } -python::list getCurrentStack(); +python::list getStack(bool inlineFrames = false); inline kdlib::StackFramePtr getCurrentFrame() { AutoRestorePyState pystate; diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index 5171759..6cd189c 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -78,6 +78,7 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( getSourceFile_, pykd::getSourceFile, 0, 1 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getSourceFileFromSrcSrv_, pykd::getSourceFileFromSrcSrv, 0, 1 ); BOOST_PYTHON_FUNCTION_OVERLOADS( getSourceLine_, pykd::getSourceLine, 0, 1 ); BOOST_PYTHON_FUNCTION_OVERLOADS( findSymbol_, pykd::findSymbol, 1, 2 ); +BOOST_PYTHON_FUNCTION_OVERLOADS( getStack_, pykd::getStack, 0, 1); BOOST_PYTHON_FUNCTION_OVERLOADS( getProcessOffset_, pykd::getProcessOffset, 0, 1); BOOST_PYTHON_FUNCTION_OVERLOADS( getProcessSystemId_, pykd::getProcessSystemId, 0, 1); @@ -482,8 +483,8 @@ void pykd_init() "Switch processor mode ( X86 <-> X64 )" ); // stack and local variables - python::def( "getStack", pykd::getCurrentStack, - "Return a current stack as a list of stackFrame objects" ); + python::def( "getStack", pykd::getStack, getStack_(python::args("inlineFrames"), + "Return a current stack as a list of stackFrame objects" ) ); python::def( "getFrame", pykd::getCurrentFrame, "Return a current stack frame" ); python::def("getFrameNumber", pykd::getCurrentFrameNumber, @@ -1116,7 +1117,15 @@ void pykd_init() "return the function's local variable by it's name") .def( "switchTo", StackFrameAdapter::switchTo, "Make this frame a current") - .def( "__str__", StackFrameAdapter::print ); + //.def( "isInline", StackFrameAdapter::isInline, + // "this virtual frame of inlined function" ) + //.def( "getFunciton", StackFrameAdapter::getFunction, + // "return instance of the typedVar class representing function") + .def( "findSymbol", StackFrameAdapter::findSymbol, + "return symbol for frame's instruction pointer") + //.def( "getSourceLine", StackFrameAdapter::getSourceLine, + // "return source line for stack frame's function" ) + .def( "__str__", StackFrameAdapter::print ); python::class_("cpu", "class for CPU context representation" ) //.def("__init__", python::make_constructor(CPUContextAdapter::getCPUContext) ) diff --git a/test/scripts/stacktest.py b/test/scripts/stacktest.py index 6c013e2..03cddf7 100644 --- a/test/scripts/stacktest.py +++ b/test/scripts/stacktest.py @@ -1,4 +1,7 @@ import unittest +import os +import sys + import pykd import target @@ -55,3 +58,34 @@ class StackTest(unittest.TestCase): self.assertEqual(0, len(topFrame.getLocals())) +class InlineStackTest(unittest.TestCase): + + def setUp(self): + dumpDir = os.path.join( os.path.dirname(sys.argv[0]), r"..\..\kdlibcpp\kdlib\tests\dumps\targetapp_stacktest_x64_release") + dump_file = os.path.join( dumpDir, "targetapp_stacktest_x64_release.cab" ) + self.symbolPath = pykd.getSymbolPath() + symbolPath = self.symbolPath + ";" + dumpDir + pykd.setSymbolPath(symbolPath) + self.dump_id = pykd.loadDump( dump_file ) + + def tearDown(self): + pykd.closeDump( self.dump_id ) + pykd.setSymbolPath(self.symbolPath) + + def testGetStack(self): + + expectedStack = [ + 'targetapp!stackTestClass::stackMethod', + 'targetapp!stackTestRun2', + 'targetapp!stackTestRun1', + 'targetapp!stackTestRun'] + + realStack = [] + for frame in pykd.getStack(inlineFrames = True): + moduleName, symbolName, disp = frame.findSymbol() + realStack.append( "%s!%s" % ( moduleName, symbolName ) ) + + self.assertEqual( expectedStack, realStack[0:4]) + + +