ICorDebug has many different ways of saying "failure". The full list is everything that starts with "CORDBG_" in CorError.h. There are a lot of very specific HRs to describe specific scenarios. For example, CORDBG_E_IL_VAR_NOT_AVAILABLE will tell you that a particular IL variable is not currently available.  However, there are some very general error codes:

  • CORDBG_E_PROCESS_NOT_SYNCHRONIZED - This means that the overall process is in the wrong state. For example, you can't take a callstack when the debuggee is running.
  • CORDBG_E_OBJECT_NEUTERED -  this means that the object is logically dead.
  • CORDBG_E_PROCESS_TERMINATED - this means the debuggee has exited.
  • CORDBG_E_PROCESS_DETACHED - this means the debuggee has detached. The client must have called ICorDebugProcess::Detach.
  • CORDBG_E_UNRECOVERABLE_ERROR - this means ICorDebug is internally inconsistent and broken.  This is bad and shouldn't happen if the API is used properly.

I think we have too many error codes here. I don't think we really need to split hairs between Neutered, Terminated, and Detached. These are really 3 different ways of saying "the object is dead and it's not coming back - and you should already know that based off other ".  In contrast, Not_Synchronized means "the object is currently in an invalid state; try again later".

We made a big push in V2 to move towards Neutering; but we hit some back compat cases where debuggers really expected Terminated instead. I'd like to see us just get rid of Terminated and Detach errors in V3 and make everything Neuter. If you're writing your own debugger against ICorDebug, just don't try to read too much into which exact HR you get.