-
Notifications
You must be signed in to change notification settings - Fork 51
CLR Expression Evaluator Intrinsics
Debugger intrinsics are special functions that can be called by an Expression Compiler to get or set values in the debugger. Intrinsics are used to support the following features (using C# as an example):
-
$exception
to get the pending exception on the current thread. -
$stowedexception
to get the stowed exception - this is only used when debugging dumps of Windows Store Apps. -
$ReturnValue
,$ReturnValue1
, etc. - Pseudo-variables - these are variables that are declared in the Immediate window. When debugging C# you can declare a variable from the Immediate window by evaluating an expression such as
int i = 0;
. - Object IDs - these are values generated using the "Make Object ID" feature. Object IDs are a way to track objects in the managed heap. Managed objects can't be tracked by address because garbage collection can move them around in memory.
- Debug Managed Memory - To support DataTips in the Debug Managed Memory feature, the Expression Evaluator must have the ability to evaluate an address value as a managed reference.
The debugger provides a method, DkmClrRuntimeInstance.GetAliases
, to get the list of valid aliases. An alias is made up of a name, full name, alias kind, and type. The name and full name values are used to populate the DkmClrLocalVariableInfo
. The kind is one of (Exception, ObjectId, ReturnValue, StowedException, or Variable). The type is an assembly qualified name indicating the type of the variable. There is also a CustomTypeInfoPayload and CustomTypeInfoPayloadTypeId that can be used to communicate custom compiler-specific type information that can't be represented in CLR metadata.
To get the value of a alias, for example $exception
, the Expression Compiler generates a query calling an "intrinsic method". To get the value of $exception
, the C# Expression Compiler generates code that looks like this:
.method public hidebysig static System.Exception M1() cil managed
{
call System.Exception Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetException()
ret
}
Notice the call to Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetException
. This is the intrinsic method call to get the current exception object. For the compiler to link to this method, it needs the metadata for all of the intrinsic methods. The intrinsic methods metadata block can be obtained by calling DkmClrRuntimeInstance.GetIntrinsicAssemblyMetaDataBytesPtr()
.
The intrinsic methods metadata is embedded in the debugger binaries and is generated by compiling this C# code:
(note: the implementations of the methods aren't used)
using System;
namespace Microsoft.VisualStudio.Debugger.Clr
{
public class IntrinsicMethods
{
public static object GetObjectAtAddress(UInt64 address)
{
return null;
}
public static Exception GetException()
{
return null;
}
public static Exception GetStowedException()
{
return null;
}
public static object GetReturnValue(int index)
{
return null;
}
public static void CreateVariable(Type type, string name, Guid customTypeInfoPayloadTypeId, byte[] customTypeInfoPayload)
{
}
public static object GetObjectByAlias(string name)
{
return null;
}
public static ref T GetVariableAddress<T>(string name)
{
throw null;
}
}
}
These methods do the following:
- GetObjectAtAddress: This function returns the object at a given address and is used by the Debug Managed Memory feature. In the C# Expression Compiler, this function is called by evaluating expressions such as
@0x12341234
. This means evaluate the object at address 0x12341234. - GetException: This function returns the exception on the current thread
- GetStowedException: This function returns the stowed exception
- GetReturnValue: This function returns the return value of the given index. The indexes are 1-based. If 0 is passed, this function returns the last return value.
- CreateVariable: This method is used to define new variables in the debugger. It takes a type and name. If there is additional type information needed by the compiler that can't be represented in the metadata, it can pass the information in the custom type info payload. The custom type id is a GUID unique to the language defining the variable. These values are passed back for future calls to GetAliases.
- GetObjectByAlias: This function is used to get the value of an alias. It is used only for pseudo-variables created using CreateVariable and for objects IDs that are created using the Make Object ID feature.
- GetVariableAddress: This returns a reference (or L-value) to a pseudo-variable. It is used to assign values to pseudo-variables created using CreateVariable. It cannot be used for object IDs because they are immutable.
Concord Documentation:
- Overview
- Visual Studio 2022 support
- Concord Architecture
- Getting troubleshooting logs
- Tips for debugging extensions
- Component Discovery and Configuration
- Component Levels
- Navigating the Concord API
- Obtaining the Concord API headers, libraries, etc
- Concord Threading Model
- Data Container API
- Creating and Closing Objects
- Expression Evaluators (EEs)
- .NET language EEs
- Native language EEs
- Installing Extensions
- Cross Platform and VS Code scenarios:
- Implementing components in native code:
- Worker Process Remoting
Samples: