2013-11-13 15:11:40 +08:00
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
import pykd
|
2013-11-13 15:11:40 +08:00
|
|
|
from pykd import *
|
|
|
|
from optparse import OptionParser
|
|
|
|
from fnmatch import fnmatch
|
|
|
|
import traceback
|
|
|
|
import sys
|
2015-12-03 15:21:29 +08:00
|
|
|
import datetime
|
2013-11-13 15:11:40 +08:00
|
|
|
|
|
|
|
nt = None
|
2014-05-01 00:42:19 +08:00
|
|
|
EPROCESS = None
|
|
|
|
ETHREAD = None
|
2015-12-03 15:21:29 +08:00
|
|
|
Tick = None
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
def setupGlobalObject():
|
|
|
|
|
2015-12-03 15:21:29 +08:00
|
|
|
global nt, EPROCESS, ETHREAD, Tick
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
try:
|
|
|
|
nt = module("nt")
|
|
|
|
EPROCESS = nt.type("_EPROCESS")
|
|
|
|
ETHREAD = nt.type("_ETHREAD")
|
2015-12-03 15:21:29 +08:00
|
|
|
if is64bitSystem():
|
|
|
|
Tick = int(typedVar("nt!_LARGE_INTEGER", 0xFFFFF78000000320).QuadPart)
|
|
|
|
else:
|
|
|
|
Tick = int(ptrDWord(nt.KeTickCount))
|
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
except DbgException:
|
|
|
|
dprintln("check symbol paths")
|
|
|
|
|
2015-12-03 15:21:29 +08:00
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
|
|
|
|
class PrintOptions:
|
|
|
|
def __init__(self):
|
|
|
|
self.ignoreNotActiveThread = True
|
|
|
|
self.ignoreNotActiveProcess = True
|
2015-12-03 15:21:29 +08:00
|
|
|
self.showWow64stack = False
|
2013-11-13 15:11:40 +08:00
|
|
|
self.showIP = True
|
|
|
|
self.showSP = True
|
|
|
|
self.showUnique = False
|
2014-05-01 00:42:19 +08:00
|
|
|
self.combineWow64 = True
|
|
|
|
self.showCpu = True
|
2013-11-13 15:11:40 +08:00
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
def printFrame(frame, printopt):
|
2013-11-13 15:11:40 +08:00
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
str = ""
|
|
|
|
|
|
|
|
if printopt.showCpu:
|
|
|
|
str += frame.cpuType + "\t"
|
2013-11-13 15:11:40 +08:00
|
|
|
|
|
|
|
if printopt.showIP:
|
2014-05-01 00:42:19 +08:00
|
|
|
str += "%016x\t" % frame.instructionOffset
|
2013-11-13 15:11:40 +08:00
|
|
|
if printopt.showSP:
|
2014-05-01 00:42:19 +08:00
|
|
|
str += "%016x\t" % frame.stackOffset
|
2013-11-13 15:11:40 +08:00
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
str += findSymbol( frame.instructionOffset )
|
2013-11-13 15:11:40 +08:00
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
dprintln(str)
|
|
|
|
|
|
|
|
|
|
|
|
def getModule(offset):
|
2013-11-13 15:11:40 +08:00
|
|
|
try:
|
2014-05-01 00:42:19 +08:00
|
|
|
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
|
|
|
|
|
2015-12-03 15:21:29 +08:00
|
|
|
def isWow64Process(process):
|
|
|
|
result = False
|
|
|
|
if is64bitSystem() == False:
|
|
|
|
return result
|
|
|
|
try:
|
|
|
|
if hasattr(process, "WoW64Process"):
|
|
|
|
return process.WoW64Process != 0
|
|
|
|
elif hasattr(process, "Wow64Process"):
|
|
|
|
return process.Wow64Process != 0
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2015-12-03 15:21:29 +08:00
|
|
|
def printThread(thread, process, ticks):
|
2014-05-01 00:42:19 +08:00
|
|
|
dprintln("")
|
2015-12-03 15:21:29 +08:00
|
|
|
dprintln( "<link cmd=\".process %x;.thread %x\">Thread %x</link>, Process: %s (%x), Ticks: %d" % ( process, thread, thread, loadCStr( process.ImageFileName ), process, ticks ), True )
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
|
|
|
|
def printProcess(process,processFilter,threadFilter,moduleFilter,funcFilter,printopt):
|
|
|
|
|
|
|
|
processName = loadCStr( process.ImageFileName )
|
2015-12-03 15:21:29 +08:00
|
|
|
processWow64 = isWow64Process(process)
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
if processFilter and not processFilter(process, process.UniqueProcessId, processName ):
|
|
|
|
return
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
dprintln( "" )
|
2014-05-01 00:42:19 +08:00
|
|
|
dprintln( "Process %x" % process )
|
|
|
|
dprintln( "Name: %s Pid: %#x" % ( processName, process.UniqueProcessId ) )
|
|
|
|
dprintln( "" )
|
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
wow64reloaded = False
|
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
try:
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
dbgCommand(".process /p /r %x" % process )
|
2014-05-29 15:38:09 +08:00
|
|
|
dbgCommand( ".reload /user" )
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
threadLst = typedVarList(process.ThreadListHead, ETHREAD, "ThreadListEntry.Flink")
|
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
stackHashes = set()
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
for thread in threadLst:
|
2015-12-03 15:21:29 +08:00
|
|
|
|
|
|
|
ticks = Tick - thread.Tcb.WaitTime
|
|
|
|
if threadFilter and not threadFilter( thread.Tcb, thread.Cid.UniqueThread, ticks ):
|
2014-05-01 00:42:19 +08:00
|
|
|
continue
|
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
try:
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
setCurrentThread( thread )
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
stkNative = getStack()
|
|
|
|
stkWow64 = []
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2015-12-03 15:21:29 +08:00
|
|
|
if processWow64 and printopt.showWow64stack == True:
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2016-03-09 17:47:40 +08:00
|
|
|
cpuMode = getCPUMode()
|
2014-05-29 15:38:09 +08:00
|
|
|
|
2016-03-09 17:47:40 +08:00
|
|
|
try:
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2018-05-14 16:45:12 +08:00
|
|
|
dbgCommand(".thread /w %x" % thread)
|
|
|
|
#setCPUMode(CPUType.I386)
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2018-05-14 16:45:12 +08:00
|
|
|
#if not wow64reloaded:
|
|
|
|
dbgCommand( ".reload /user" )
|
|
|
|
# wow64reloaded = True
|
|
|
|
|
2016-03-09 17:47:40 +08:00
|
|
|
stkWow64 = getStack()
|
2014-05-29 15:38:09 +08:00
|
|
|
|
|
|
|
except DbgException:
|
|
|
|
pass
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2016-03-09 17:47:40 +08:00
|
|
|
setCPUMode(cpuMode)
|
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
stk = []
|
|
|
|
|
|
|
|
for frame in stkNative:
|
|
|
|
|
|
|
|
mod = getModule(frame.instructionOffset)
|
|
|
|
|
|
|
|
if mod and printopt.combineWow64 and stkWow64:
|
|
|
|
if mod.name() == "wow64cpu":
|
|
|
|
break
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
frame.cpuType = str(getCPUMode())
|
|
|
|
stk.append(frame)
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
for frame in stkWow64:
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
frame.cpuType = "WOW64"
|
|
|
|
stk.append(frame)
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
if printopt.showUnique:
|
|
|
|
stackHash= getStackHash(stk)
|
|
|
|
if stackHash in stackHashes:
|
|
|
|
continue
|
|
|
|
stackHashes.add( stackHash )
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
if moduleFilter:
|
|
|
|
if not [ m for m in getStackModules(stk) if moduleFilter( m, m.name() ) ]:
|
|
|
|
continue
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
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
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2015-12-03 15:21:29 +08:00
|
|
|
printThread( thread, process, ticks )
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
for frame in stk:
|
|
|
|
printFrame(frame, printopt)
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2014-05-29 15:38:09 +08:00
|
|
|
except DbgException:
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2015-12-03 15:21:29 +08:00
|
|
|
printThread( thread, process, ticks )
|
2014-05-29 15:38:09 +08:00
|
|
|
dprintln( "Failed to get stack")
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except DbgException:
|
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
if not printopt.ignoreNotActiveProcess:
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
dprintln( "Process %x" % process )
|
|
|
|
dprintln( "Name: %s" % processName )
|
|
|
|
dprintln( "Failed to switch into process context\n")
|
2014-05-01 00:42:19 +08:00
|
|
|
dprintln( "" )
|
|
|
|
|
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
def main():
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
dprintln("Stack walker. ver 1.1")
|
|
|
|
|
|
|
|
if not hasattr(pykd, "__version__") or not fnmatch( pykd.__version__, "0.3.*"):
|
|
|
|
dprintln ( "pykd has incompatible version" )
|
2013-11-13 15:11:40 +08:00
|
|
|
|
|
|
|
parser = OptionParser()
|
|
|
|
parser.add_option("-p", "--process", dest="processfilter",
|
|
|
|
help="process filter: boolean expression with python syntax" )
|
|
|
|
parser.add_option("-m", "--module", dest="modulefilter",
|
|
|
|
help="module filter: boolean expression with python syntax" )
|
|
|
|
parser.add_option("-f", "--function", dest="funcfilter",
|
2014-05-01 00:42:19 +08:00
|
|
|
help="function filter: boolean expression with python syntax" )
|
2013-11-13 15:11:40 +08:00
|
|
|
parser.add_option("-t", "--thread", dest="threadfilter",
|
2014-05-01 00:42:19 +08:00
|
|
|
help="thread filter: boolean expresion with python syntax" )
|
2013-11-13 15:11:40 +08:00
|
|
|
parser.add_option("-u", "--unique", action="store_true", dest="uniquestack",
|
2014-05-01 00:42:19 +08:00
|
|
|
help="show only unique stacks" )
|
|
|
|
parser.add_option("-d", "--dump", dest="dumpname",
|
2015-12-03 15:21:29 +08:00
|
|
|
help="open crash dump" )
|
|
|
|
parser.add_option("-w", "--wow64", action="store_true", dest="wow64",
|
2014-05-01 00:42:19 +08:00
|
|
|
help="show WOW64 stacks")
|
2013-11-13 15:11:40 +08:00
|
|
|
|
|
|
|
(options, args) = parser.parse_args()
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
if not isKernelDebugging():
|
|
|
|
dprintln("This script is only for kernel debugging")
|
|
|
|
return
|
|
|
|
|
2014-11-06 17:13:23 +08:00
|
|
|
if not isWindbgExt():
|
|
|
|
try:
|
|
|
|
initialize()
|
|
|
|
except DbgException:
|
|
|
|
pass
|
|
|
|
|
|
|
|
if getNumberProcesses() == 0:
|
|
|
|
loadDump( options.dumpname )
|
|
|
|
|
2014-05-01 00:42:19 +08:00
|
|
|
setupGlobalObject()
|
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
processFilter = None
|
|
|
|
moduleFilter = None
|
|
|
|
funcFilter = None
|
|
|
|
threadFilter = None
|
|
|
|
|
|
|
|
if options.processfilter:
|
|
|
|
processFilter = lambda process, pid, name: eval( options.processfilter )
|
|
|
|
|
|
|
|
if options.modulefilter:
|
|
|
|
moduleFilter = lambda module, name: eval(options.modulefilter)
|
|
|
|
|
|
|
|
if options.funcfilter:
|
|
|
|
funcFilter = lambda name: eval( options.funcfilter)
|
|
|
|
|
|
|
|
if options.threadfilter:
|
2015-12-03 15:21:29 +08:00
|
|
|
threadFilter = lambda thread, tid, ticks: eval( options.threadfilter)
|
2014-05-01 00:42:19 +08:00
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
printopt = PrintOptions()
|
|
|
|
printopt.showUnique = True if options.uniquestack else False
|
|
|
|
|
2015-12-03 15:21:29 +08:00
|
|
|
if options.wow64 == True and is64bitSystem():
|
|
|
|
printopt.showWow64stack = True
|
2014-05-01 00:42:19 +08:00
|
|
|
|
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
processLst = nt.typedVarList( nt.PsActiveProcessHead, "_EPROCESS", "ActiveProcessLinks.Flink")
|
|
|
|
for process in processLst:
|
2014-05-01 00:42:19 +08:00
|
|
|
printProcess( process, processFilter, threadFilter, moduleFilter, funcFilter, printopt )
|
|
|
|
|
2013-11-13 15:11:40 +08:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|