From d922dbe8daef81fbf9a991e58eca2f3b8d2a674b Mon Sep 17 00:00:00 2001 From: "SND\\kernelnet_cp" Date: Wed, 30 Apr 2014 16:42:19 +0000 Subject: [PATCH] [0.3.x] refactored : stkwalk script git-svn-id: https://pykd.svn.codeplex.com/svn@88179 9b283d60-5439-405e-af05-b73fd8c4d996 --- snippets/stkwalk.py | 342 +++++++++++++++++++++++--------------------- 1 file changed, 179 insertions(+), 163 deletions(-) diff --git a/snippets/stkwalk.py b/snippets/stkwalk.py index cf70970..95b6696 100644 --- a/snippets/stkwalk.py +++ b/snippets/stkwalk.py @@ -1,4 +1,5 @@ +import pykd from pykd import * from optparse import OptionParser from fnmatch import fnmatch @@ -6,6 +7,21 @@ import traceback import sys nt = None +EPROCESS = None +ETHREAD = None + +def setupGlobalObject(): + + global nt, EPROCESS, ETHREAD + + try: + nt = module("nt") + EPROCESS = nt.type("_EPROCESS") + ETHREAD = nt.type("_ETHREAD") + except DbgException: + dprintln("check symbol paths") + + class PrintOptions: def __init__(self): @@ -15,179 +31,167 @@ class PrintOptions: self.showIP = True self.showSP = True self.showUnique = False - -def applayThreadFilter(thread,threadFilter,moduleFilter,funcFilter,printopt,stackHashes): - - filterMatch = False - - if not moduleFilter and not funcFilter and not threadFilter: - if printopt.showUnique == False: - return True - else: - filterMatch = True - - if threadFilter and threadFilter( thread.Tcb, thread.Cid.UniqueThread ): - if printopt.showUnique == False: - return True - else: - filterMatch = True - - try: - - setImplicitThread(thread) - - stk = getStack() - - strStack = "" - - for frame in stk: - m = module( frame.instructionOffset ) - if filterMatch == False and moduleFilter and moduleFilter( m, m.name() ): - filterMatch = True - if printopt.showUnique == False: - return True - - sym = m.findSymbol( frame.instructionOffset, showDisplacement = False ) - if filterMatch == False and funcFilter and funcFilter( sym ): - filterMatch = True - if printopt.showUnique == False: - return True - - if printopt.showUnique == True: - strStack += sym - - if is64bitSystem(): - processorMode = getProcessorMode() - try: - setProcessorMode("X86") - dbgCommand( ".reload /user" ) - stk = getStackWow64() - for frame in stk: - m = module( frame.instructionOffset ) - if filterMatch == False and moduleFilter and moduleFilter( m, m.name() ): - filterMatch = True - if printopt.showUnique == False: - return True - - sym = m.findSymbol( frame.instructionOffset, showDisplacement = False ) - if filterMatch == False and funcFilter and funcFilter( sym ): - filterMatch = True - if printopt.showUnique == False: - return True - - if printopt.showUnique == True: - strStack += sym - except BaseException: - pass - setProcessorMode(processorMode) - - if printopt.showUnique == False or filterMatch == False: - return filterMatch - - hashStack = hash( strStack ) - if hashStack in stackHashes: - return False - - stackHashes.add( hashStack ) - - return True - - except BaseException: - pass - - return False + self.combineWow64 = True + self.showCpu = True def printFrame(frame, printopt): + + str = "" + + if printopt.showCpu: + str += frame.cpuType + "\t" + if printopt.showIP: - dprint( "%016x\t" % frame.instructionOffset ) + str += "%016x\t" % frame.instructionOffset if printopt.showSP: - dprint( "%016x\t" % frame.stackOffset ) + str += "%016x\t" % frame.stackOffset - dprintln( findSymbol( frame.instructionOffset ) ) - - -def printThread(process,thread,printopt): + str += findSymbol( frame.instructionOffset ) + dprintln(str) + + +def getModule(offset): try: - setImplicitThread(thread) - - stk = getStack() - - dprintln( "Thread %x, Process: %s (%x)" % ( thread, loadCStr( process.ImageFileName ), process ) ) - for frame in stk: - printFrame(frame, printopt) - - if is64bitSystem(): - processorMode = getProcessorMode() - try: - setProcessorMode("X86") - stk = getStackWow64() - dprintln("\nWOW64 stack") - for frame in stk: - printFrame(frame, printopt) - except BaseException: - pass - setProcessorMode(processorMode) - - dprintln("") - - except BaseException: - - if not printopt.ignoreNotActiveThread: - dprintln( "Thread %x, Process: %s" % ( thread, loadCStr( process.ImageFileName ) ) ) - dprintln( "Failed to switch into thread context\n") - dprintln("") + return module(offset) + except DbgException: + pass + return None + +def getStackHash(stk): + hashStr = "" + for frame in stk: + hashStr += str(frame.instructionOffset) + return hash(hashStr) + +def getStackModules(stk): + modules = [] + for frame in stk: + m = getModule(frame.instructionOffset) + if m and not ( m in modules ): + modules.append( m ) + return modules + +def getStackSymbols(stk): + symbols = [] + for frame in stk: + sym = findSymbol( frame.instructionOffset, showDisplacement = False ) + if sym and not ( sym in symbols ): + symbols.append(sym) + return symbols + + +def printThread(thread, process): + dprintln("") + dprintln( "Thread %x, Process: %s (%x)" % ( thread, loadCStr( process.ImageFileName ), process ) ) + - - def printProcess(process,processFilter,threadFilter,moduleFilter,funcFilter,printopt): processName = loadCStr( process.ImageFileName ) - + if processFilter and not processFilter(process, process.UniqueProcessId, processName ): return - + + dprintln( "Process %x" % process ) + dprintln( "Name: %s Pid: %#x" % ( processName, process.UniqueProcessId ) ) + dprintln( "" ) + try: - #setCurrentProcess(process) - dbgCommand(".process /p %x" % process ) - + + dbgCommand(".process /p /r %x" % process ) dbgCommand( ".reload /user" ) - - threadLst = nt.typedVarList(process.ThreadListHead, "_ETHREAD", "ThreadListEntry.Flink") - filteredThreadLst = [] + + threadLst = typedVarList(process.ThreadListHead, ETHREAD, "ThreadListEntry.Flink") + stackHashes = set() - - for thread in threadLst: - if applayThreadFilter( thread, threadFilter, moduleFilter, funcFilter, printopt, stackHashes ): - filteredThreadLst.append( thread ) - - if filteredThreadLst == []: - return - dprintln( "Process %x" % process ) - dprintln( "Name: %s Pid: %#x" % ( processName, process.UniqueProcessId ) ) - dprintln( "" ) + for thread in threadLst: + + if threadFilter and not threadFilter( thread.Tcb, thread.Cid.UniqueThread ): + continue + + setCurrentThread( thread ) + + stkNative = getStack() + stkWow64 = [] + + if printopt.showWow64stack == True: + try: + + switchCPUMode(); + + try: + stkWow64 = getStack() + + except MemoryException: + pass + + switchCPUMode(); + + except DbgException: + pass + + + stk = [] + + for frame in stkNative: + + mod = getModule(frame.instructionOffset) + + if mod and printopt.combineWow64 and stkWow64: + if mod.name() == "wow64cpu": + break + + frame.cpuType = str(getCPUMode()) + stk.append(frame) + + for frame in stkWow64: + + frame.cpuType = "WOW64" + stk.append(frame) + + if printopt.showUnique: + stackHash= getStackHash(stk) + if stackHash in stackHashes: + continue + stackHashes.add( stackHash ) + + if moduleFilter: + if not [ m for m in getStackModules(stk) if moduleFilter( m, m.name() ) ]: + continue + + if funcFilter: + match = False + for sym in getStackSymbols(stk): + if funcFilter(sym) or ( len( sym.split('!', 1) ) == 2 and funcFilter( sym.split('!', 1)[1] ) ): + match = True + break + if not match: + continue + + printThread( thread, process ) + + for frame in stk: + printFrame(frame, printopt) + + + except DbgException: - for thread in filteredThreadLst: - printThread(process,thread, printopt) - - except BaseException: if not printopt.ignoreNotActiveProcess: + dprintln( "Process %x" % process ) dprintln( "Name: %s" % processName ) dprintln( "Failed to switch into process context\n") - dprintln( "" ) - - + dprintln( "" ) + + def main(): - dprintln("Stack walker. ver 1.0") - - if not isKernelDebugging(): - dprintln("This script is only for kernel debugging") - return - - global nt - nt = module("nt") + + dprintln("Stack walker. ver 1.1") + + if not hasattr(pykd, "__version__") or not fnmatch( pykd.__version__, "0.3.*"): + dprintln ( "pykd has incompatible version" ) parser = OptionParser() parser.add_option("-p", "--process", dest="processfilter", @@ -195,14 +199,28 @@ def main(): parser.add_option("-m", "--module", dest="modulefilter", help="module filter: boolean expression with python syntax" ) parser.add_option("-f", "--function", dest="funcfilter", - help="function filter: boolean expression with python syntax" ) + help="function filter: boolean expression with python syntax" ) parser.add_option("-t", "--thread", dest="threadfilter", - help="thread filter: boolean expresion with python syntax" ) + help="thread filter: boolean expresion with python syntax" ) parser.add_option("-u", "--unique", action="store_true", dest="uniquestack", - help="show only unique stacks" ) + help="show only unique stacks" ) + parser.add_option("-d", "--dump", dest="dumpname", + help="open crach dump" ) + parser.add_option("-w", "--wow64", dest="wow64", + help="show WOW64 stacks") (options, args) = parser.parse_args() - + + if not isWindbgExt(): + initialize() + loadDump( options.dumpname ) + + if not isKernelDebugging(): + dprintln("This script is only for kernel debugging") + return + + setupGlobalObject() + processFilter = None moduleFilter = None funcFilter = None @@ -219,20 +237,18 @@ def main(): if options.threadfilter: threadFilter = lambda thread, tid: eval( options.threadfilter) - + printopt = PrintOptions() printopt.showUnique = True if options.uniquestack else False - - currentProcess = getCurrentProcess() - currentThread = getImplicitThread() + if options.wow64 != None: + printopt.showWow64stack = options.wow64.lower() == 'true' + + processLst = nt.typedVarList( nt.PsActiveProcessHead, "_EPROCESS", "ActiveProcessLinks.Flink") for process in processLst: - printProcess( process, processFilter, threadFilter, moduleFilter, funcFilter, printopt ) - - setCurrentProcess(currentProcess) - setImplicitThread(currentThread) - + printProcess( process, processFilter, threadFilter, moduleFilter, funcFilter, printopt ) + if __name__ == "__main__": main()