Synopsis: CLR Stack Explorer obtains reliable call stacks of managed processes, supports any combination of 32-bit/64-bit and CLR2/CLR4.
UPDATE [2011/7/20]: If you downloaded CLR Stack Explorer from the above link and are using a recent Windows version, you need to Unblock all the .exe files (right-click, Properties, Unblock) for the tool to run correctly. I have just updated the download location with a self-extracting executable which should solve this problem.
I’m happy to announce that CLR Stack Explorer, a tool I’ve been working on during the last few days, is now ready for preview. Frankly, I have Managed Stack Explorer to thank for this little project – its lack of support for CLR 4 has encouraged me to embark on this journey.
You can find the bits here – but please remember this is a very early preview with probably lots of bugs. Your process may crash as a result of using this tool to view its call stacks.
This is the basic experience when using CLR Stack Explorer:
The tool consists of several components:
- C++/CLI assembly which contains the necessary interactions with the unmanaged CLR Debugging APIs. This assembly exports an unmanaged class, too – so it can be used without the rest of the code.
- C# WinForms GUI that displays a list of relevant managed processes and obtains call stacks from…
- …a C# WCF service that listens over a named pipe for requests to obtain process call stacks. The reason for this service is that the CLR Debugging APIs don’t support cross-bitness debugging, i.e. a 32-bit debugger process can’t obtain call stacks of 64-bit processes and vice versa. Instead of having two separate GUI versions for 32-bit and 64-bit, the GUI talks to two separate services (32-bit and 64-bit) which provide the information.
As I was going at it I found that it would be pretty easy to add source browsing support, so if you have sources at the right location you can double-click a stack frame and go to the line of code:
Also, CLR 4 features a nice addition to the Debugging API which lets a debugger easily see which thread is holding a Monitor (lock) and which threads are waiting for a Monitor using Monitor.Wait. This information is made available through the GUI when right-clicking a thread:
If you find this tool useful, please let me know. It’s been a pleasure writing it so far, and I’m planning to go on – some of the things I have on my TODO list:
- Use GetActiveInternalFrames to retrieve internal frames and display them on the stack (e.g. managed-unmanaged transition)
- Consider moving to ICorDebugStackWalk
- Consider support for unmanaged frames
- Perform automatic deadlock detection
- Cache module metadata and symbol information
- Symbol path support (currently it’s just the current directory)
- Source path support (e.g. prompt the user for source location)