Here's random information about ICorDebugThread that I hope eventually makes it into MSDN:
 1. The managed CreateThread callback comes at the first bit of managed code that a thread runs. (I think this is a bad for these reasons, and instead it should come as soon as the CLR knows about the thread). This introduces the ICorDebugThread object for that thread.
 2. We haven't defined when exactly the ExitThread callback comes. Currently, it does not come until the underlying native thread has exited.
 3. This means that an ICDThread may not have any managed frames on its stack. For example, the thread may have called into managed code and then returned back to native code. Since the native thread hasn't exited yet, the ICDThread still exists. A very common case of this is the Finalizer thread when it's not running any finalizers.
 4. With fibers, ICorDebugThread becomes 1:1 with the fibers, not the raw OS threads. ICDThread::GetID() didn't make this clear enough (and clients ended up using that expecting it to be stable), so we added ICDThread2::GetVolatileOSThreadID() to make this more obvious.
5. If a debuggee is rudely terminated, you'll still get the ExitProcess event, but not all of the other managed exit-events are guaranteed to come.