Created
April 13, 2017 20:57
-
-
Save kanru/b6b41871db28bdcd10e4c7be792b9e58 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python | |
import json | |
import sys | |
import cmd | |
from colorama import Fore, Style | |
skipList = [ | |
"BaseThreadInitThunk", | |
"CharPrevA", | |
"CsrAllocateMessagePointer", | |
"DispatchMessageW", | |
"DispatchMessageWorker", | |
"EtwEventEnabled", | |
"GetCurrentThread", | |
"GetTickCount", | |
"KiFastSystemCallRet", | |
"MessageLoop::Run", | |
"MessageLoop::RunHandler", | |
"MsgWaitForMultipleObjects", | |
"MsgWaitForMultipleObjectsEx", | |
"NS_ProcessNextEvent", | |
"NS_internal_main", | |
"NtUserValidateHandleSecure", | |
"NtWaitForAlertByThreadId", | |
"NtWaitForMultipleObjects", | |
"NtWaitForSingleObject", | |
"PR_Lock", | |
"PeekMessageW", | |
"RealMsgWaitForMultipleObjectsEx", | |
"RtlAnsiStringToUnicodeString", | |
"RtlDeNormalizeProcessParams", | |
"RtlEnterCriticalSection", | |
"RtlLeaveCriticalSection", | |
"RtlUserThreadStart", | |
"RtlpAllocateListLookup", | |
"RtlpDeCommitFreeBlock", | |
"RtlpEnterCriticalSectionContended", | |
"RtlpUnWaitCriticalSection", | |
"RtlpWaitOnAddress", | |
"RtlpWaitOnAddressWithTimeout", | |
"RtlpWaitOnCriticalSection", | |
"RtlpWakeByAddress", | |
"UserCallWinProcCheckWow" | |
"ValidateHwnd", | |
"WaitForMultipleObjectsEx", | |
"WaitForMultipleObjectsExImplementation", | |
"WaitForSingleObjectEx", | |
"XRE_InitChildProcess", | |
"XRE_RunAppShell", | |
"ZwWaitForMultipleObjects", | |
"ZwWaitForSingleObject", | |
"_RtlUserThreadStart", | |
"__RtlUserThreadStart", | |
"__scrt_common_main_seh", | |
"content_process_main", | |
"mozilla::BackgroundHangMonitor::NotifyActivity", | |
"mozilla::BackgroundHangThread::NotifyActivity", | |
"mozilla::BackgroundHangThread::NotifyWait", | |
"mozilla::BootstrapImpl::XRE_InitChildProcess", | |
"mozilla::HangMonitor::NotifyActivity", | |
"mozilla::HangMonitor::Suspend", | |
"mozilla::ValidatingDispatcher::Runnable::Run", | |
"mozilla::detail::MutexImpl::lock", | |
"mozilla::ipc::MessageChannel::MessageTask::Run", | |
"mozilla::ipc::MessagePump::Run", | |
"mozilla::ipc::MessagePumpForChildProcess::Run", | |
"mozilla::widget::WinUtils::PeekMessageW", | |
"mozilla::widget::WinUtils::WaitForMessage", | |
"nsAppShell::ProcessNextNativeEvent", | |
"nsAppShell::Run", | |
"nsBaseAppShell::DoProcessNextNativeEvent", | |
"nsBaseAppShell::OnProcessNextEvent", | |
"nsBaseAppShell::Run", | |
"nsThread::DoMainThreadSpecificProcessing", | |
"nsThread::ProcessNextEvent", | |
"wmain", | |
"UserCallWinProcCheckWow", | |
"ValidateHwnd", | |
"0x1bc3d", | |
"0x1905a", | |
"RtlSleepConditionVariableCS", | |
"SleepConditionVariableCS", | |
"NDXGI::CDevice::GetKernelDeviceExecutionState", | |
"NtGdiDdDDIGetDeviceState", | |
] | |
def shouldSkip(frame): | |
for item in skipList: | |
if frame.startswith(item): | |
return True | |
return False | |
def filterStacks(stacks): | |
newstacks = [] | |
for frame in stacks: | |
if shouldSkip(frame): | |
continue | |
newstacks.append(frame) | |
return newstacks | |
def hasNativeStack(record, name): | |
for frame in filterStacks(record['nativeStack']['symbolicatedStacks'][0]): | |
if name in frame: | |
return True | |
return False | |
def countAndSort(hangs): | |
buckets = {} | |
for record in hangs: | |
key = ' \n'.join(record['stack']) | |
if not buckets.has_key(key): | |
buckets[key] = 0 | |
buckets[key] += 1 | |
return sorted(buckets.iteritems(), key=lambda p: p[1], reverse=True) | |
class Repl(cmd.Cmd): | |
def __init__(self, hangs): | |
cmd.Cmd.__init__(self) | |
self.prompt = Style.BRIGHT+Fore.RED + "(Stacks with frame?) " + Style.RESET_ALL | |
self.hangs = hangs | |
def onecmd(self, line): | |
if line == '': | |
return | |
if line == 'EOF': | |
sys.exit(0) | |
matches = [] | |
for record in self.hangs: | |
if hasNativeStack(record, line): | |
matches.append(record) | |
for record in countAndSort(matches): | |
print("{}{}{}".format(Style.BRIGHT+Fore.GREEN, | |
record[1], | |
Style.RESET_ALL)) | |
print("{}".format(record[0])) | |
if __name__ == "__main__": | |
hangs = sys.argv[1] | |
data = json.load(open(hangs)) | |
repl = Repl(data) | |
repl.cmdloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment