System.Object represents a managed object within a process. ICorDebugValue is the debugger's representation of a System.Object within the debuggee process.
The key here is that the debugger and debuggee processes are ideally fully isolated from each other. For example
- They could both be running different versions of the runtime.
- The debugger should not be "tainted" by the debuggee's runtime.
- The debugger should never need to load debuggee code into the debugger process. In fact, it may not even be able to. (Eg, imagine if the debugger + debuggee on different machines or CPUs. Now I know ICD doesn't currently, allow this, but we still need to future-proof)
- They could be running in different security contexts (debugger could be admin, debugging a low-priv debuggee)
Some common questions:
- Can I get a System.Object from an ICDValue? The debuggee and debugger are 2 separate processes. Getting a system.object from 1 process into another process is done through serialization. So this is really just a serialization problem, with all of the challenges and evils of serialization. Just because one process happens to be debugging the other doesn't suddenly make serialization easy.
ICorDebug doesn't provide a built-in way to do this. There kind of was something in V1 (ICorDebugValue::GetManagedCopy), but it didn't work right and we deprecated it in V2.
- Why is ICDValue so hard to use? Because with ICDValue, all object-inspection operations are exposed through function calls. Whereas with System.Object, you have much more natural language features. For example, a field lookup with System.Object is like "p.field". Psuedo code for a field lookup with ICDValue would be like:
ICDValue _p = ... // get value for 'p'
ICDValue _field = _p.GetFieldValue("field");
In theory, you could build a wrapper around ICDValue that does things like overload operators to hide the ICDValue function calls behind a more natural syntax. However, that's very language dependent (not all languages support overloading field accessors), and ICDValue is a COM-classic interface that must expose everything through explicit interfaces.
The fact that ICDValue is indeed so hard to use motivates folks to want to be able to get an System.Object (which is easy to inspect) from an ICDValue, and then run complex inspection operations on the System.Object. The MDbg (managed) wrappers for ICDValue ought to do a better job here.
- Where does function evaluation fit into this? Func-eval is the ability for the debugger to have the debuggee run code. The key is that the debuggee code is still being run in the debuggee process, and so the isolation is preserved.
- If this is so hard, then how does VS's immediate window lets me do easy inspection of objects in the debuggee? Because the VS's Expression Evaluator team is awesome and has done an amazing job of building on top of ICDValue.