You can’t get a mixed-mode callstack from inprocess.

You can't get a full-mixed (both managed+ native) stack of a thread within your own process.
You can get a native-only stack from function like DbgHelp!StackWalk64 (which is what this article on Codeproject  does) to get the native callstack of a native thread. However, the native stackwalker gets lost once it hits managed code because it doesn't know how to decode managed code.  I allude to this problem here.
You can also get a managed-only stack from the managed StackTrace class, but that won't have any native frames.
Unfortunately, you can't really stitch these two results together because there's not enough information.

Consider this example. Suppose the callstack is:
    (M1) calls (U1) calls (M2) calls (U2).
Where M1 and M2 are managed code; and U1 and U2 are unmanaged code. The thread is currently stopped in U2.

A full mixed mode callstack would yield all frames {M1, U1, M2, U2 }. A managed-only stack trace from the StackTrace class would yield {M1, M2} and ignore the unmanaged frames. A native-only stack trace would likely just yield {U2}. This is because stack traces start at the leaf most end of the stack (where the thread is currently active), unwind through U2, then get lost inside of M2 and not even be able to determine that it's in M2. Once a stacktrace gets lost, it will likely just stop trying to make any further progress and thus you get a truncated stack trace.  (It is possible the native stack trace might get "lucky" enough to find U1, depending on the codegen for M2 and the type of transitions between managed and native code).
So the managed-only trace is  {M1, M2}, and the native-only trace is {U2}. There's no way to recover the original full trace {M1, U1, M2, U2} because:
1.) U1 is completely lost.
2.) there's not enough information to be 100% sure about how to order the two traces. Is it {M1, M2, U2} or {M1, U2, M2} or {U2, M1, M2}? 

Obviously, the fact that VS can show fill mixed-mode stacks with MC++ testifies that ICorDebug provides enough information through the Interop-debugging interfaces to allow full mixed-stacks. But that stackwalk is being done from a separate process (the debugger) than the target. You can't use the ICorDebug interfaces for interop-debugging on your own process because as soon as you hit any native debug event, the entire process is frozen. Unlike the native-only debugging API, ICorDebug's interop-debugging API doesn't have non-invasive functionality.

Comments (7)

  1. Brien says:

    Hi Mike,

    Is there any way from managed code to enumerate all managed threads so that I can print stack traces for each for the purpose of debugging (e.g. deadlocks).



  2. Brien – the CLR tracks that information internally, but I don’t think it is exposed out through the class libraries. In the native world, check out CreateToolhelp32Snapshot and Thread32First. I don’t think the CLR exposes a way to get a System.Thread from an OS thread-id (tid).

    You can enumerate all the threads from out of process using the ICorDebug debugging API.

  3. Brien says:

    Hi Mike,

    What I’m interested in is making additional information available about a .NET process in a runtime environment. If I understand correctly, using ICorDebug means I’m effectively running my process under a debugger. Is there any way to do this without imposing speed or memory performance penalties to the process?

    I haven’t used the CLR Hosting API, but do you think that would provide the facility I’m looking for?



  4. Brien says:

    Sorry, that last post should read "in a PRODUCTION runtime environment."

  5. Brien – you’re correct that using ICorDebug means you need to have a separate process for debugger and debuggee.

    The CLR hosting API ( ) can’t help you take a mixed callstack.

  6. The ICorDebug API (the API for debugging managed apps) is about 70 total interfaces.  Here is how…

  7. I’ve had a growing number of people inquire about how to write an interop-debugger with ICorDebug. My

Skip to main content