windbgcrash-dumpssosex

Get the threads which contain a certain .NET function in their call stack?


I have a user mode dump with 73 threads. Some of them are managed and some of them native. I would like to find the managed thread, which call stack contains a certain managed function.

I have the SOSEX extension loaded in the debugger.

Right now I do ~*e !mk to dump all the managed threads and then browse through them manually looking for what I need - too long and tiresome.

Is there a better way?


Solution

  • Related commands

    There is !findstack <module> 2 to find threads that have a specific module on the stack, but IMHO it only works well for native callstacks and for modules only, not for methods.

    Then there is !uniqstack which might help narrowing down the threads in case many threads have the same callstack. It's also a native command.

    Ugly built-in solution

    What I do in such cases is an ugly workaround, but I have not found something better yet:

    .shell -ci "!clrstack" find "Class.Method("
    

    Of course you can combine this with ~*e to do it for all threads.

    ~*e ? $tid;.shell -ci "!clrstack" find "Program.Main("
    

    PyKd script

    If you don't mind installing another WinDbg extension, I recommend PyKd for a more convenient and silent solution. Create a file findstack.py in WinDbg directory (or maybe the working directory of WinDbg, not so sure, otherwise use the full path) with the content

    from pykd import * 
    if "Class.Method(" in dbgCommand("!clrstack"):
        print(hex(expr("$tid")))
    

    In WinDbg, run the script like this:

    .load E:\path to\x86\pykd.pyd
    *** Actually it's a DLL and I prefer renaming it
    *** .load E:\path to\x86\pykd.dll
    ~*e !py findstack.py
    

    Of course you can parameterize the script, e.g. like

    from pykd import *
    import sys
    if (len(sys.argv) < 4):
        print "find <command> <search term> <success command>."
        quit()
    
    if sys.argv[2] in dbgCommand(sys.argv[1]):
        print(dbgCommand(sys.argv[3]))
    

    and then call it with arguments

    ~*e !py find.py "!clrstack" "Program.Main(" "? $tid"