diff options
Diffstat (limited to 'src/inc/corprof.idl')
-rw-r--r-- | src/inc/corprof.idl | 3857 |
1 files changed, 3857 insertions, 0 deletions
diff --git a/src/inc/corprof.idl b/src/inc/corprof.idl new file mode 100644 index 0000000000..4288897844 --- /dev/null +++ b/src/inc/corprof.idl @@ -0,0 +1,3857 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/************************************************************************************** + ** ** + ** Corprof.idl - CLR Profiling interfaces. ** + ** ** + **************************************************************************************/ + +/* -------------------------------------------------------------------------- * + * Imported types + * -------------------------------------------------------------------------- */ + +#if !DEFINITIONS_FROM_NON_IMPORTABLE_PLACES + +cpp_quote("#define CorDB_CONTROL_Profiling \"Cor_Enable_Profiling\"") +cpp_quote("#define CorDB_CONTROL_ProfilingL L\"Cor_Enable_Profiling\"") + +cpp_quote("#if 0") + + +import "unknwn.idl"; + +typedef LONG32 mdToken; +typedef mdToken mdModule; +typedef mdToken mdTypeDef; +typedef mdToken mdMethodDef; +typedef mdToken mdFieldDef; +typedef ULONG CorElementType; + +// Forward declaration of enum in CorHdr.h +enum CorElementType; + +// Forward declaration of structs in Cor.h + +typedef struct +{ + DWORD dwOSPlatformId; // Operating system platform. + DWORD dwOSMajorVersion; // OS Major version. + DWORD dwOSMinorVersion; // OS Minor version. +} OSINFO; + +typedef struct +{ + USHORT usMajorVersion; // Major Version. + USHORT usMinorVersion; // Minor Version. + USHORT usBuildNumber; // Build Number. + USHORT usRevisionNumber; // Revision Number. + LPWSTR szLocale; // Locale. + ULONG cbLocale; // [IN/OUT] Size of the buffer in wide chars/Actual size. + DWORD *rProcessor; // Processor ID array. + ULONG ulProcessor; // [IN/OUT] Size of the Processor ID array/Actual # of entries filled in. + OSINFO *rOS; // OSINFO array. + ULONG ulOS; // [IN/OUT]Size of the OSINFO array/Actual # of entries filled in. +} ASSEMBLYMETADATA; + +cpp_quote("#endif") + +typedef const BYTE *LPCBYTE; +typedef BYTE *LPBYTE; + +#endif + + +cpp_quote("#ifndef _COR_IL_MAP") +cpp_quote("#define _COR_IL_MAP") + +#ifdef INTERNAL_DOCS +// Note that this structure is also defined in CorDebug.idl - PROPAGATE CHANGES +// BOTH WAYS, or this'll become a really insidious bug some day. +#endif +typedef struct _COR_IL_MAP +{ + ULONG32 oldOffset; // Old IL offset relative to beginning of function + ULONG32 newOffset; // New IL offset relative to beginning of function + BOOL fAccurate; //put here for compatibility with the Debugger structure. +} COR_IL_MAP; + +cpp_quote("#endif //_COR_IL_MAP") + +cpp_quote("#ifndef _COR_DEBUG_IL_TO_NATIVE_MAP_") +cpp_quote("#define _COR_DEBUG_IL_TO_NATIVE_MAP_") + +/* ICorProfilerInfo:: GetILToNativeMapping returns an array of + * COR_DEBUG_IL_TO_NATIVE_MAP structures. In order to convey that certain + * ranges of native instructions correspond to special regions of code (for + * example, the prolog), an entry in the array may have it's ilOffset field set + * to one of these values. + */ +typedef enum CorDebugIlToNativeMappingTypes +{ + NO_MAPPING = -1, + PROLOG = -2, + EPILOG = -3 +} CorDebugIlToNativeMappingTypes; + +typedef struct COR_DEBUG_IL_TO_NATIVE_MAP +{ + ULONG32 ilOffset; + ULONG32 nativeStartOffset; + ULONG32 nativeEndOffset; +} COR_DEBUG_IL_TO_NATIVE_MAP; + +cpp_quote("#endif // _COR_DEBUG_IL_TO_NATIVE_MAP_") + +cpp_quote("#ifndef _COR_FIELD_OFFSET_") +cpp_quote("#define _COR_FIELD_OFFSET_") + +typedef struct _COR_FIELD_OFFSET +{ + mdFieldDef ridOfField; // fieldDef token of the field + ULONG ulOffset; // offset (from the ObjectID pointer) of the field +} COR_FIELD_OFFSET; + +cpp_quote("#endif // _COR_FIELD_OFFSET_") + + +#ifndef DO_NO_IMPORTS +import "wtypes.idl"; +import "unknwn.idl"; +#endif + +typedef UINT_PTR ProcessID; +typedef UINT_PTR AssemblyID; +typedef UINT_PTR AppDomainID; +typedef UINT_PTR ModuleID; +typedef UINT_PTR ClassID; +typedef UINT_PTR ThreadID; +typedef UINT_PTR ContextID; +typedef UINT_PTR FunctionID; +typedef UINT_PTR ObjectID; +typedef UINT_PTR GCHandleID; +typedef UINT_PTR COR_PRF_ELT_INFO; +typedef UINT_PTR ReJITID; + +typedef union {FunctionID functionID; UINT_PTR clientID;} FunctionIDOrClientID; + +/* + * The FunctionIDMapper type definition is used by the + * ICorProfilerInfo::SetFunctionIDMapper method to specify + * a function that will be called to map FunctionIDs to alternative + * values that will be passed to the function entry and function exit + * callbacks supplied to the ICorProfilerInfo::SetEnterLeaveFunctionHooks + * method. The mapper can be set only once and it is recommended to do so + * in the Initialize callback. + * + * NOTE: There is a known bug in this API that must be worked around. + * The return value of FunctionIDMapper cannot be NULL (unless the boolean + * value in pbHookTheFunction is FALSE). All other values are treated as + * opaque data to be passed to the entry/exit callback functions. The use + * of a NULL return value will produce unpredictable results, including + * possibly halting the process. + * + * NOTE: Profilers should be tolerant of cases where multiple threads of + * a profiled app are calling the same method simultaneously. In such + * cases, the profiler may receive multiple FunctionIDMapper callbacks + * for the same functionId. The profiler should be certain to return + * the same values from this callback when it is called multiple times + * with the same functionId. + * + */ +typedef UINT_PTR __stdcall FunctionIDMapper( + FunctionID funcId, + BOOL *pbHookFunction); + +typedef UINT_PTR __stdcall FunctionIDMapper2( + FunctionID funcId, + void *clientData, + BOOL *pbHookFunction); + +/* + * Enum for specifying how much data to pass back with a stack snapshot + */ +typedef enum _COR_PRF_SNAPSHOT_INFO +{ + COR_PRF_SNAPSHOT_DEFAULT = 0x0, + + // Return a register context for each frame + COR_PRF_SNAPSHOT_REGISTER_CONTEXT = 0x1, + + // Use a quicker stack walk algorithm based on the EBP frame chain. This is available + // on x86 only. + COR_PRF_SNAPSHOT_X86_OPTIMIZED = 0x2, +} COR_PRF_SNAPSHOT_INFO; + +/* + * Opaque handle that represents information about a given stack frame. It is only + * valid during the callback to which it is passed. + */ +typedef UINT_PTR COR_PRF_FRAME_INFO; + +/* + * Describes a range of function arguments stored contiguously in left-to-right + * order in memory. + */ +typedef struct _COR_PRF_FUNCTION_ARGUMENT_RANGE +{ + UINT_PTR startAddress; // start address of the range + ULONG length; // contiguous length of the range +} COR_PRF_FUNCTION_ARGUMENT_RANGE; + +/* + * Describes the locations in memory of a function's arguments, in + * left-to-right order. Note that arguments stored in registers are + * spilled to memory to build these structures. + */ +typedef struct _COR_PRF_FUNCTION_ARGUMENT_INFO +{ + ULONG numRanges; // number of chunks of arguments + ULONG totalArgumentSize; // total size of arguments + COR_PRF_FUNCTION_ARGUMENT_RANGE ranges[1]; // chunks +} COR_PRF_FUNCTION_ARGUMENT_INFO; + +/* + * Represents one contiguous chunk of native code + */ +typedef struct _COR_PRF_CODE_INFO +{ + UINT_PTR startAddress; + SIZE_T size; +} COR_PRF_CODE_INFO; + +/* + * Enum for describing the type of static a field is. These may be bit-wise + * or'ed with each other if the field is multiple types. + */ +typedef enum +{ + COR_PRF_FIELD_NOT_A_STATIC = 0x0, + COR_PRF_FIELD_APP_DOMAIN_STATIC = 0x1, + COR_PRF_FIELD_THREAD_STATIC = 0x2, + COR_PRF_FIELD_CONTEXT_STATIC = 0x4, + COR_PRF_FIELD_RVA_STATIC = 0x8 +} COR_PRF_STATIC_TYPE; + +/* + * Represents a function uniquely by combining the FunctionID + * with a ReJITID. + */ +typedef struct _COR_PRF_FUNCTION +{ + FunctionID functionId; + ReJITID reJitId; +} COR_PRF_FUNCTION; + + +/* + * Structure populated by profiler when declaring additional assembly references + * that the CLR should consider when performing an assembly reference closure + * walk. See ICorProfilerCallback6::GetAssemblyReferences and + * ICorProfilerAssemblyReferenceProvider::AddAssemblyReference + */ +typedef struct _COR_PRF_ASSEMBLY_REFERENCE_INFO +{ + void *pbPublicKeyOrToken; // Public key or token of the assembly. + ULONG cbPublicKeyOrToken; // Count of bytes in the public key or token. + LPCWSTR szName; // Name of the assembly being referenced. + ASSEMBLYMETADATA * pMetaData; // Assembly MetaData, as defined in cor.h + void *pbHashValue; // Hash Blob. + ULONG cbHashValue; // Count of bytes in the Hash Blob. + DWORD dwAssemblyRefFlags; // Flags. +} COR_PRF_ASSEMBLY_REFERENCE_INFO; + + +/* + * Represents a IL methods uniquely by combining the module ID and method token. + */ +typedef struct _COR_PRF_METHOD +{ + ModuleID moduleId; + mdMethodDef methodId; +} COR_PRF_METHOD; + +/* + * NOTE!!! + * + * The following applies to ALL FunctionEnter[2,3], FunctionLeave[2,3], + * FunctionTailcall[2,3] hooks below: + * + * It is VERY IMPORTANT to note that these function implementations must be + * __declspec(naked), since the EE is not saving any registers before calling + * any of them. YOU MUST SAVE ALL REGISTERS YOU USE, INCLUDING FPU REGISTERS + * IF THE FPU STACK IS NOT EMPTY AND YOU INTEND TO USE IT. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + */ + + /* + * NOTE: DEPRECATED IN V2 + * + * These functions are considered deprecated in V2 and higher. They will + * continue to work, but incur a performance penalty for usage. For equivalent + * functionality, use the FunctionEnter3/Leave3/Tailcall3 callbacks with + * bits cleared for COR_PRF_ENABLE_FRAME_INFO, COR_PRF_ENABLE_FUNCTION_RETVAL + * and COR_PRF_ENABLE_FUNCTION_ARGS. + */ +typedef void __stdcall FunctionEnter( + FunctionID funcID); + +typedef void __stdcall FunctionLeave( + FunctionID funcID); + +typedef void __stdcall FunctionTailcall( + FunctionID funcID); + +/* + * NOTE: DEPRECATED IN V4 + * + * These functions are considered deprecated in V4 and higher. They will + * continue to work, but incur a performance penalty for usage. For equivalent + * functionality, use the FunctionEnter3/Leave3/Tailcall3 callbacks. + */ + +typedef void __stdcall FunctionEnter2( + FunctionID funcId, + UINT_PTR clientData, + COR_PRF_FRAME_INFO func, + COR_PRF_FUNCTION_ARGUMENT_INFO *argumentInfo); + +typedef void __stdcall FunctionLeave2( + FunctionID funcId, + UINT_PTR clientData, + COR_PRF_FRAME_INFO func, + COR_PRF_FUNCTION_ARGUMENT_RANGE *retvalRange); + +typedef void __stdcall FunctionTailcall2( + FunctionID funcId, + UINT_PTR clientData, + COR_PRF_FRAME_INFO func); + +/* + * When you are not interested in inspecting arguments or return values, then + * use these to be notified as functions are called and return. Use + * SetEnterLeaveFunctionHooks3 to register your implementations of these + * functions. + * + * functionIDOrClientID: if the profiler returned a remapped value from + * FunctionIDMapper[2], then this is that remapped value; else it is the + * true FunctionID of the function. + */ + +typedef void __stdcall FunctionEnter3( + FunctionIDOrClientID functionIDOrClientID); + +typedef void __stdcall FunctionLeave3( + FunctionIDOrClientID functionIDOrClientID); + +typedef void __stdcall FunctionTailcall3( + FunctionIDOrClientID functionIDOrClientID); + +/* + * When you are interested in inspecting arguments and return values, then + * use these to be notified as functions are called and return. Use + * SetEnterLeaveFunctionHooks3WithInfo to register your implementations of these + * functions. + * + * functionIDOrClientID: if the profiler returned a remapped value from + * FunctionIDMapper[2], then this is that remapped value; else it is the + * true FunctionID of the function. + * + * eltInfo is an opaque handle that represents information about a given stack frame. + * It is only valid during the callback to which it is passed. + */ + +typedef void __stdcall FunctionEnter3WithInfo( + FunctionIDOrClientID functionIDOrClientID, + COR_PRF_ELT_INFO eltInfo); + +typedef void __stdcall FunctionLeave3WithInfo( + FunctionIDOrClientID functionIDOrClientID, + COR_PRF_ELT_INFO eltInfo); + +typedef void __stdcall FunctionTailcall3WithInfo( + FunctionIDOrClientID functionIDOrClientID, + COR_PRF_ELT_INFO eltInfo); + +/* + * Stack snapshot callback definition. + * + * This callback is called once per managed frame or run of unmanaged frames. + * + * funcID is the FunctionID of the managed function. If funcID == 0, the callback is + * for a run of unmanaged frames. The profiler may either ignore the frame, or use + * the register context to perform its own unmanaged stackwalk. + * + * ip is the native IP in the frame + * + * frameInfo is the COR_PRF_FRAME_INFO for this frame. It is only valid for + * use during this callback. + * + * context is a Win32 CONTEXT struct for the current platform (size given in + * contextSize). It will only be valid if the COR_PRF_SNAPSHOT_CONTEXT flag + * was passed to DoStackSnapshot. + * + * clientData is a void* passed straight through from DoStackSnapshot + * + * NOTE: One must limit the complexity of work done in StackSnapshotCallback. + * For example, particularly when using DoStackSnapshot in an asynchronous manner, + * the target thread may be holding locks. Executing code within StackSnapshotCallback + * that requires the same locks could lead to deadlock. + */ +typedef HRESULT __stdcall StackSnapshotCallback( + FunctionID funcId, + UINT_PTR ip, + COR_PRF_FRAME_INFO frameInfo, + ULONG32 contextSize, + BYTE context[], + void *clientData); + +typedef enum +{ + // These flags represent classes of callback events + COR_PRF_MONITOR_NONE = 0x00000000, + + // MONITOR_FUNCTION_UNLOADS controls the + // FunctionUnloadStarted callback. + COR_PRF_MONITOR_FUNCTION_UNLOADS = 0x00000001, + + // MONITOR_CLASS_LOADS controls the ClassLoad* + // and ClassUnload* callbacks. + // See the comments on those callbacks for important + // behavior changes in V2. + COR_PRF_MONITOR_CLASS_LOADS = 0x00000002, + + // MONITOR_MODULE_LOADS controls the + // ModuleLoad*, ModuleUnload*, and ModuleAttachedToAssembly + // callbacks. + COR_PRF_MONITOR_MODULE_LOADS = 0x00000004, + + // MONITOR_ASSEMBLY_LOADS controls the + // AssemblyLoad* and AssemblyUnload* callbacks + COR_PRF_MONITOR_ASSEMBLY_LOADS = 0x00000008, + + // MONITOR_APPDOMAIN_LOADS controls the + // AppDomainCreation* and AppDomainShutdown* callbacks + COR_PRF_MONITOR_APPDOMAIN_LOADS = 0x00000010, + + // MONITOR_JIT_COMPILATION controls the + // JITCompilation*, JITFunctionPitched, and JITInlining + // callbacks. + COR_PRF_MONITOR_JIT_COMPILATION = 0x00000020, + + + // MONITOR_EXCEPTIONS controls the ExceptionThrown, + // ExceptionSearch*, ExceptionOSHandler*, ExceptionUnwind*, + // and ExceptionCatcher* callbacks. + COR_PRF_MONITOR_EXCEPTIONS = 0x00000040, + + // MONITOR_GC controls the GarbageCollectionStarted/Finished, + // MovedReferences, SurvivingReferences, + // ObjectReferences, ObjectsAllocatedByClass, + // RootReferences*, HandleCreated/Destroyed, and FinalizeableObjectQueued + // callbacks. + COR_PRF_MONITOR_GC = 0x00000080, + + // MONITOR_OBJECT_ALLOCATED controls the + // ObjectAllocated callback. + COR_PRF_MONITOR_OBJECT_ALLOCATED = 0x00000100, + + // MONITOR_THREADS controls the ThreadCreated, + // ThreadDestroyed, ThreadAssignedToOSThread, + // and ThreadNameChanged callbacks. + COR_PRF_MONITOR_THREADS = 0x00000200, + + // MONITOR_REMOTING controls the Remoting* + // callbacks. + COR_PRF_MONITOR_REMOTING = 0x00000400, + + // MONITOR_CODE_TRANSITIONS controls the + // UnmanagedToManagedTransition and + // ManagedToUnmanagedTransition callbacks. + COR_PRF_MONITOR_CODE_TRANSITIONS = 0x00000800, + + // MONITOR_ENTERLEAVE controls the + // FunctionEnter*/Leave*/Tailcall* callbacks + COR_PRF_MONITOR_ENTERLEAVE = 0x00001000, + + // MONITOR_CCW controls the COMClassicVTable* + // callbacks. + COR_PRF_MONITOR_CCW = 0x00002000, + + // MONITOR_REMOTING_COOKIE controls whether + // a cookie will be passed to the Remoting* callbacks + COR_PRF_MONITOR_REMOTING_COOKIE = 0x00004000 | COR_PRF_MONITOR_REMOTING, + + // MONITOR_REMOTING_ASYNC controls whether + // the Remoting* callbacks will monitor async events + COR_PRF_MONITOR_REMOTING_ASYNC = 0x00008000 | COR_PRF_MONITOR_REMOTING, + + // MONITOR_SUSPENDS controls the RuntimeSuspend*, + // RuntimeResume*, RuntimeThreadSuspended, and + // RuntimeThreadResumed callbacks. + COR_PRF_MONITOR_SUSPENDS = 0x00010000, + + // MONITOR_CACHE_SEARCHES controls the + // JITCachedFunctionSearch* callbacks. + // See the comments on those callbacks for important + // behavior changes in V2. + COR_PRF_MONITOR_CACHE_SEARCHES = 0x00020000, + + // NOTE: ReJIT is now supported again. The profiler must set this flag on + // startup in order to use RequestReJIT or RequestRevert. If the profiler specifies + // this flag, then the profiler must also specify COR_PRF_DISABLE_ALL_NGEN_IMAGES + COR_PRF_ENABLE_REJIT = 0x00040000, + + // V2 MIGRATION WARNING: DEPRECATED + // Inproc debugging is no longer supported. ENABLE_INPROC_DEBUGGING + // has no effect. + COR_PRF_ENABLE_INPROC_DEBUGGING = 0x00080000, + + // V2 MIGRATION NOTE: DEPRECATED + // The runtime now always tracks IL-native maps; this flag is thus always + // considered to be set. + COR_PRF_ENABLE_JIT_MAPS = 0x00100000, + + // DISABLE_INLINING tells the runtime to disable all inlining + COR_PRF_DISABLE_INLINING = 0x00200000, + + // DISABLE_OPTIMIZATIONS tells the runtime to disable all code optimizations + COR_PRF_DISABLE_OPTIMIZATIONS = 0x00400000, + + // ENABLE_OBJECT_ALLOCATED tells the runtime that the profiler may want + // object allocation notifications. This must be set during initialization if the profiler + // ever wants object notifications (using COR_PRF_MONITOR_OBJECT_ALLOCATED) + COR_PRF_ENABLE_OBJECT_ALLOCATED = 0x00800000, + + // MONITOR_CLR_EXCEPTIONS controls the ExceptionCLRCatcher* + // callbacks. + COR_PRF_MONITOR_CLR_EXCEPTIONS = 0x01000000, + + // All callback events are enabled with this flag + COR_PRF_MONITOR_ALL = 0x0107FFFF, + + // ENABLE_FUNCTION_ARGS enables argument tracing through FunctionEnter2. + COR_PRF_ENABLE_FUNCTION_ARGS = 0X02000000, + + // ENABLE_FUNCTION_RETVAL enables retval tracing through FunctionLeave2. + COR_PRF_ENABLE_FUNCTION_RETVAL = 0X04000000, + + // ENABLE_FRAME_INFO enables retrieval of exact ClassIDs for generic functions using + // GetFunctionInfo2 with a COR_PRF_FRAME_INFO obtained from FunctionEnter2. + COR_PRF_ENABLE_FRAME_INFO = 0X08000000, + + // ENABLE_STACK_SNAPSHOT enables the used of DoStackSnapshot calls. + COR_PRF_ENABLE_STACK_SNAPSHOT = 0X10000000, + + // USE_PROFILE_IMAGES causes the native image search to look for profiler-enhanced + // images. If no profiler-enhanced image is found for a given assembly the + // runtime will fallback to JIT for that assembly. + COR_PRF_USE_PROFILE_IMAGES = 0x20000000, + + // COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST will disable security + // transparency checks normally done during JIT compilation and class loading for + // full trust assemblies. This can make some instrumentation easier to perform. + COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST + = 0x40000000, + + // Prevents all NGEN images (including profiler-enhanced images) from loading. If + // this and COR_PRF_USE_PROFILE_IMAGES are both specified, + // COR_PRF_DISABLE_ALL_NGEN_IMAGES wins. + COR_PRF_DISABLE_ALL_NGEN_IMAGES = 0x80000000, + + // The mask for valid mask bits + COR_PRF_ALL = 0x8FFFFFFF, + + // COR_PRF_REQUIRE_PROFILE_IMAGE represents all flags that require profiler-enhanced + // images. + COR_PRF_REQUIRE_PROFILE_IMAGE = COR_PRF_USE_PROFILE_IMAGES | + COR_PRF_MONITOR_CODE_TRANSITIONS | + COR_PRF_MONITOR_ENTERLEAVE, + + COR_PRF_ALLOWABLE_AFTER_ATTACH = COR_PRF_MONITOR_THREADS | + COR_PRF_MONITOR_MODULE_LOADS | + COR_PRF_MONITOR_ASSEMBLY_LOADS | + COR_PRF_MONITOR_APPDOMAIN_LOADS | + COR_PRF_ENABLE_STACK_SNAPSHOT | + COR_PRF_MONITOR_GC | + COR_PRF_MONITOR_SUSPENDS | + COR_PRF_MONITOR_CLASS_LOADS | + COR_PRF_MONITOR_EXCEPTIONS | + COR_PRF_MONITOR_JIT_COMPILATION, + + // MONITOR_IMMUTABLE represents all flags that may only be set during initialization. + // Trying to change any of these flags elsewhere will result in a + // failed HRESULT. + COR_PRF_MONITOR_IMMUTABLE = COR_PRF_MONITOR_CODE_TRANSITIONS | + COR_PRF_MONITOR_REMOTING | + COR_PRF_MONITOR_REMOTING_COOKIE | + COR_PRF_MONITOR_REMOTING_ASYNC | + COR_PRF_ENABLE_REJIT | + COR_PRF_ENABLE_INPROC_DEBUGGING | + COR_PRF_ENABLE_JIT_MAPS | + COR_PRF_DISABLE_OPTIMIZATIONS | + COR_PRF_DISABLE_INLINING | + COR_PRF_ENABLE_OBJECT_ALLOCATED | + COR_PRF_ENABLE_FUNCTION_ARGS | + COR_PRF_ENABLE_FUNCTION_RETVAL | + COR_PRF_ENABLE_FRAME_INFO | + COR_PRF_USE_PROFILE_IMAGES | + COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST | + COR_PRF_DISABLE_ALL_NGEN_IMAGES +} COR_PRF_MONITOR; + +/* + * Additional flags the profiler can specify via SetEventMask2 when loading + */ +typedef enum +{ + COR_PRF_HIGH_MONITOR_NONE = 0x00000000, + + COR_PRF_HIGH_ADD_ASSEMBLY_REFERENCES = 0x00000001, + + COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED = 0x00000002, + + COR_PRF_HIGH_REQUIRE_PROFILE_IMAGE = 0, + + COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED, + + // MONITOR_IMMUTABLE represents all flags that may only be set during initialization. + // Trying to change any of these flags elsewhere will result in a + // failed HRESULT. + COR_PRF_HIGH_MONITOR_IMMUTABLE = 0, + +} COR_PRF_HIGH_MONITOR; + +/* + * COR_PRF_MISC contains miscellaneous constant ID's used for special + * purposes. + */ +typedef enum +{ + // PROFILER_PARENT_UNKNOWN is the AssemblyID used by GetModuleInfo + // when a module has not yet been attached to an assembly. + PROFILER_PARENT_UNKNOWN = 0xFFFFFFFD, + + // PROFILER_GLOBAL_CLASS is a ClassID used for globals that belong to no class + PROFILER_GLOBAL_CLASS = 0xFFFFFFFE, + + // PROFILER_GLOBAL_MODULE is a ModuleID used for globals that belong + // to no module in particular + PROFILER_GLOBAL_MODULE = 0xFFFFFFFF +} COR_PRF_MISC; + +/* + * COR_PRF_JIT_CACHE contains values used to express the result of a + * cached function search. Note that FOUND is 0, and thus this is not truly + * a boolean. + */ +typedef enum +{ + COR_PRF_CACHED_FUNCTION_FOUND, + COR_PRF_CACHED_FUNCTION_NOT_FOUND +} COR_PRF_JIT_CACHE; + +/* + * COR_PRF_TRANSITION_REASON contains values used to describe + * the reason for a ManagedToUnmanaged or UnmanagedToManagedTransition + * callback. + */ +typedef enum +{ + COR_PRF_TRANSITION_CALL, + COR_PRF_TRANSITION_RETURN +} COR_PRF_TRANSITION_REASON; + +/* + * COR_PRF_SUSPEND_REASON contains values used to describe the + * reason for suspending the runtime. See the RuntimeSuspension* + * callbacks for detailed descriptions of each. + */ +typedef enum +{ + COR_PRF_SUSPEND_OTHER = 0, + COR_PRF_SUSPEND_FOR_GC = 1, + COR_PRF_SUSPEND_FOR_APPDOMAIN_SHUTDOWN = 2, + COR_PRF_SUSPEND_FOR_CODE_PITCHING = 3, + COR_PRF_SUSPEND_FOR_SHUTDOWN = 4, + COR_PRF_SUSPEND_FOR_INPROC_DEBUGGER = 6, + COR_PRF_SUSPEND_FOR_GC_PREP = 7, + COR_PRF_SUSPEND_FOR_REJIT = 8, +} COR_PRF_SUSPEND_REASON; + +/* + * COR_PRF_RUNTIME_TYPE contains values used to indicate the + * type of runtime. + */ +typedef enum +{ + COR_PRF_DESKTOP_CLR = 0x1, + COR_PRF_CORE_CLR = 0x2, +} COR_PRF_RUNTIME_TYPE; + + +/* -------------------------------------------------------------------------- * + * Forward declarations + * -------------------------------------------------------------------------- */ + +interface ICorProfilerCallback; +interface ICorProfilerCallback2; +interface ICorProfilerCallback3; +interface ICorProfilerCallback4; +interface ICorProfilerInfo; +interface ICorProfilerInfo2; +interface ICorProfilerInfo3; +interface ICorProfilerInfo4; +interface ICorProfilerObjectEnum; +interface ICorProfilerFunctionEnum; +interface ICorProfilerModuleEnum; +interface ICorProfilerThreadEnum; +interface ICorProfilerMethodEnum; +interface IMethodMalloc; +interface ICorProfilerFunctionControl; +interface ICorProfilerAssemblyReferenceProvider; +/* -------------------------------------------------------------------------- * + * User Callback interface + * -------------------------------------------------------------------------- */ + +/* + * The ICorProfilerCallback interface is used by the CLR to notify a + * code profiler when events have occurred that the code profiler has registered + * an in interest in receiving. This is the primary callback interface through + * which the CLR communicates with the code profiler. A code profiler + * must register this callback interface in the Win32 registry. This object has + * several methods that receive notification from the runtime when an event is + * about to occur in an executing runtime process. + * + * The methods implemented on this interface return S_OK on success, or E_FAIL + * on failure. + */ + +[ + object, + uuid(176FBED1-A55C-4796-98CA-A9DA0EF883E7), + pointer_default(unique), + local +] +interface ICorProfilerCallback : IUnknown +{ + + /* + * + * STARTUP/SHUTDOWN EVENTS + * + */ + + /* + * The CLR calls Initialize to setup the code profiler + * whenever a new CLR application is started. The call provides + * an IUnknown interface pointer that should be QI'd for an ICorProfilerInfo + * interface pointer. + * + * NOTE: this is the only opportunity to enable callbacks that are a part + * of COR_PRF_MONITOR_IMMUTABLE, since they can no longer be changed after + * returning from this function. This is done through SetEventMask on the + * ICorProfilerInfo object. + */ + HRESULT Initialize( + [in] IUnknown *pICorProfilerInfoUnk); + + /* + * The CLR calls Shutdown to notify the code profiler that + * the application is exiting. This is the profiler's last opportunity to + * safely call functions on the ICorProfilerInfo interface. After returning + * from this function the runtime will proceed to unravel its internal data + * structures and any calls to ICorProfilerInfo are undefined in their + * behaviour. + * + * NOTE: Certain IMMUTABLE events may still occur after Shutdown. + * + * NOTE: Shutdown will only fire where the managed application that is being + * profiled was started running managed code (i.e., the initial frame on the + * process' stack is managed). If the application being profiled started + * life as unmanaged code, which later 'jumped into' managed code (thereby + * creating an instance of the CLR), then Shutdown will not fire. In these + * cases, the profiler should include a DllMain routine in their library that + * uses Win32's DLL_PROCESS_DETACH call to free any resources and perform tidy-up + * processing of its data (flush traces to disk, etc) + * + * NOTE: The profiler must in general cope with unexpected shutdowns, such as + * when the process is "killed" by Win32's TerminateProcess. + * + * NOTE: Sometimes the CLR will violently kill certain managed threads + * (background threads) without delivering orderly destruction messages for them. + */ + HRESULT Shutdown(); + + + /* + * + * APPLICATION DOMAIN EVENTS + * + */ + + /* + * Called when an application domain creation has begun and ended. + * The ID is not valid for any information request until the Finished + * event is called. + * + * Some parts of app domain loading may take place lazily at some time + * after the Finished callback. Therefore, while a failure HRESULT in + * hrStatus definitely indicates a failure, a success HRESULT only indicates + * that the first part of app domain creation succeeded. + */ + HRESULT AppDomainCreationStarted( + [in] AppDomainID appDomainId); + + HRESULT AppDomainCreationFinished( + [in] AppDomainID appDomainId, + [in] HRESULT hrStatus); + + /* + * Called before and after an app domain is unloaded from a process. + * The ID is no longer valid after the Started event returns. + * + * Some parts of app domain unloading may take place lazily at some time + * after the Finished callback. Therefore, while a failure HRESULT in + * hrStatus definitely indicates a failure, a success HRESULT only indicates + * that the first part of app domain unloading succeeded. + */ + HRESULT AppDomainShutdownStarted( + [in] AppDomainID appDomainId); + + HRESULT AppDomainShutdownFinished( + [in] AppDomainID appDomainId, + [in] HRESULT hrStatus); + + /* + * + * ASSEMBLY EVENTS + * + */ + + /* + * Called when an Assembly load has begun and ended. The ID is not valid + * for any information request until the Finished event is called. + * + * Some parts of assembly loading may take place lazily at some time + * after the Finished callback. Therefore, while a failure HRESULT in + * hrStatus definitely indicates a failure, a success HRESULT only indicates + * that the first part of assembly loading succeeded. + */ + HRESULT AssemblyLoadStarted( + [in] AssemblyID assemblyId); + + HRESULT AssemblyLoadFinished( + [in] AssemblyID assemblyId, + [in] HRESULT hrStatus); + + /* + * Called before and after an assembly is unloaded. + * The ID is no longer valid after the Started event returns. + * + * Some parts of assembly unloading may take place lazily at some time + * after the Finished callback. Therefore, while a failure HRESULT in + * hrStatus definitely indicates a failure, a success HRESULT only indicates + * that the first part of assembly unloading succeeded. + */ + HRESULT AssemblyUnloadStarted( + [in] AssemblyID assemblyId); + + HRESULT AssemblyUnloadFinished( + [in] AssemblyID assemblyId, + [in] HRESULT hrStatus); + + + /* + * + * MODULE EVENTS + * + */ + + /* + * Called when a module load has begun and ended. The ID is not valid + * for any information request until the Finished event is called. + * + * Some parts of module loading may take place lazily at some time + * after the Finished callback. Therefore, while a failure HRESULT in + * hrStatus definitely indicates a failure, a success HRESULT only indicates + * that the first part of module loading succeeded. + * + * Note that when a module load is reported as finished this indicates + * that the load has completed but it has not yet returned to the caller. + * This is the opportunity for the profiler to note that other notifications regarding + * this module may start coming afterwards however internal safeguards + * protecting the runtime from recursive loading are still present and so it is + * a bad time to begin inquiries on this module. The notification is informational + * only. + * + * Note: ModuleLoadFinished is a reasonable time to interrogate MetaData via API's + * like GetModuleMetadata, however APIs that create (e.g. ClassID's and FunctionID's) + * are not safe to use here. Profiler writers are advised to stay in the universe of + * tokens. + * + */ + HRESULT ModuleLoadStarted( + [in] ModuleID moduleId); + + HRESULT ModuleLoadFinished( + [in] ModuleID moduleId, + [in] HRESULT hrStatus); + + /* + * Called before and after a module is unloaded. + * The ID is no longer valid after the Started event returns. + * + * Some parts of module unloading may take place lazily at some time + * after the Finished callback. Therefore, while a failure HRESULT in + * hrStatus definitely indicates a failure, a success HRESULT only indicates + * that the first part of module unloading succeeded. + */ + HRESULT ModuleUnloadStarted( + [in] ModuleID moduleId); + + HRESULT ModuleUnloadFinished( + [in] ModuleID moduleId, + [in] HRESULT hrStatus); + + /* + * A module can get loaded through legacy means (ie: IAT or LoadLibrary) or + * through a metadata reference. The CLR loader therefore has many code + * paths for determining what assembly a module lives in. It is therefore + * possible that after a ModuleLoadFinished event, the module does not + * know what assembly it is in and getting the parent AssemblyID is not possible. + * This event is fired when the module is officially attached to its parent + * assembly. Calling GetModuleInfo after this function is called will return the + * proper parent assembly. + */ + HRESULT ModuleAttachedToAssembly( + [in] ModuleID moduleId, + [in] AssemblyID AssemblyId); + + + /* + * + * CLASS EVENTS + * + */ + + /* + * Called when a class load has begun and ended. The ID is not valid + * for any information request until the Finished event is called. + * + * Some parts of class loading may take place lazily at some time + * after the Finished callback. Therefore, while a failure HRESULT in + * hrStatus definitely indicates a failure, a success HRESULT only indicates + * that the first part of class loading succeeded. + * + * Note that when a class load is reported as finished this indicates + * that the load has completed but it has not yet returned to the caller. + * This is the opportunity for the profiler to note that other notifications regarding + * this class may start coming afterwards however internal safeguards + * protecting the runtime from recursive loading are still present and so it is + * a bad time to begin inquiries on this class. The notification is informational + * only. + * + */ + HRESULT ClassLoadStarted( + [in] ClassID classId); + + HRESULT ClassLoadFinished( + [in] ClassID classId, + [in] HRESULT hrStatus); + + /* + * Called before and after a class is unloaded. + * The ID is no longer valid after the Started event returns. + * + * Some parts of class unloading may take place lazily at some time + * after the Finished callback. Therefore, while a failure HRESULT in + * hrStatus definitely indicates a failure, a success HRESULT only indicates + * that the first part of class unloading succeeded. + */ + HRESULT ClassUnloadStarted( + [in] ClassID classId); + + HRESULT ClassUnloadFinished( + [in] ClassID classId, + [in] HRESULT hrStatus); + + /* + * + * JIT EVENTS + * + */ + + /* + * The CLR calls FunctionUnloadStarted to notify the code + * profiler that a function is being unloaded. After returning from this + * call, the FunctionID is no longer valid. + */ + HRESULT FunctionUnloadStarted( + [in] FunctionID functionId); + + + /* + * The CLR calls JITCompilationStarted to notify the code + * profiler that the JIT compiler is starting to compile a function. + * + * The fIsSafeToBlock argument tells the profiler whether or not blocking + * will affect the operation of the runtime. If true, blocking may cause + * the runtime to wait for the calling thread to return from this callback. + * Although this will not harm the runtime, it will skew the profiling + * results. + * + * NOTE: It is possible to receive more than one JITCompilationStarted/ + * JITCompilationFinished pair for each method. This is because of how + * the runtime handles class constructors: method A starts to be JIT'd, + * then realizes that the class ctor for class B needs to be run, so + * JIT's it and runs it, and while it's running makes a call to original + * method A, which causes it to be JIT'd again, and causes the original + * (incomplete) JIT'ing of A to be aborted. However, both attempts to + * JIT A are reported with JIT compilation events. If the profiler is + * going to replace IL code for this method with SetILFunctionBody, then + * it must do so for both JITCompilationStarted events, but may use the + * same IL block for both. + * + * NOTE: A profiler should be tolerant of the sequence of JIT callbacks + * received in cases where two threads are simultaneously calling a + * method. For example, thread A receives JITCompilationStarted. + * But before thread A receives JITCompilationFinished, thread B + * receives FunctionEnter with the functionId from thread A's + * JITCompilationStarted callback. It may appear that functionId should + * not yet be valid because JITCompilationFinished had not yet been + * received. But it is indeed valid in such a case. + */ + HRESULT JITCompilationStarted( + [in] FunctionID functionId, + [in] BOOL fIsSafeToBlock); + + /* + * The CLR calls JITCompilationFinished to notify the code + * profiler that the JIT compiler has finished compiling a function. + * + * The fIsSafeToBlock argument tells the profiler whether or not blocking + * will affect the operation of the runtime. If true, blocking may cause + * the runtime to wait for the calling thread to return from this callback. + * Although this will not harm the runtime, it will skew the profiling + * results. + * + * The FunctionID is now valid in ICorProfilerInfo APIs. + * + * The hrStatus provides the success or failure of the operation + */ + HRESULT JITCompilationFinished( + [in] FunctionID functionId, + [in] HRESULT hrStatus, + [in] BOOL fIsSafeToBlock); + + /* + * V2 MIGRATION WARNING: DOES NOT ALWAYS OCCUR + * The JITCachedFunctionSearchStarted/Finished callbacks + * will now occur only for some functions in regular NGEN images; + * only profiler-optimized NGEN images will generate callbacks for + * all functions in the image. Profilers which do not use these callbacks + * to force a function to be JIT-compiled should move to using a lazy + * strategy for gathering function information. + * + * This notifies the profiler when a search for a prejitted function is + * starting. + * + * functionId: the function for which the search is being performed. + * bUseCachedFunction: if true, the EE uses the cached function (if applicable) + * if false, the EE jits the function instead of + * using a pre-jitted version. + * + * NOTE: Profilers should be tolerant of cases where multiple threads of + * a profiled app are calling the same method simultaneously. For example, + * thread A may receive JITCachedFunctionSearchStarted (and the + * profiler sets *pbUseCachedFunction=FALSE to force a JIT), thread A + * then receives JITCompilationStarted/JITCompilationFinished, then + * thread B receives another JITCachedFunctionSearchStarted for the same + * method. It might appear odd to receive this final callback, since the + * profiler already stated its intention to JIT the method. But this is + * occurring because the CLR in thread B decided to send this callback + * before thread A responded to JITCachedFunctionSearchStarted + * with *pbUseCachedFunction=FALSE, and the thread B callback + * hadn't actually been sent until now due how the threads + * happened to be scheduled. In such cases where the profiler + * receives duplicate JITCachedFunctionSearchStarted callbacks for + * the same functionId, the profiler should be certain to set + * *pbUseCachedFunction to the same value from this callback + * when it is called multiple times with the same functionId. + */ + HRESULT JITCachedFunctionSearchStarted( + [in] FunctionID functionId, + [out] BOOL *pbUseCachedFunction); + + /* + * V2 MIGRATION WARNING: DOES NOT ALWAYS OCCUR + * The JITCachedFunctionSearchStarted/Finished callbacks + * will now occur only for some functions in regular NGEN images; + * only profiler-optimized NGEN images will generate callbacks for + * all functions in the image. Profilers which do not use these callbacks + * to force a function to be JIT-compiled should move to using a lazy + * strategy for gathering function information. + * + * This notifies the profiler when a search for a cached function has been + * performed. + * + * functionId: the function for which the search has been performed. + * result: the result of the search. There are two possible results: + * COR_PRF_CACHED_FUNCTION_FOUND + * COR_PRF_CACHED_FUNCTION_NOT_FOUND + * + */ + HRESULT JITCachedFunctionSearchFinished( + [in] FunctionID functionId, + [in] COR_PRF_JIT_CACHE result); + + /* + * The CLR calls JITFunctionPitched to notify the profiler + * that a jitted function was removed from memory. If the pitched + * function is called in the future, the profiler will receive new + * JIT compilation events as it is re-jitted. + * + * Currently the CLR JIT does not pitch functions, so this callback + * will not be received. + * + * NOTE: the FunctionID is not valid until it is re-jitted. When it is + * re-jitted, it will use the same FunctionID value. + */ + HRESULT JITFunctionPitched( + [in] FunctionID functionId); + + /* + * The CLR calls JITInlining to notify the profiler that the jitter + * is about to inline calleeId into callerId. Set pfShouldInline to FALSE + * to prevent the callee from being inlined into the caller, and set to + * TRUE to allow the inline to occur. + * + * NOTE: Inlined functions do not provide Enter/Leave events, so if you desire + * an accurate callgraph, you should set FALSE. Be aware that + * setting FALSE will affect performance, since inlining typically + * increases speed and reduces separate jitting events for the inlined + * method. + * + * NOTE: It is also possible to globally disable inlining by setting the + * COR_PRF_DISABLE_INLINING flag. + */ + HRESULT JITInlining( + [in] FunctionID callerId, + [in] FunctionID calleeId, + [out] BOOL *pfShouldInline); + + /* + * + * THREAD EVENTS + * + */ + + /* + * The CLR calls ThreadCreated to notify the code profiler + * that a thread has been created. The ThreadID is valid immediately. + */ + HRESULT ThreadCreated( + [in] ThreadID threadId); + + /* + * The CLR calls ThreadDestroyed to notify the code profiler + * that a thread has been destroyed. The ThreadID is no longer valid + * at the time of this call. + */ + HRESULT ThreadDestroyed( + [in] ThreadID threadId); + + /* + * The CLR calls ThreadAssignedToOSThread to tell the profiler + * that a managed thread is being implemented via a particualr OS thread. + * This callback exists so that the profiler can maintain an accurate + * OS to Managed thread mapping across fibres. + */ + HRESULT ThreadAssignedToOSThread( + [in] ThreadID managedThreadId, + [in] DWORD osThreadId); + + /* + * + * REMOTING EVENTS + * + */ + + // + // Client-side events + // + + /* + * NOTE: each of the following pairs of callbacks will occur on the same + * thread + * RemotingClientInvocationStarted & RemotingClientSendingMessage + * RemotingClientReceivingReply & RemotingClientInvocationFinished + * RemotingServerInvocationReturned & RemotingServerSendingReply + * + * There are a few issues with the remoting callbacks that should be outlined. + * First, remoting function execution is not reflected by the profiler API, so + * the notifications for functions that are called from the client and executed + * to the server are not properly received. The actual invocation happens via a + * proxy object. That creates the illusion to the profiler that certain + * functions get jit-compiled but they never get used. Second, the profiler does + * not receive accurate notifications for asynchronous remoting events. + */ + + /* + * The CLR calls RemotingClientInvocationStarted to notify the profiler that + * a remoting call has begun. This event is the same for synchronous and + * asynchronous calls. + */ + HRESULT RemotingClientInvocationStarted(); + + /* + * The CLR calls RemotingClientSendingMessage to notify the profiler that + * a remoting call is requiring the the caller to send an invocation request through + * a remoting channel. + * + * pCookie - if remoting GUID cookies are active, this value will correspond with the + * the value provided in RemotingServerReceivingMessage, if the channel + * succeeds in transmitting the message, and if GUID cookies are active on + * the server-side process. This allows easy pairing of remoting calls, + * and the creation of a logical call stack. + * fIsAsync - is true if the call is asynchronous. + */ + HRESULT RemotingClientSendingMessage( + [in] GUID *pCookie, + [in] BOOL fIsAsync); + + /* + * The CLR calls RemotingClientReceivingReply to notify the profiler that + * the server-side portion of a remoting call has completed and that the client is + * now receiving and about to process the reply. + * + * pCookie - if remoting GUID cookies are active, this value will correspond with the + * the value provided in RemotingServerSendingReply, if the channel + * succeeds in transmitting the message, and if GUID cookies are active on + * the server-side process. This allows easy pairing of remoting calls. + * fIsAsync - is true if the call is asynchronous. + */ + HRESULT RemotingClientReceivingReply( + [in] GUID *pCookie, + [in] BOOL fIsAsync); + + /* + * The CLR calls RemotingClientInvocationFinished to notify the profiler that + * a remoting invocation has run to completion on the client side. If the call was + * synchronous, this means that it has also run to completion on the server side. If + * the call was asynchronous, a reply may still be expected when the call is handled. + * If the call is asynchronous, and a reply is expected, then the reply will occur in + * the form of a call to RemotingClientReceivingReply and an additional call to + * RemotingClientInvocationFinished to indicate the required secondary processing of + * an asynchronous call. + */ + HRESULT RemotingClientInvocationFinished(); + + // + // Server-side events + // + + /* + * The CLR calls RemotingServerReceivingMessage to notify the profiler that + * the process has received a remote method invocation (or activation) request. If + * the message request is asynchronous, then the request may be serviced by any + * arbitrary thread. + * + * pCookie - if remoting GUID cookies are active, this value will correspond with the + * the value provided in RemotingClientSendingMessage, if the channel + * succeeds in transmitting the message, and if GUID cookies are active on + * the client-side process. This allows easy pairing of remoting calls. + * fIsAsync - is true if the call is asynchronous. + */ + HRESULT RemotingServerReceivingMessage( + [in] GUID *pCookie, + [in] BOOL fIsAsync); + + /* + * The CLR calls RemotingServerInvocationStarted to notify the profiler that + * the process is invoking a method due to a remote method invocation request. + */ + HRESULT RemotingServerInvocationStarted(); + + /* + * The CLR calls RemotingServerInvocationReturned to notify the profiler that + * the process has finished invoking a method due to a remote method invocation request. + */ + HRESULT RemotingServerInvocationReturned(); + + /* + * The CLR calls RemotingServerSendingReply to notify the profiler that + * the process has finished processing a remote method invocation request and is + * about to transmit the reply through a channel. + * + * pCookie - if remoting GUID cookies are active, this value will correspond with the + * the value provided in RemotingClientReceivingReply, if the channel + * succeeds in transmitting the message, and if GUID cookies are active on + * the client-side process. This allows easy pairing of remoting calls. + * fIsAsync - is true if the call is asynchronous. + */ + HRESULT RemotingServerSendingReply( + [in] GUID *pCookie, + [in] BOOL fIsAsync); + + /* + * + * TRANSITION EVENTS + * + */ + + /* + * The CLR calls UnmanagedToManagedTransition to notify the + * code profiler that a transition from unmanaged code to managed code has + * occurred. functionId is always the ID of the callee, and reason + * indicates whether the transition was due to a call into managed code from + * unmanaged, or a return from an unmanaged function called by a managed one. + * + * Note that if the reason is COR_PRF_TRANSITION_RETURN and the functionId is + * non-NULL, then the functionId is that of the unmanaged function, and will + * never have been jitted. Unmanaged functions still have some basic + * information associated with them, such as a name, and some metadata. + * + * Note that if the reason is COR_PRF_TRANSITION_RETURN and the callee was + * a PInvoke call indirect, then the runtime does not know the destination + * of the call and functionId will be NULL. + * + * Note that if the reason is COR_PRF_TRANSITION_CALL then it may be possible + * that the callee has not yet been JIT-compiled. + */ + HRESULT UnmanagedToManagedTransition( + [in] FunctionID functionId, + [in] COR_PRF_TRANSITION_REASON reason); + + + /* + * The CLR calls ManagedToUnmanagedTransition to notify the + * code profiler that a transition from managed code to unmanaged code has + * occurred. functionId is always the ID of the callee, and reason + * indicates whether the transition was due to a call into unmanaged code from + * managed, or a return from an managed function called by an unmanaged one. + * + * Note that if the reason is COR_PRF_TRANSITION_CALL, then the functionId + * is that of the unmanaged function, and will never have been jitted. + * Unmanaged functions still have some basic information associated with + * them, such as a name, and some metadata. + * + * Note that if the reason is COR_PRF_TRANSITION_CALL and the callee is + * a PInvoke call indirect, then the runtime does not know the destination + * of the call and functionId will be NULL. + */ + HRESULT ManagedToUnmanagedTransition( + [in] FunctionID functionId, + [in] COR_PRF_TRANSITION_REASON reason); + + + /* + * + * RUNTIME SUSPENSION EVENTS + * + */ + + /* + * The CLR calls RuntimeSuspendStarted to notify the code profiler + * that the runtime is about to suspend all of the runtime threads. + * All runtime threads that are in unmanaged code are permitted to continue + * running until they try to re-enter the runtime, at which point they will + * also suspend until the runtime resumes. This also applies to new threads + * that enter the runtime. All threads within the runtime are either + * suspended immediately if they are in interruptible code, or asked to + * suspend when they do reach interruptible code. + * + * suspendReason make be any of the following values: + * COR_PRF_SUSPEND_FOR_GC + * the runtime is suspending to service a GC request. The GC-related + * callbacks will occur between the RuntimeSuspendFinished and + * RuntimeResumeStarted events. + * COR_PRF_SUSPEND_FOR_CODE_PITCHING + * the runtime is suspending so that code pitching may occur. This + * only occurs when the EJit is active with code pitching enabled. + * Code pitching callbacks will occur between the + * RuntimeSuspendFinished and RuntimeResumeStarted events. + * COR_PRF_SUSPEND_FOR_APPDOMAIN_SHUTDOWN + * the runtime is suspending so that an AppDomain can be shut down. + * While the runtime is suspended, the runtime will determine which + * threads are in the AppDomain that is being shut down, set them to + * abort when they resume, and then resumes the runtime. There are + * no AppDomain-specific callbacks during this suspension. + * COR_PRF_SUSPEND_FOR_SHUTDOWN + * the runtime is shutting down, and it must suspend all threads to + * complete the operation. + * COR_PRF_SUSPEND_FOR_GC_PREP + * the runtime is preparing for a GC. + * COR_PRF_SUSPEND_FOR_INPROC_DEBUGGER + * the runtime is suspending for in-process debugging. + * COR_PRF_SUSPEND_OTHER + * the runtime is suspending for a reason other than those above. + */ + HRESULT RuntimeSuspendStarted( + [in] COR_PRF_SUSPEND_REASON suspendReason); + + /* + * The CLR calls RuntimeSuspendFinished to notify the code profiler + * that the runtime has suspended all threads needed for a runtime + * suspension. Note that not all runtime threads are required to be + * suspended, as described in the comment for RuntimeSuspendStarted. + * + * NOTE: It is guaranteed that this event will occur on the same ThreadID + * as RuntimeSuspendStarted occurred on. + */ + HRESULT RuntimeSuspendFinished(); + + /* + * The CLR calls RuntimeSuspendAborted to notify the code profiler + * that the runtime is aborting the runtime suspension that was occurring. + * This may occur if two threads simultaneously attempt to suspend the + * runtime. + * + * NOTE: It is guaranteed that this event will occur on the same ThreadID + * as the RuntimeSuspendStarted occurred on, and that only one of + * RuntimeSuspendFinished and RuntimeSuspendAborted may occur on a single + * thread following a RuntimeSuspendStarted event. + */ + HRESULT RuntimeSuspendAborted(); + + /* + * The CLR calls RuntimeResumeStarted to notify the code profiler + * that the runtime is about to resume all of the runtime threads. + */ + HRESULT RuntimeResumeStarted(); + + /* + * The CLR calls RuntimeResumeFinished to notify the code profiler + * that the runtime has finished resuming all of it's threads and is now + * back in normal operation. + * + * NOTE: It is *NOT* guaranteed that this event will occur on the same + * ThreadID as the RuntimeSuspendStarted occurred on, but is guaranteed + * to occur on the same ThreadID as the RuntimeResumeStarted occurred on. + */ + HRESULT RuntimeResumeFinished(); + + /* + * The CLR calls RuntimeThreadSuspended to notify the code profiler + * that a particular thread has been suspended. + * + * This notification may occur any time between the RuntimeSuspendStarted + * and the associated RuntimeResumeStarted. Notifications that occur + * between RuntimeSuspendFinished and RuntimeResumeStarted are for + * threads that had been running in unmanaged code and were suspended + * upon entry to the runtime. + */ + HRESULT RuntimeThreadSuspended( + [in] ThreadID threadId); + + /* + * The CLR calls RuntimeThreadResumed to notify the code profiler + * that a particular thread has been resumed after being suspended due to + * a runtime suspension. + */ + HRESULT RuntimeThreadResumed( + [in] ThreadID threadId); + + /* + * + * GC EVENTS + * + * NOTE: All of these callbacks (except ObjectAllocated) are made while the + * runtime is suspended, so none of the ObjectID values can change until + * the runtime resumes and another GC occurs. + * + * NOTE: The profiler will receive GC-related events (except ObjectAllocated) + * when the profiler has been suspended for COR_PRF_SUSPEND_FOR_GC *except* + * for one special case. When the runtime is shutting down, there is a + * stage where it is suspended for COR_PRF_SUSPEND_FOR_SHUTDOWN reason and + * is never resumed. But after this suspension a garbage collection may + * occur without a COR_PRF_SUSPEND_FOR_GC suspension notification, and + * the profiler will thus receive GC-related callbacks. + * + * NOTE: All of these callbacks (except ObjectAllocated) may be called more than + * once during the same GC. These calls should be considered multiple parts of + * one long report; the profiler should simply aggregate the information provided + * in all of them. + */ + + /* + * The CLR calls MovedReferences with information about + * object references that moved as a result of garbage collection. + * + * cMovedObjectIDRanges is a count of the number of ObjectID ranges that + * were moved. + * oldObjectIDRangeStart is an array of elements, each of which is the start + * value of a range of ObjectID values before being moved. + * newObjectIDRangeStart is an array of elements, each of which is the start + * value of a range of ObjectID values after being moved. + * cObjectIDRangeLength is an array of elements, each of which states the + * size of the moved ObjectID value range. + * + * The last three arguments of this function are parallel arrays. + * + * In other words, if an ObjectID value lies within the range + * oldObjectIDRangeStart[i] <= ObjectID < oldObjectIDRangeStart[i] + cObjectIDRangeLength[i] + * for 0 <= i < cMovedObjectIDRanges, then the ObjectID value has changed to + * ObjectID - oldObjectIDRangeStart[i] + newObjectIDRangeStart[i] + * + * NOTE: None of the objectIDs returned by MovedReferences are valid during the callback + * itself, as the GC may be in the middle of moving objects from old to new. Thus profilers + * should not attempt to inspect objects during a MovedReferences call. At + * GarbageCollectionFinished, all objects have been moved to their new locations, and + * inspection may be done. + * + * THIS CALLBACK IS OBSOLETE. It reports ranges for objects >4GB as ULONG_MAX + * on 64-bit platforms. Use ICorProfilerCallback4::MovedReferences2 instead. + */ + HRESULT MovedReferences( + [in] ULONG cMovedObjectIDRanges, + [in, size_is(cMovedObjectIDRanges)] ObjectID oldObjectIDRangeStart[] , + [in, size_is(cMovedObjectIDRanges)] ObjectID newObjectIDRangeStart[] , + [in, size_is(cMovedObjectIDRanges)] ULONG cObjectIDRangeLength[] ); + + /* + * The CLR calls ObjectAllocated to notify the code profiler + * an object was allocated on the heap. This notification does not fire + * for allocations from the stack, nor from unmanaged memory. + * + * It is possible to receive a classId that corresponds to a regular class + * that has not been loaded yet. The profiler will receive a class load + * callback for that class immediately after the object creation callback. + */ + HRESULT ObjectAllocated( + [in] ObjectID objectId, + [in] ClassID classId); + + /* + * The CLR calls ObjectsAllocatedByClass to notify the code + * profiler about the number of objects of a particular class that were + * allocated since the previous garbage collection. The classes and the + * counts are passed in parallel arrays. (Classes for which no instances + * have been allocated since the previous GC are omitted entirely.) + * + * NOTE: This callback will not report objects allocated in the large + * object heap. + * + * NOTE: The numbers here are only estimates. Use ObjectAllocated for + * exact counts. + */ + HRESULT ObjectsAllocatedByClass( + [in] ULONG cClassCount, + [in, size_is(cClassCount)] ClassID classIds[] , + [in, size_is(cClassCount)] ULONG cObjects[] ); + + /* + * The CLR calls ObjectReferences to provide information + * about objects in memory referenced by a given object. This function + * is called for each object remaining in the GC heap after a collection + * has completed. If the profiler returns an error from this callback, + * the profiling services will discontinue invoking this callback until the + * next GC. This callback can be used in conjunction with the + * RootReferences callback to create a complete object reference graph for + * the runtime. + * + * NOTE: The CLR will ensure that each object reference is reported only + * once by this function. + * + * NOTE: None of the objectIDs returned by ObjectReferences are valid during the callback + * itself, as the GC may be in the middle of moving objects from old to new. Thus profilers + * should not attempt to inspect objects during an ObjectReferences call. At + * GarbageCollectionFinished, all objects have been moved to their new locations, and + * inspection may be done. + */ + HRESULT ObjectReferences( + [in] ObjectID objectId, + [in] ClassID classId, + [in] ULONG cObjectRefs, + [in, size_is(cObjectRefs)] ObjectID objectRefIds[] ); + + /* + * The CLR calls RootReferences with information about root + * references after a garbage collection has occurred. Static object + * references and references to objects on a stack are co-mingled in the + * arrays. + * + * NOTE: It is possible to get NULL ObjectIDs in the RootReferences callback. + * For example, all object references declared on the stack are treated as + * roots by the GC, and will always be reported. + * + * NOTE: None of the objectIDs returned by RootReferences are valid during the callback + * itself, as the GC may be in the middle of moving objects from old to new. Thus profilers + * should not attempt to inspect objects during a RootReferences call. At + * GarbageCollectionFinished, all objects have been moved to their new locations, and + * inspection may be done. + */ + HRESULT RootReferences( + [in] ULONG cRootRefs, + [in, size_is(cRootRefs)] ObjectID rootRefIds[] ); + + + /* + * + * EXCEPTION EVENTS + * + */ + + // + // Exception creation + // + + /* + * The CLR calls ExceptionThrown to notify the code + * profiler that an exception has been thrown. + * + * NOTE: This function is only called if the exception reaches + * managed code. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + */ + HRESULT ExceptionThrown( + [in] ObjectID thrownObjectId); + + // + // Search phase + // + + /* + * The CLR calls ExceptionSearchFunctionEnter to notify the profiler + * that the search phase of exception handling has entered a function. + */ + HRESULT ExceptionSearchFunctionEnter( + [in] FunctionID functionId); + + /* + * The CLR calls ExceptionSearchFunctionLeave to notify the profiler + * that the search phase of exception handling has left a function. + */ + HRESULT ExceptionSearchFunctionLeave(); + + /* + * The CLR will call ExceptionSearchFilterEnter just before excecuting + * a user filter. The functionID is that of the function containing the filter. + */ + HRESULT ExceptionSearchFilterEnter( + [in] FunctionID functionId); + + /* + * The CLR will call ExceptionSearchFilterLeave immediately after + * executing a user filter. + */ + HRESULT ExceptionSearchFilterLeave(); + + /* + * The CLR will call ExceptionSearchCatcherFound when the search + * phase of exception handling has located a handler for the exception that + * was thrown. + */ + HRESULT ExceptionSearchCatcherFound( + [in] FunctionID functionId); + + /* + * DEPRECATED. It is the job of the unmanaged profiler to detect OS + * handling of exceptions. + */ + HRESULT ExceptionOSHandlerEnter( + [in] UINT_PTR __unused); + + /* + * DEPRECATED. It is the job of the unmanaged profiler to detect OS + * handling of exceptions. + */ + HRESULT ExceptionOSHandlerLeave( + [in] UINT_PTR __unused); + + // + // Unwind phase + // + + /* + * The CLR calls ExceptionUnwindFunctionEnter to notify the profiler + * that the unwind phase of exception handling has entered a function. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + */ + HRESULT ExceptionUnwindFunctionEnter( + [in] FunctionID functionId); + + /* + * The CLR calls ExceptionUnwindFunctionLeave to notify the profiler + * that the unwind phase of exception handling has left a function. The + * function instance and it's stack data has now been removed from the stack. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + */ + HRESULT ExceptionUnwindFunctionLeave(); + + /* + * The CLR calls ExceptionUnwindFinallyEnter to notify the profiler + * that the unwind phase of exception is entering a finally clause contained + * in the specified function. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + */ + HRESULT ExceptionUnwindFinallyEnter( + [in] FunctionID functionId); + + /* + * The CLR calls ExceptionUnwindFinallyLeave to notify the profiler + * that the unwind phase of exception is leaving a finally clause. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + */ + HRESULT ExceptionUnwindFinallyLeave(); + + /* + * The CLR calls this function just before passing control to + * the appropriate catch block. Note that this is called only if the + * catch point is in JIT'ed code. An exception that is caught in + * unmanaged code, or in the internal code of the CLR will + * not generate this notification. The ObjectID is passed again since + * a GC could have moved the object since the ExceptionThrown + * notification. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + */ + HRESULT ExceptionCatcherEnter( + [in] FunctionID functionId, + [in] ObjectID objectId); + + /* + * The CLR calls ExceptionCatcherLeave when the runtime leaves + * the catcher's code. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + */ + HRESULT ExceptionCatcherLeave(); + + /* + * CLR<->COM interop vtable creation/destruction. + */ + + /* + * The CLR calls this function when an CLR<->COM interop vtable + * for a particular IID and for a particular class has been created. + * This provides the ClassID of the class for which this vtable has been + * created, the IID it implements, the start of the vtable and how many + * slots are in it. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + * + * NOTE: It is possible to receive a NULL GUID if the interface is + * internal only. + */ + HRESULT COMClassicVTableCreated( + [in] ClassID wrappedClassId, + [in] REFGUID implementedIID, + [in] void *pVTable, + [in] ULONG cSlots); + + /* + * The CLR calls this function when a CLR<->COM interop vtable is + * being destroyed. Provided are the ClassID, IID and vtable pointer for + * the destroyed vtable. + * + * NOTE: The profiler should not block here, since the stack may not be in a + * GC-friendly state and so preemptive GC cannot be enabled. If the + * profiler blocks here and a GC is attempted, the runtime will block + * until this callback returns. Also, the profiler may NOT call into + * managed code or in any way cause a managed memory allocation. + * + * NOTE: It is possible to receive a NULL GUID if the interface is + * internal only. + * + * NOTE: This callback is likely never to occur, since the destruction of + * vtables occurs very close to Shutdown. + */ + HRESULT COMClassicVTableDestroyed( + [in] ClassID wrappedClassId, + [in] REFGUID implementedIID, + [in] void *pVTable); + + /* + * DEPRECATED. These callbacks are no longer delivered. + */ + HRESULT ExceptionCLRCatcherFound(); + + HRESULT ExceptionCLRCatcherExecute(); +} + +/* + * COR_PRF_GC_ROOT_KIND describes the kind of GC root exposed by + * the RootReferences2 callback. + */ + +typedef enum +{ + COR_PRF_GC_ROOT_STACK = 1, // Variables on the stack + COR_PRF_GC_ROOT_FINALIZER = 2, // Entry in the finalizer queue + COR_PRF_GC_ROOT_HANDLE = 3, // GC Handle + COR_PRF_GC_ROOT_OTHER = 0 //Misc. roots +} COR_PRF_GC_ROOT_KIND; + + +/* + * COR_PRF_GC_ROOT_FLAGS describes properties of a GC root + * exposed by the RootReferences callback. + */ + +typedef enum +{ + COR_PRF_GC_ROOT_PINNING = 0x1, // Prevents GC from moving the object + COR_PRF_GC_ROOT_WEAKREF = 0x2, // Does not prevent collection + COR_PRF_GC_ROOT_INTERIOR = 0x4, // Refers to a field of the object rather than the object itself + COR_PRF_GC_ROOT_REFCOUNTED = 0x8, // Whether it prevents collection depends on a refcount - if not, + // COR_PRF_GC_ROOT_WEAKREF will be set also +} COR_PRF_GC_ROOT_FLAGS; + + +/* + * COR_PRF_FINALIZER_FLAGS is used by FinalizableObjectQueued to describe + * the finalizer for the object. + */ + +typedef enum +{ + COR_PRF_FINALIZER_CRITICAL = 0x1 // Critical finalizer +} COR_PRF_FINALIZER_FLAGS; + + +/* + * COR_PRF_GC_GENERATION contains the numbers used to represent each GC generation + * in the GetGenerationBounds and GetObjectGeneration functions. + */ + +typedef enum +{ + COR_PRF_GC_GEN_0 = 0, + COR_PRF_GC_GEN_1 = 1, + COR_PRF_GC_GEN_2 = 2, + COR_PRF_GC_LARGE_OBJECT_HEAP = 3 +} COR_PRF_GC_GENERATION; + + +/* + * COR_PRF_GC_GENERATION_RANGE describes a range of memory in the GetGenerationBounds and GetObjectGeneration functions. + * Note that the rangeLength member is only guaranteed to be accurate if GetGenerationBounds or GetObjectGeneration are + * called from a GarbageCollectionStarted or GarbageCollectionFinished notification + */ +typedef struct COR_PRF_GC_GENERATION_RANGE +{ + COR_PRF_GC_GENERATION generation; // what generation the range of memory belongs to + ObjectID rangeStart; // the start of the range + UINT_PTR rangeLength; // the used length of the range + UINT_PTR rangeLengthReserved; // the amount of memory reserved for the range (including rangeLength) + +} COR_PRF_GC_GENERATION_RANGE; + + + +/* + * COR_PRF_CLAUSE_TYPE defines the various clause codes for the EX clauses + */ +typedef enum +{ + COR_PRF_CLAUSE_NONE = 0, // not a real clause (only used in error cases) + COR_PRF_CLAUSE_FILTER = 1, + COR_PRF_CLAUSE_CATCH = 2, + COR_PRF_CLAUSE_FINALLY = 3, +} COR_PRF_CLAUSE_TYPE; + +/* + * COR_PRF_EX_CLAUSE_INFO identifies a specific exception clause instance and its associated frame. + * When an exception notification is received, GetNotifiedExceptionClauseInfo() may be used to get the + * native address and frame information for the exception clause (catch/finally/filter) that is + * about to be run (ExceptionCatchEnter, ExceptionUnwindFinallyEnter, ExceptionFilterEnter) or has just + * been run (ExceptionCatchLeave, ExceptionUnwindFinallyLeave, ExceptionFilterLeave). + */ +typedef struct COR_PRF_EX_CLAUSE_INFO +{ + COR_PRF_CLAUSE_TYPE clauseType; // the type of clause we just entered or left + UINT_PTR programCounter; // the native entry point of the clause handler (e.g. EIP) + UINT_PTR framePointer; // the logical frame pointer (e.g. EBP) for that clause handler + UINT_PTR shadowStackPointer; // the shadow stack pointer (IA64 only, BSP) +} COR_PRF_EX_CLAUSE_INFO; + +/* + * COR_PRF_GC_REASON describes the reason for a given GC. + */ +typedef enum +{ + COR_PRF_GC_INDUCED = 1, // Induced by GC.Collect + COR_PRF_GC_OTHER = 0 // Anything else +} COR_PRF_GC_REASON; + +/* + * Bits from COR_PRF_MODULE_FLAGS are returned to the profiler in GetModuleInfo2's + * pdwModuleFlags output parameter. Some combinations of 2 or more flags are possible, + * though not all combinations are possible. + */ +typedef enum +{ + // The module was loaded from disk + COR_PRF_MODULE_DISK = 0x00000001, + + // The module had been generated via NGEN + COR_PRF_MODULE_NGEN = 0x00000002, + + // The module was created via methods in the Reflection.Emit namespace + COR_PRF_MODULE_DYNAMIC = 0x00000004, + + // The module's lifetime is managed by the garbage collector. + COR_PRF_MODULE_COLLECTIBLE = 0x00000008, + + // The module contains no metadata and is used strictly as a resource. The managed + // equivalent of this bit is the System.Reflection.Module.IsResource() method. + COR_PRF_MODULE_RESOURCE = 0x00000010, + + // The module's layout in memory is flat, as opposed to mapped. For modules that have + // this bit set, profilers that directly read information out of the PE header will + // need to be careful when interpreting RVAs present in the PE header. + COR_PRF_MODULE_FLAT_LAYOUT = 0x00000020, + + // The Windows Runtime content type flag is set in the metadata for this module's + // assembly + COR_PRF_MODULE_WINDOWS_RUNTIME = 0x00000040, +} COR_PRF_MODULE_FLAGS; +/* + * The ICorProfilerCallback2 interface is used by the CLR to notify a + * code profiler when events have occurred that the code profiler has registered + * an in interest in receiving. These are new callbacks implemented in V2.0 + * of the runtime. + * + * The methods implemented on this interface return S_OK on success, or E_FAIL + * on failure. + */ + +[ + object, + uuid(8A8CC829-CCF2-49fe-BBAE-0F022228071A), + pointer_default(unique), + local +] +interface ICorProfilerCallback2 : ICorProfilerCallback +{ + + /* + * + * THREAD EVENTS + * + */ + + /* + * The CLR calls ThreadNameChanged to notify the code profiler + * that a thread's name has changed. + * + * name is not NULL terminated. + * + */ + HRESULT ThreadNameChanged( + [in] ThreadID threadId, + [in] ULONG cchName, + [in, annotation("_In_reads_opt_(cchName)")] WCHAR name[]); + + /* + * + * GARBAGE COLLECTION EVENTS + * + */ + + /* + * The CLR calls GarbageCollectionStarted before beginning a + * garbage collection. All GC callbacks pertaining to this + * collection will occur between the GarbageCollectionStarted + * callback and the corresponding GarbageCollectionFinished + * callback. Corresponding GarbageCollectionStarted and + * GarbageCollectionFinished callbacks need not occur on the same thread. + * + * cGenerations indicates the total number of entries in + * the generationCollected array + * generationCollected is an array of booleans, indexed + * by COR_PRF_GC_GENERATIONS, indicating which + * generations are being collected in this collection + * reason indicates whether this GC was induced + * by the application calling GC.Collect(). + * + * NOTE: It is safe to inspect objects in their original locations + * during this callback. The GC will begin moving objects after + * the profiler returns from this callback. Therefore, after + * returning, the profiler should consider all ObjectIDs to be invalid + * until it receives a GarbageCollectionFinished callback. + */ + HRESULT GarbageCollectionStarted( + [in] int cGenerations, + [in, size_is(cGenerations)] BOOL generationCollected[], + [in] COR_PRF_GC_REASON reason); + + /* + * The CLR calls SurvivingReferences with information about + * object references that survived a garbage collection. + * + * Generally, the CLR calls SurvivingReferences for non-compacting garbage collections. + * For compacting garbage collections, MovedReferences is called instead. + * + * The exception to this rule is that the CLR always calls SurvivingReferences for objects + * in the large object heap, which is not compacted. + * + * Multiple calls to SurvivingReferences may be received during a particular + * garbage collection, due to limited internal buffering, multiple threads reporting + * in the case of server gc, and other reasons. + * In the case of multiple calls, the information is cumulative - all of the references + * reported in any SurvivingReferences call survive this collection. + * + * cSurvivingObjectIDRanges is a count of the number of ObjectID ranges that + * survived. + * objectIDRangeStart is an array of elements, each of which is the start + * value of a range of ObjectID values that survived the collection. + * cObjectIDRangeLength is an array of elements, each of which states the + * size of the surviving ObjectID value range. + * + * The last two arguments of this function are parallel arrays. + * + * In other words, if an ObjectID value lies within the range + * objectIDRangeStart[i] <= ObjectID < objectIDRangeStart[i] + cObjectIDRangeLength[i] + * for 0 <= i < cMovedObjectIDRanges, then the ObjectID has survived the collection + * + * THIS CALLBACK IS OBSOLETE. It reports ranges for objects >4GB as ULONG_MAX + * on 64-bit platforms. Use ICorProfilerCallback4::SurvivingReferences2 instead. + */ + HRESULT SurvivingReferences( + [in] ULONG cSurvivingObjectIDRanges, + [in, size_is(cSurvivingObjectIDRanges)] ObjectID objectIDRangeStart[] , + [in, size_is(cSurvivingObjectIDRanges)] ULONG cObjectIDRangeLength[] ); + /* + * The CLR calls GarbageCollectionFinished after a garbage + * collection has completed and all GC callbacks have been + * issued for it. + * + * NOTE: It is now safe to inspect objects in their + * final locations. + */ + HRESULT GarbageCollectionFinished(); + + /* + * The CLR calls FinalizeableObjectQueued to notify the code profiler + * that an object with a finalizer (destructor in C# parlance) has + * just been queued to the finalizer thread for execution of its + * Finalize method. + * + * finalizerFlags describes aspects of the finalizer, and takes its + * value from COR_PRF_FINALIZER_FLAGS. + * + */ + + HRESULT FinalizeableObjectQueued( + [in] DWORD finalizerFlags, + [in] ObjectID objectID); + + /* + * The CLR calls RootReferences2 with information about root + * references after a garbage collection has occurred. + * For each root reference in rootRefIds, there is information in + * rootClassifications to classify it. Depending on the classification, + * rootsIds may contain additional information. The information in + * rootKinds and rootFlags contains information about the location and + * properties of the reference. + * + * If the profiler implements ICorProfilerCallback2, both + * ICorProfilerCallback::RootReferences and ICorProfilerCallback2::RootReferences2 + * are called. As the information passed to RootReferences2 is a superset + * of the one passed to RootReferences, profilers will normally implement + * one or the other, but not both. + * + * If the root kind is STACK, the ID is the FunctionID of the + * function containing the variable. If the FunctionID is 0, the function + * is an unnamed function internal to the CLR. + * + * If the root kind is HANDLE, the ID is the GCHandleID. + * + * For the other root kinds, the ID is an opaque value and should + * be ignored. + * + * It's possible for entries in rootRefIds to be 0 - this just + * implies the corresponding root reference was null and thus did not + * refer to an object on the managed heap. + * + * NOTE: None of the objectIDs returned by RootReferences2 are valid during the callback + * itself, as the GC may be in the middle of moving objects from old to new. Thus profilers + * should not attempt to inspect objects during a RootReferences2 call. At + * GarbageCollectionFinished, all objects have been moved to their new locations, and + * inspection may be done. + */ + + HRESULT RootReferences2( + [in] ULONG cRootRefs, + [in, size_is(cRootRefs)] ObjectID rootRefIds[], + [in, size_is(cRootRefs)] COR_PRF_GC_ROOT_KIND rootKinds[], + [in, size_is(cRootRefs)] COR_PRF_GC_ROOT_FLAGS rootFlags[], + [in, size_is(cRootRefs)] UINT_PTR rootIds[]); + + /* + * The CLR calls HandleCreated when a gc handle has been created. + * + */ + + HRESULT HandleCreated( + [in] GCHandleID handleId, + [in] ObjectID initialObjectId); + + /* + * The CLR calls HandleDestroyed when a gc handle has been destroyed. + * + */ + + HRESULT HandleDestroyed( + [in] GCHandleID handleId); +} + +[ + object, + uuid(4FD2ED52-7731-4b8d-9469-03D2CC3086C5), + pointer_default(unique), + local +] +interface ICorProfilerCallback3 : ICorProfilerCallback2 +{ + HRESULT InitializeForAttach( + [in] IUnknown * pCorProfilerInfoUnk, + [in] void * pvClientData, + [in] UINT cbClientData); + + HRESULT ProfilerAttachComplete(); + + HRESULT ProfilerDetachSucceeded(); +}; + +[ + object, + uuid(7B63B2E3-107D-4d48-B2F6-F61E229470D2), + pointer_default(unique), + local +] +interface ICorProfilerCallback4 : ICorProfilerCallback3 +{ + /* + * Similar to JITCompilationStarted, except called when rejitting a method + */ + HRESULT ReJITCompilationStarted( + [in] FunctionID functionId, + [in] ReJITID rejitId, + [in] BOOL fIsSafeToBlock); + + /* + * This is called exactly once per method (which may represent more than + * one function id), to allow the code profiler to set alternate code + * generation flags or a new method body. + */ + HRESULT GetReJITParameters( + [in] ModuleID moduleId, + [in] mdMethodDef methodId, + [in] ICorProfilerFunctionControl *pFunctionControl); + + /* + * Similar to JITCompilationFinished, except called when rejitting a method + */ + HRESULT ReJITCompilationFinished( + [in] FunctionID functionId, + [in] ReJITID rejitId, + [in] HRESULT hrStatus, + [in] BOOL fIsSafeToBlock); + + /* + * This is called to report an error encountered while processing a ReJIT request. + * This may either be called from within the RequestReJIT call itself, or called after + * RequestReJIT returns, if the error was encountered later on. + */ + HRESULT ReJITError( + [in] ModuleID moduleId, + [in] mdMethodDef methodId, + [in] FunctionID functionId, + [in] HRESULT hrStatus); + + /* + * The CLR calls MovedReferences with information about + * object references that moved as a result of garbage collection. + * + * cMovedObjectIDRanges is a count of the number of ObjectID ranges that + * were moved. + * oldObjectIDRangeStart is an array of elements, each of which is the start + * value of a range of ObjectID values before being moved. + * newObjectIDRangeStart is an array of elements, each of which is the start + * value of a range of ObjectID values after being moved. + * cObjectIDRangeLength is an array of elements, each of which states the + * size of the moved ObjectID value range. + * + * The last three arguments of this function are parallel arrays. + * + * In other words, if an ObjectID value lies within the range + * oldObjectIDRangeStart[i] <= ObjectID < oldObjectIDRangeStart[i] + cObjectIDRangeLength[i] + * for 0 <= i < cMovedObjectIDRanges, then the ObjectID value has changed to + * ObjectID - oldObjectIDRangeStart[i] + newObjectIDRangeStart[i] + * + * NOTE: None of the objectIDs returned by MovedReferences are valid during the callback + * itself, as the GC may be in the middle of moving objects from old to new. Thus profilers + * should not attempt to inspect objects during a MovedReferences call. At + * GarbageCollectionFinished, all objects have been moved to their new locations, and + * inspection may be done. + * + * If the profiler implements ICorProfilerCallback4, ICorProfilerCallback4::MovedReferences2 + * is called first and ICorProfilerCallback::MovedReferences is called second but only if + * ICorProfilerCallback4::MovedReferences2 returned success. Profilers can return failure + * from ICorProfilerCallback4::MovedReferences2 to save some chattiness. + */ + HRESULT MovedReferences2( + [in] ULONG cMovedObjectIDRanges, + [in, size_is(cMovedObjectIDRanges)] ObjectID oldObjectIDRangeStart[] , + [in, size_is(cMovedObjectIDRanges)] ObjectID newObjectIDRangeStart[] , + [in, size_is(cMovedObjectIDRanges)] SIZE_T cObjectIDRangeLength[] ); + + /* + * The CLR calls SurvivingReferences with information about + * object references that survived a garbage collection. + * + * Generally, the CLR calls SurvivingReferences for non-compacting garbage collections. + * For compacting garbage collections, MovedReferences is called instead. + * + * The exception to this rule is that the CLR always calls SurvivingReferences for objects + * in the large object heap, which is not compacted. + * + * Multiple calls to SurvivingReferences may be received during a particular + * garbage collection, due to limited internal buffering, multiple threads reporting + * in the case of server gc, and other reasons. + * In the case of multiple calls, the information is cumulative - all of the references + * reported in any SurvivingReferences call survive this collection. + * + * cSurvivingObjectIDRanges is a count of the number of ObjectID ranges that + * survived. + * objectIDRangeStart is an array of elements, each of which is the start + * value of a range of ObjectID values that survived the collection. + * cObjectIDRangeLength is an array of elements, each of which states the + * size of the surviving ObjectID value range. + * + * The last two arguments of this function are parallel arrays. + * + * In other words, if an ObjectID value lies within the range + * objectIDRangeStart[i] <= ObjectID < objectIDRangeStart[i] + cObjectIDRangeLength[i] + * for 0 <= i < cMovedObjectIDRanges, then the ObjectID has survived the collection + * + * If the profiler implements ICorProfilerCallback4, ICorProfilerCallback4::SurvivingReferences2 + * is called first and ICorProfilerCallback2::SurvivingReferences is called second but only if + * ICorProfilerCallback4::SurvivingReferences2 returned success. Profilers can return failure + * from ICorProfilerCallback4::SurvivingReferences2 to save some chattiness. + */ + HRESULT SurvivingReferences2( + [in] ULONG cSurvivingObjectIDRanges, + [in, size_is(cSurvivingObjectIDRanges)] ObjectID objectIDRangeStart[] , + [in, size_is(cSurvivingObjectIDRanges)] SIZE_T cObjectIDRangeLength[] ); + +}; + + +[ + object, + uuid(8DFBA405-8C9F-45F8-BFFA-83B14CEF78B5), + pointer_default(unique), + local +] +interface ICorProfilerCallback5 : ICorProfilerCallback4 +{ + /* + * The CLR calls ConditionalWeakTableElementReferences with information + * about dependent handles after a garbage collection has occurred. + * + * For each root ID in rootIds, keyRefIds will contain the ObjectID for + * the primary element in the dependent handle pair, and valueRefIds will + * contain the ObjectID for the secondary element (keyRefIds[i] keeps + * valueRefIds[i] alive). + * + * NOTE: None of the objectIDs returned by ConditionalWeakTableElementReferences + * are valid during the callback itself, as the GC may be in the middle + * of moving objects from old to new. Thus profilers should not attempt + * to inspect objects during a ConditionalWeakTableElementReferences call. + * At GarbageCollectionFinished, all objects have been moved to their new + * locations, and inspection may be done. + */ + HRESULT ConditionalWeakTableElementReferences( + [in] ULONG cRootRefs, + [in, size_is(cRootRefs)] ObjectID keyRefIds[], + [in, size_is(cRootRefs)] ObjectID valueRefIds[], + [in, size_is(cRootRefs)] GCHandleID rootIds[]); +}; + + +[ + object, + uuid(FC13DF4B-4448-4F4F-950C-BA8D19D00C36), + pointer_default(unique), + local +] +interface ICorProfilerCallback6 : ICorProfilerCallback5 +{ + // Controlled by the COR_PRF_HIGH_ADD_ASSEMBLY_REFERENCES event mask flag. + // Notifies the profiler of a very early stage in the loading of an Assembly, where the CLR + // performs an assembly reference closure walk. This is useful ONLY if the profiler will need + // to modify the metadata of the Assembly to add AssemblyRefs (later, in ModuleLoadFinished). In + // such a case, the profiler should implement this callback as well, to inform the CLR that assembly references + // will be added once the module has loaded. This is useful to ensure that assembly sharing decisions + // made by the CLR during this early stage remain valid even though the profiler plans to modify the metadata + // assembly references later on. This can be used to avoid some instances where profiler metadata + // modifications can cause the SECURITY_E_INCOMPATIBLE_SHARE error to be thrown. + // + // The profiler uses the ICorProfilerAssemblyReferenceProvider provided to add assembly references + // to the CLR assembly reference closure walker. The ICorProfilerAssemblyReferenceProvider + // should only be used from within this callback. The profiler will still need to explicitly add assembly + // references via IMetaDataAssemblyEmit, from within the ModuleLoadFinished callback for the referencing assembly, + // even though the profiler implements this GetAssemblyReferences callback. This callback does not result in + // modified metadata; only in a modified assembly reference closure walk. + // + // The profiler should be prepared to receive duplicate calls to this callback for the same assembly, + // and should respond identically for each such duplicate call (by making the same set of + // ICorProfilerAssemblyReferenceProvider::AddAssemblyReference calls). + HRESULT GetAssemblyReferences( + [in, string] const WCHAR * wszAssemblyPath, + [in] ICorProfilerAssemblyReferenceProvider * pAsmRefProvider); +}; + + +[ + object, + uuid(F76A2DBA-1D52-4539-866C-2AA518F9EFC3), + pointer_default(unique), + local +] +interface ICorProfilerCallback7 : ICorProfilerCallback6 +{ + // This event is triggered whenever the symbol stream associated with an + // in-memory module is updated. Even when symbols are provided up-front in + // a call to the managed API Assembly.Load(byte[], byte[], ...) the runtime + // may not actually associate the symbolic data with the module until after + // the ModuleLoadFinished callback has occured. This event provides a later + // opportunity to collect symbols for such modules. + // + // This event is controlled by the COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED + // event mask flag. + // + // Note: This event is not currently raised for symbols implicitly created or + // modified via Reflection.Emit APIs. + HRESULT ModuleInMemorySymbolsUpdated(ModuleID moduleId); +} + + +/* + * COR_PRF_CODEGEN_FLAGS controls various flags and hooks for a specific + * method. A combination of COR_PRF_CODEGEN_FLAGS is provided by the + * profiler in its call to ICorProfilerFunctionControl::SetCodegenFlags() + * when rejitting a method. + */ +typedef enum +{ + COR_PRF_CODEGEN_DISABLE_INLINING = 0x0001, + COR_PRF_CODEGEN_DISABLE_ALL_OPTIMIZATIONS = 0x0002, +} COR_PRF_CODEGEN_FLAGS; + + +/* + * The CLR implements the ICorProfilerInfo interface. This interface is + * used by a code profiler to communicate with the CLR to control event + * monitoring and request information. The CLR passes an + * ICorProfilerInfo interface to each code profiler during initialization. + * + * A code profiler can call methods on the ICorProfilerInfo interface to get + * information about managed code being executed under the control of the CLR + * + * The ICorProfilerInfo interface implemented by the CLR uses the free + * threaded model. + * + * The methods implemented on this interface return S_OK on success, or E_FAIL + * on failure. + * + */ + +[ + object, + uuid(28B5557D-3F3F-48b4-90B2-5F9EEA2F6C48), + pointer_default(unique), + local +] +interface ICorProfilerInfo : IUnknown +{ + /* + * The code profiler calls GetClassFromObject to obtain the ClassID of an + * object given its ObjectID. + */ + HRESULT GetClassFromObject( + [in] ObjectID objectId, + [out] ClassID *pClassId); + + /* + * V2 MIGRATION WARNING - DOES NOT WORK FOR GENERIC TYPES + * + * This function will be removed in a future release, so + * use GetClassFromTokenAndTypeArgs for all types. + */ + HRESULT GetClassFromToken( + [in] ModuleID moduleId, + [in] mdTypeDef typeDef, + [out] ClassID *pClassId); + + /* + * V2 MIGRATION WARNING - WILL NOT WORK WITH .NET FRAMEWORK + * FUNCTIONS + * + * This function will be removed in a future release; use GetCodeInfo2 + * in all cases. + */ + HRESULT GetCodeInfo( + [in] FunctionID functionId, + [out] LPCBYTE *pStart, + [out] ULONG *pcSize); + + /* + * RECOMMENDATION: USE GetEventMask2 INSTEAD. WHILE THIS METHOD CONTINUES TO + * TO WORK, GetEventMask2 PROVIDES MORE FUNCTIONALITY. + * + * The code profiler calls GetEventMask to obtain the current event + * categories for which it is to receive event notifications from the COM+ + * Runtime. + */ + HRESULT GetEventMask( + [out] DWORD *pdwEvents); + + /* + * The code profiler calls GetFunctionFromIP to map an instruction pointer + * in managed code to a FunctionID. + */ + HRESULT GetFunctionFromIP( + [in] LPCBYTE ip, + [out] FunctionID *pFunctionId); + + /* + * V2 MIGRATION WARNING - WILL NOT WORK FOR GENERIC FUNCTIONS OR + * FUNCTIONS ON GENERIC TYPES + * + * This function will be removed in a future release, so use + * GetFunctionFromTokenAndTypeArgs for all functions. + */ + HRESULT GetFunctionFromToken( + [in] ModuleID moduleId, + [in] mdToken token, + [out] FunctionID *pFunctionId); + + /* + * The code profiler calls GetHandleFromThread to map a ThreadID to a Win32 + * thread handle. The profiler must call DuplicateHandle on the handle + * before using it. + */ + HRESULT GetHandleFromThread( + [in] ThreadID threadId, + [out] HANDLE *phThread); + + /* + * The code profiler calls GetObjectSize to obtain the size of an object. + * Note that types like arrays and strings may have a different size for each object. + * + * THIS API IS OBSOLETE. It does not work for objects >4GB on 64-bit platforms. + * Use ICorProfilerInfo4::GetObjectSize2 instead. + */ + HRESULT GetObjectSize( + [in] ObjectID objectId, + [out] ULONG *pcSize); + + /* + * This will return S_OK if the ClassID provided is an array class, and will + * fill out the information for any non-null out params. S_FALSE will be + * returned if the ClassID is not an array. + * + * classId : the ClassID to return information about + * pBaseElemType : the array's base element type + * pBaseClassId : the base ClassID if the element type == ELEMENT_TYPE_CLASS + * pcRank : the number of dimensions of the array + */ + HRESULT IsArrayClass( + [in] ClassID classId, + [out] CorElementType *pBaseElemType, + [out] ClassID *pBaseClassId, + [out] ULONG *pcRank); + + /* + * The code profiler calls GetThreadInfo to obtain the current Win32 thread ID for + * the specified thread. + */ + HRESULT GetThreadInfo( + [in] ThreadID threadId, + [out] DWORD *pdwWin32ThreadId); + + /* + * The code profiler calls GetCurrentThreadID to get the managed thread ID + * for the current thread. + * + * NOTE: GetCurrentThreadID may return CORPROF_E_NOT_MANAGED_THREAD if the + * current thread is an internal runtime thread, and the returned value of + * pThreadId will be NULL. + */ + HRESULT GetCurrentThreadID( + [out] ThreadID *pThreadId); + + /* + * V2 MIGRATION NOTE - More information is available for generic types + * from GetClassIDInfo2. + * + * Returns the parent module a class is defined in, along with the + * metadata token for the class. One can call GetModuleMetaData + * to obtain the metadata interface for a given module. The token + * can then be used to access the metadata for this class. + */ + HRESULT GetClassIDInfo( + [in] ClassID classId, + [out] ModuleID *pModuleId, + [out] mdTypeDef *pTypeDefToken); + + /* + * Return the parent class for a given function. Also return the metadata + * token which can be used to read the metadata. + * + * V2 MIGRATION WARNING - LESS INFORMATION FOR GENERIC CLASSES + * The ClassID of a function on a generic class may not be obtainable without + * more context about the use of the function. In this case, *pClassId will be 0; + * try using GetFunctionInfo2 with a COR_PRF_FRAME_INFO to give more context. + */ + HRESULT GetFunctionInfo( + [in] FunctionID functionId, + [out] ClassID *pClassId, + [out] ModuleID *pModuleId, + [out] mdToken *pToken); + + /* + * RECOMMENDATION: USE SetEventMask2 INSTEAD. WHILE THIS METHOD CONTINUES TO + * TO WORK, SetEventMask2 PROVIDES MORE FUNCTIONALITY. + * + * The code profiler calls SetEventMask to set the event categories for + * which it is set to receive notification from the CLR. + */ + HRESULT SetEventMask( + [in] DWORD dwEvents); + + /* + * The code profiler calls SetFunctionHooks to specify handlers + * for FunctionEnter, FunctionLeave, and FunctionTailcall. + * + * Note that only one set of callbacks may be active at a time. Thus, + * if a profiler calls SetEnterLeaveFunctionHooks, SetEnterLeaveFunctionHooks2 + * and SetEnterLeaveFunctionHooks3(WithInfo), then SetEnterLeaveFunctionHooks3(WithInfo) + * wins. SetEnterLeaveFunctionHooks2 takes precedence over SetEnterLeaveFunctionHooks + * when both are set. + * + * Each function pointer may be null to disable that callback. + * + * SetEnterLeaveFunctionHooks may only be called from the + * profiler's Initialize() callback. + */ + HRESULT SetEnterLeaveFunctionHooks( + [in] FunctionEnter *pFuncEnter, + [in] FunctionLeave *pFuncLeave, + [in] FunctionTailcall *pFuncTailcall); + + /* + * This is used for mapping FunctionIDs to alternative values that will be + * passed to the callbacks + */ + HRESULT SetFunctionIDMapper( + [in] FunctionIDMapper *pFunc); + + /* + * For a given function, retrieve the token value and an instance of the + * meta data interface which can be used against this token. + */ + HRESULT GetTokenAndMetaDataFromFunction( + [in] FunctionID functionId, + [in] REFIID riid, + [out] IUnknown **ppImport, + [out] mdToken *pToken); + + /* + * Retrieve information about a given module. + * + * When the module is loaded from disk, the name returned will be the filename; + * otherwise, the name will be the name from the metadata Module table (i.e., + * the same as the managed System.Reflection.Module.ScopeName). + * + * NOTE: While this function may be called as soon as the moduleId is alive, + * the AssemblyID of the containing assembly will not be available until the + * ModuleAttachedToAssembly callback. + * + * NOTE: More information is available by using ICorProfilerInfo3::GetModuleInfo2 instead. + */ + HRESULT GetModuleInfo( + [in] ModuleID moduleId, + [out] LPCBYTE *ppBaseLoadAddress, + [in] ULONG cchName, + [out] ULONG *pcchName, + [out, annotation("_Out_writes_to_(cchName, *pcchName)")] + WCHAR szName[] , + [out] AssemblyID *pAssemblyId); + + /* + * Get a metadata interface instance which maps to the given module. + * One may ask for the metadata to be opened in read+write mode, but + * this will result in slower metadata execution of the program, because + * changes made to the metadata cannot be optimized as they were from + * the compiler. + * + * NOTE: Some modules (such as resource modules) have no metadata. In + * those cases, GetModuleMetaData will return S_FALSE, and a NULL + * IUnknown. + * + * NOTE: the only values valid for dwOpenFlags are ofRead and ofWrite. + */ + HRESULT GetModuleMetaData( + [in] ModuleID moduleId, + [in] DWORD dwOpenFlags, + [in] REFIID riid, + [out] IUnknown **ppOut); + + /* + * Retrieve a pointer to the body of a method starting at it's header. + * A method is scoped by the module it lives in. Because this function + * is designed to give a tool access to IL before it has been loaded + * by the Runtime, it uses the metadata token of the method to find + * the instance desired. + * + * GetILFunctionBody can return CORPROF_E_FUNCTION_NOT_IL if the methodId + * points to a method without any IL (such as an abstract method, or a + * P/Invoke method). + */ + HRESULT GetILFunctionBody( + [in] ModuleID moduleId, + [in] mdMethodDef methodId, + [out] LPCBYTE *ppMethodHeader, + [out] ULONG *pcbMethodSize); + + /* + * IL method bodies must be located as RVA's to the loaded module, which + * means they come after the module within 4 gb. In order to make it + * easier for a tool to swap out the body of a method, this allocator + * will ensure memory is allocated within that range. + */ + HRESULT GetILFunctionBodyAllocator( + [in] ModuleID moduleId, + [out] IMethodMalloc **ppMalloc); + + /* + * Replaces the method body for a function in a module. This will replace + * the RVA of the method in the metadata to point to this new method body, + * and adjust any internal data structures as required. This function can + * only be called on those methods which have never been compiled by a JITTER. + * Please use the GetILFunctionAllocator to allocate space for the new method to + * ensure the buffer is compatible. + */ + HRESULT SetILFunctionBody( + [in] ModuleID moduleId, + [in] mdMethodDef methodid, + [in] LPCBYTE pbNewILMethodHeader); + + /* + * Retrieve app domain information given its id. + */ + HRESULT GetAppDomainInfo( + [in] AppDomainID appDomainId, + [in] ULONG cchName, + [out] ULONG *pcchName, + [out, annotation("_Out_writes_to_(cchName, *pcchName)")] + WCHAR szName[] , + [out] ProcessID *pProcessId); + + /* + * Retrieve information about an assembly given its ID. + */ + HRESULT GetAssemblyInfo( + [in] AssemblyID assemblyId, + [in] ULONG cchName, + [out] ULONG *pcchName, + [out, annotation("_Out_writes_to_(cchName, *pcchName)")] + WCHAR szName[] , + [out] AppDomainID *pAppDomainId, + [out] ModuleID *pModuleId); + + + /* + * V2 MIGRATION WARNING: DEPRECATED. Returns E_NOTIMPL always. + * + * See ICorProfilerInfo4::RequestReJIT instead + * + */ + HRESULT SetFunctionReJIT( + [in] FunctionID functionId); + + /* + * ForceGC forces a GC to occur within the runtime. + * + * NOTE: This method needs to be called from a thread that does not have any + * profiler callbacks on its stack. The most convenient way to implement this is + * to create a separate thread within the profiler and have it call ForceGC when + * signalled. + */ + HRESULT ForceGC(); + + /* + * + * V2 MIGRATION NOTE - Calling SetILInstrumentedCodeMap on any one + * of the multiple FunctionIDs that represent a generic function in a given + * AppDomain will affect all instantiations of that function in the AppDomain. + * + * fStartJit should be set to true the first time this function is called for + * a given FunctionID, and false thereafter. + * + * The format of the map is as follows: + * The debugger will assume that each oldOffset refers to an IL offset + * within the original, unmodified IL code. newOffset refers to the corresponding + * IL offset within the new, instrumented code. + * + * The map should be sorted in increasing order. For stepping to work properly: + * - Instrumented IL should not be reordered (so both old & new are sorted) + * - original IL should not be removed + * - the map should include entries to map all of the sequence points from the pdb. + * + * The map does not interpolate missing entries. So given the following map: + * (0 old, 0 new) + * (5 old, 10 new) + * (9 old, 20 new) + * - An old offset of 0,1,2,3,4 will be mapped to a new offset of 0 + * - An old offset of 5,6,7, or 8 will be mapped to new offset 10. + * - An old offset of 9 or higher will be mapped to new offset 20. + * - A new offset of 0, 1,...8,9 will be mapped to old offset 0 + * - A new offset of 10,11,...18,19 will be mapped to old offset 5. + * - A new offset of 20 or higher will be mapped to old offset 9. + * + */ + HRESULT SetILInstrumentedCodeMap( + [in] FunctionID functionId, + [in] BOOL fStartJit, + [in] ULONG cILMapEntries, + [in, size_is(cILMapEntries)] COR_IL_MAP rgILMapEntries[] ); + + /* + * DEPRECATED. + */ + HRESULT GetInprocInspectionInterface( + [out] IUnknown **ppicd); + + /* + * DEPRECATED. + */ + HRESULT GetInprocInspectionIThisThread( + [out] IUnknown **ppicd); + + /* + * This will return the ContextID currently associated with the calling + * runtime thread. This will set pContextId to NULL if the calling thread + * is not a runtime thread. + */ + HRESULT GetThreadContext( + [in] ThreadID threadId, + [out] ContextID *pContextId); + + /* + * DEPRECATED. + */ + HRESULT BeginInprocDebugging( + [in] BOOL fThisThreadOnly, + [out] DWORD *pdwProfilerContext); + + /* + * DEPRECATED. + */ + HRESULT EndInprocDebugging( + [in] DWORD dwProfilerContext); + + /* + * GetILToNativeMapping returns a map from IL offsets to native + * offsets for this code. An array of COR_PROF_IL_TO_NATIVE_MAP + * structs will be returned, and some of the ilOffsets in this array + * may be the values specified in CorDebugIlToNativeMappingTypes. + */ + HRESULT GetILToNativeMapping( + [in] FunctionID functionId, + [in] ULONG32 cMap, + [out] ULONG32 *pcMap, + [out, size_is(cMap), length_is(*pcMap)] + COR_DEBUG_IL_TO_NATIVE_MAP map[]); +} + +/* + * The CLR implements the ICorProfilerInfo2 interface. This interface is + * used by a code profiler to communicate with the CLR to control event + * monitoring and request information. The CLR passes an + * ICorProfilerInfo2 interface to each code profiler during initialization. + * + * A code profiler can call methods on the ICorProfilerInfo2 interface to get + * information about managed code being executed under the control of the CLR + * + * The ICorProfilerInfo2 interface implemented by the CLR uses the free + * threaded model. + * + * The methods implemented on this interface return S_OK on success, or E_FAIL + * on failure. + * + */ + +[ + object, + uuid(CC0935CD-A518-487d-B0BB-A93214E65478), + pointer_default(unique), + local +] +interface ICorProfilerInfo2 : ICorProfilerInfo +{ + /* + * The code profiler calls DoStackSnapshot to do sparse one-off stack snapshots. + * + * Passing NULL for thread yields a snapshot of the current thread. If a ThreadID + * of a different thread is passed, the runtime will suspend that thread, perform + * the snapshot, and resume. + * + * infoFlags come from the COR_PRF_SNAPSHOT_INFO enum. + * + * context is a platform-dependent CONTEXT structure, representing the complete + * register context that the profiling API will use to seed the stack walk. If this + * is non-NULL, it must point to JITd or NGENd code, or else DoStackSnapshot + * will return CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX. Contexts are + * only provided by profilers that hijack threads to force them to walk their + * own stacks; profilers should not attempt to provide a context when walking + * another thread's stack. If context is NULL, the stack walk will begin at the + * last available managed frame for the target thread. + * + * See the definition of StackSnapshotCallback for more information. + */ + HRESULT DoStackSnapshot( + [in] ThreadID thread, + [in] StackSnapshotCallback *callback, + [in] ULONG32 infoFlags, + [in] void *clientData, + [in, size_is(contextSize)] BYTE context[], + [in] ULONG32 contextSize); + + /* + * The code profiler calls SetFunctionHooks2 to specify handlers + * for FunctionEnter2, FunctionLeave2, and FunctionTailcall2 + * callbacks. + * + * Note that only one set of callbacks may be active at a time. Thus, + * if a profiler calls SetEnterLeaveFunctionHooks, SetEnterLeaveFunctionHooks2 + * and SetEnterLeaveFunctionHooks3(WithInfo), then SetEnterLeaveFunctionHooks3(WithInfo) + * wins. SetEnterLeaveFunctionHooks2 takes precedence over SetEnterLeaveFunctionHooks + * when both are set. + * + * Each pointer may be null to disable that particular callback. + * + * SetEnterLeaveFunctionHooks2 may only be called from the + * profiler's Initialize() callback. + */ + HRESULT SetEnterLeaveFunctionHooks2( + [in] FunctionEnter2 *pFuncEnter, + [in] FunctionLeave2 *pFuncLeave, + [in] FunctionTailcall2 *pFuncTailcall); + + /* + * GetFunctionInfo2 returns the parent class of a function, plus the + * function's metadata token and the ClassIDs of its type arguments + * (if any). + * + * When a COR_PRF_FRAME_INFO obtained from a FunctionEnter2 + * callback is passed, the ClassID and all type arguments will be exact. + * + * When a COR_PRF_FRAME_INFO from any other source is passed, or + * when 0 is passed as the frameInfo argument, exact ClassID and type + * arguments cannot always be determined. The value returned in pClassId + * may be NULL and some type args will come back as System.Object. + * + */ + HRESULT GetFunctionInfo2( + [in] FunctionID funcId, + [in] COR_PRF_FRAME_INFO frameInfo, + [out] ClassID *pClassId, + [out] ModuleID *pModuleId, + [out] mdToken *pToken, + [in] ULONG32 cTypeArgs, + [out] ULONG32 *pcTypeArgs, + [out] ClassID typeArgs[]); + + /* + * GetStringLayout returns detailed information about how string objects are stored. + * + * *pBufferLengthOffset is the offset (from the ObjectID pointer) to a DWORD that + * stores the length of the string's buffer + * + * *pStringLengthOffset is the offset (from the ObjectID pointer) to a DWORD that + * stores the length of the string itself + * + * *pBufferOffset is the offset (from the ObjectID pointer) to the actual buffer + * of wide characters + * + * Strings may or may not be null-terminated. + */ + HRESULT GetStringLayout( + [out] ULONG *pBufferLengthOffset, + [out] ULONG *pStringLengthOffset, + [out] ULONG *pBufferOffset); + + /* + * GetClassLayout returns detailed information how a specific class is stored. + * It only returns the fields defined by the class itself; if the parent class + * defined fields as well, the profiler must call GetClassLayout on the parent class + * to obtain those fields. + * + * It will fail with E_INVALIDARG for string and array classes. + */ + HRESULT GetClassLayout( + [in] ClassID classID, + [in, out] COR_FIELD_OFFSET rFieldOffset[], + [in] ULONG cFieldOffset, + [out] ULONG *pcFieldOffset, + [out] ULONG *pulClassSize); + + /* + * Returns the parent module a class is defined in, along with the + * metadata token for the class, the ClassID of its parent class, and the + * ClassIDs of its type arguments (if any). + * + * One can call GetModuleMetaData to obtain the metadata interface for + * a given module. The token can then be used to access the metadata for this + * class. + */ + HRESULT GetClassIDInfo2( + [in] ClassID classId, + [out] ModuleID *pModuleId, + [out] mdTypeDef *pTypeDefToken, + [out] ClassID *pParentClassId, + [in] ULONG32 cNumTypeArgs, + [out] ULONG32 *pcNumTypeArgs, + [out] ClassID typeArgs[]); + + /* + * GetCodeInfo2 returns the extents of native code associated with the + * given FunctionID. These extents are returned sorted in order of increasing + * IL offset. + */ + HRESULT GetCodeInfo2( + [in] FunctionID functionID, + [in] ULONG32 cCodeInfos, + [out] ULONG32 *pcCodeInfos, + [out, size_is(cCodeInfos), length_is(*pcCodeInfos)] + COR_PRF_CODE_INFO codeInfos[]); + + /* + * GetClassFromTokenAndTypeArgs returns the ClassID of a type given its metadata + * token (typedef) and the ClassIDs of its type arguments (if any). + * + * cTypeArgs must be equal to the number of type parameters for the given type + * (0 for non-generic types) + * typeArgs may be NULL if cTypeArgs == 0 + * + * Calling this function with a TypeRef token can have unpredictable results; callers + * should resolve the TypeRef to a TypeDef and use that. + * + * If the type is not already loaded, calling this function will cause it to be. + * Loading is a dangerous operation in many contexts. For example, calling + * this function during loading of modules or other types could lead to an infinite + * loop as the runtime attempts to circularly load things. + * + * In general, use of this function is discouraged. If profilers are interested in + * events for a particular type, they should store the ModuleID and TypeDef of that type, + * and use GetClassIDInfo2 to check whether a given ClassID is the desired type. + */ + HRESULT GetClassFromTokenAndTypeArgs( + [in] ModuleID moduleID, + [in] mdTypeDef typeDef, + [in] ULONG32 cTypeArgs, + [in, size_is(cTypeArgs)] ClassID typeArgs[], + [out] ClassID* pClassID); + + /* + * GetFunctionFromTokenAndTypeArgs returns the FunctionID of a function given + * its metadata token (methoddef), containing class, and type args (if any). + * + * classID may be 0 if the containing class is not generic + * typeArgs may be NULL if cTypeArgs == 0 + * + * Calling this function with a MethodRef token can have unpredictable results; callers + * should resolve the MethodRef to a MethodDef and use that. + * + * If the function is not already loaded, calling this function will cause it to be. + * Loading is a dangerous operation in many contexts. For example, calling + * this function during loading of modules or types could lead to an infinite + * loop as the runtime attempts to circularly load things. + * + * In general, use of this function is discouraged. If profilers are interested in + * events for a particular function, they should store the ModuleID and MethodDef of that function, + * and use GetFunctionInfo2 to check whether a given FunctionID is the desired function. + */ + HRESULT GetFunctionFromTokenAndTypeArgs( + [in] ModuleID moduleID, + [in] mdMethodDef funcDef, + [in] ClassID classId, + [in] ULONG32 cTypeArgs, + [in, size_is(cTypeArgs)] ClassID typeArgs[], + [out] FunctionID* pFunctionID); + + /* + * Returns an enumerator over all frozen objects in the given module. + */ + HRESULT EnumModuleFrozenObjects( + [in] ModuleID moduleID, + [out] ICorProfilerObjectEnum** ppEnum); + + + + /* + * GetArrayObjectInfo returns detailed information about an array object. + * objectId is a valid array object. + * cDimensions is the rank (# of dimensions). + * On success: + * pDimensionSizes, pDimensionLowerBounds are parallel arrays describing the size and lower bound for each dimension. + * (*ppData) is a pointer to the raw buffer for the array, which is laid out according to the C++ + * convention + */ + HRESULT GetArrayObjectInfo( + [in] ObjectID objectId, + [in] ULONG32 cDimensions, + [out, size_is(cDimensions)] ULONG32 pDimensionSizes[], + [out, size_is(cDimensions)] int pDimensionLowerBounds[], + [out] BYTE **ppData); + + /* + * GetBoxClassLayout returns information about how a particular value type is laid out + * when boxed. + * + * *pBufferOffset is the offset (from the ObjectID pointer) to where the value type + * is stored within the box. The value type's class layout may then be used to + * interpret it. + */ + HRESULT GetBoxClassLayout( + [in] ClassID classId, + [out] ULONG32 *pBufferOffset); + + + /* + * GetThreadAppDomain returns the AppDomainID currently associated with\ + * the given ThreadID + */ + HRESULT GetThreadAppDomain( + [in] ThreadID threadId, + [out] AppDomainID *pAppDomainId); + + + /* + * GetRVAStaticAddress gets the address of the home for the given + * RVA static. It must be called from a managed thread. Otherwise, + * it will return CORPROF_E_NOT_MANAGED_THREAD. + */ + HRESULT GetRVAStaticAddress( + [in] ClassID classId, + [in] mdFieldDef fieldToken, + [out] void **ppAddress); + + /* + * GetAppDomainStaticAddress gets the address of the home for the given + * AppDomain static in the given AppDomain. + * + * This function may return CORPROF_E_DATAINCOMPLETE if the given static + * has not been assigned a home in the given AppDomain. + */ + HRESULT GetAppDomainStaticAddress( + [in] ClassID classId, + [in] mdFieldDef fieldToken, + [in] AppDomainID appDomainId, + [out] void **ppAddress); + + /* + * GetThreadStaticAddress gets the address of the home for the given + * Thread static in the given Thread. threadId must be the current thread + * ID or NULL, which means using curernt thread ID. + * + * This function may return CORPROF_E_DATAINCOMPLETE if the given static + * has not been assigned a home in the given Thread. + */ + HRESULT GetThreadStaticAddress( + [in] ClassID classId, + [in] mdFieldDef fieldToken, + [in] ThreadID threadId, + [out] void **ppAddress); + + /* + * GetContextStaticAddress gets the address of the home for the given + * Context static in the given context. It must be called from a managed + * thread. Otherwise, it will return CORPROF_E_NOT_MANAGED_THREAD. + * + * This function may return CORPROF_E_DATAINCOMPLETE if the given static + * has not been assigned a home in the given Context. + */ + HRESULT GetContextStaticAddress( + [in] ClassID classId, + [in] mdFieldDef fieldToken, + [in] ContextID contextId, + [out] void **ppAddress); + + /* + * GetStaticFieldInfo gets COR_PRF_STATIC_TYPE for a specific + * field in a class. This information can be used to decide which + * function to call to get the address of the static. + * + * NOTE: One should still check the metadata for a static to ensure + * it is actually going to have an address. Statics that are literals + * (aka constants) exist only in the metadata and do not have an address. + * + */ + HRESULT GetStaticFieldInfo( + [in] ClassID classId, + [in] mdFieldDef fieldToken, + [out] COR_PRF_STATIC_TYPE *pFieldInfo); + + /* + * GetGenerationBounds returns the memory regions that make up a given + * GC generation in memory. It may be called from any profiler callback as long + * as a GC is not in progress. (To be exact, it may be called from any callback + * except for those that occur between GarbageCollectionStarted and GarbageCollectionFinished.) + * + * Most shifting of generations takes place during garbage collections; between + * collections generations may grow, but generally do not move around. Therefore + * the most interesting places to call this function are in GarbageCollectionStarted + * and Finished. + * + * During program startup, some objects are allocated by the CLR itself, generally + * in generations 3 and 0. So by the time managed code starts executing, these + * generations will already contain objects. Generations 1 and 2 will be normally + * empty, except for dummy objects generated by the garbage collector (of size 12 + * bytes in 32-bit implementations of the CLR, larger in 64-bit implementaions). + * You may also see generation 2 ranges that are inside modules generated by ngen. + * These are "frozen objects" generated at ngen time rather than allocated by the + * garbage collector. + * + * cObjectRanges is a count of the number of elements allocated by the caller for + * the ranges array + * pcObjectRanges is an out param for the number of ranges in the given generation + * ranges is an array of elements of type COR_PRF_GC_GENERATION_RANGE, each of which + * describes a range of memory used by the garbage collector + */ + + HRESULT GetGenerationBounds( + [in] ULONG cObjectRanges, + [out] ULONG *pcObjectRanges, + [out, size_is(cObjectRanges), length_is(*pcObjectRanges)] COR_PRF_GC_GENERATION_RANGE ranges[]); + + /* + * GetObjectGeneration returns which generation the given object is currently in, along + * with the start and length of the segment containing the object. It may be called + * at any time as long as a GC is not in progress. + */ + + HRESULT GetObjectGeneration( + [in] ObjectID objectId, + [out] COR_PRF_GC_GENERATION_RANGE *range); + + + /* + * When an exception notification is received, GetNotifiedExceptionClauseInfo() may be used + * to get the native address and frame information for the exception clause (catch/finally/filter) + * that is about to be run (ExceptionCatchEnter, ExceptionUnwindFinallyEnter, ExceptionFilterEnter) + * or has just been run (ExceptionCatchLeave, ExceptionUnwindFinallyLeave, ExceptionFilterLeave). + * + * This call may be made at any time after one of the Enter calls above until either the matching + * Leave call is received or until a nested exception throws out of the current clause in which case + * there will be no Leave notification for that clause. Note it is not possible for a throw to escape + * a Filter so there is always a Leave in that case. + * + * Return values: + * S_OK indicates success + * S_FALSE indicates that no exception clause is active + * CORPROF_E_NOT_MANAGED_THREAD indicates an unmanaged thread. + */ + + HRESULT GetNotifiedExceptionClauseInfo( + [out] COR_PRF_EX_CLAUSE_INFO *pinfo); +} + +/* + * The CLR implements the ICorProfilerInfo3 interface. This interface is + * used by a code profiler to communicate with the CLR to control event + * monitoring and request information. The CLR passes an + * ICorProfilerInfo3 interface to each code profiler during initialization. + * + * A code profiler can call methods on the ICorProfilerInfo3 interface to get + * information about managed code being executed under the control of the CLR + * + * The ICorProfilerInfo3 interface implemented by the CLR uses the free + * threaded model. + * + * The methods implemented on this interface return S_OK on success, or E_FAIL + * on failure. + * + */ + +[ + object, + uuid(B555ED4F-452A-4E54-8B39-B5360BAD32A0), + pointer_default(unique), + local +] +interface ICorProfilerInfo3 : ICorProfilerInfo2 +{ + /* + * Returns an enumerator for all previously jitted functions. May overlap with + * functions previously reported via CompilationStarted callbacks. + * NOTE: The returned enumeration will only include '0' for the value of the + * COR_PRF_FUNCTION::reJitId field. If you require valid COR_PRF_FUNCTION::reJitId values, use + * ICorProfilerInfo4::EnumJITedFunctions2. + */ + HRESULT EnumJITedFunctions([out] ICorProfilerFunctionEnum** ppEnum); + + HRESULT RequestProfilerDetach([in] DWORD dwExpectedCompletionMilliseconds); + + HRESULT SetFunctionIDMapper2( + [in] FunctionIDMapper2 *pFunc, + [in] void *clientData); + + /* + * GetStringLayout2 returns detailed information about how string objects are stored. + * + * *pStringLengthOffset is the offset (from the ObjectID pointer) to a DWORD that + * stores the length of the string itself + * + * *pBufferOffset is the offset (from the ObjectID pointer) to the actual buffer + * of wide characters + * + * Strings may or may not be null-terminated. + */ + HRESULT GetStringLayout2( + [out] ULONG *pStringLengthOffset, + [out] ULONG *pBufferOffset); + + /* + * The code profiler calls SetFunctionHooks3 to specify handlers + * for FunctionEnter3, FunctionLeave3, and FunctionTailcall3, and calls + * SetFunctionHooks3WithInfo to specify handlers for FunctionEnter3WithInfo, + * FunctionLeave3WithInfo, and FunctionTailcall3WithInfo. + * + * Note that only one set of callbacks may be active at a time. Thus, + * if a profiler calls SetEnterLeaveFunctionHooks, SetEnterLeaveFunctionHooks2 + * and SetEnterLeaveFunctionHooks3(WithInfo), then SetEnterLeaveFunctionHooks3(WithInfo) + * wins. SetEnterLeaveFunctionHooks2 takes precedence over SetEnterLeaveFunctionHooks + * when both are set. + * + * Each function pointer may be null to disable that callback. + * + * SetEnterLeaveFunctionHooks3(WithInfo) may only be called from the + * profiler's Initialize() callback. + */ + HRESULT SetEnterLeaveFunctionHooks3( + [in] FunctionEnter3 *pFuncEnter3, + [in] FunctionLeave3 *pFuncLeave3, + [in] FunctionTailcall3 *pFuncTailcall3); + + + HRESULT SetEnterLeaveFunctionHooks3WithInfo( + [in] FunctionEnter3WithInfo *pFuncEnter3WithInfo, + [in] FunctionLeave3WithInfo *pFuncLeave3WithInfo, + [in] FunctionTailcall3WithInfo *pFuncTailcall3WithInfo); + + /* + * The profiler can call GetFunctionEnter3Info to gather frame info and argument info + * in FunctionEnter3WithInfo callback. The profiler needs to allocate sufficient space + * for COR_PRF_FUNCTION_ARGUMENT_INFO of the function it's inspecting and indicate the + * size in a ULONG pointed by pcbArgumentInfo. + */ + HRESULT GetFunctionEnter3Info( + [in] FunctionID functionId, + [in] COR_PRF_ELT_INFO eltInfo, + [out] COR_PRF_FRAME_INFO *pFrameInfo, + [in, out] ULONG *pcbArgumentInfo, + [out, size_is(*pcbArgumentInfo)] COR_PRF_FUNCTION_ARGUMENT_INFO *pArgumentInfo); + + /* + * The profiler can call GetFunctionLeave3Info to gather frame info and return value + * in FunctionLeave3WithInfo callback. + */ + HRESULT GetFunctionLeave3Info( + [in] FunctionID functionId, + [in] COR_PRF_ELT_INFO eltInfo, + [out] COR_PRF_FRAME_INFO *pFrameInfo, + [out] COR_PRF_FUNCTION_ARGUMENT_RANGE *pRetvalRange); + + /* + * The profiler can call GetFunctionTailcall3Info to gather frame info in + * FunctionTailcall3WithInfo callback. + */ + HRESULT GetFunctionTailcall3Info( + [in] FunctionID functionId, + [in] COR_PRF_ELT_INFO eltInfo, + [out] COR_PRF_FRAME_INFO *pFrameInfo); + + HRESULT EnumModules([out] ICorProfilerModuleEnum** ppEnum); + + /* + * The profiler can call GetRuntimeInformation to query CLR version information. + * Passing NULL to any parameter is acceptable except pcchVersionString cannot + * be NULL if szVersionString is not NULL. + */ + HRESULT GetRuntimeInformation([out] USHORT *pClrInstanceId, + [out] COR_PRF_RUNTIME_TYPE *pRuntimeType, + [out] USHORT *pMajorVersion, + [out] USHORT *pMinorVersion, + [out] USHORT *pBuildNumber, + [out] USHORT *pQFEVersion, + [in] ULONG cchVersionString, + [out] ULONG *pcchVersionString, + [out, annotation("_Out_writes_to_(cchVersionString, *pcchVersionString)")] + WCHAR szVersionString[]); + + /* + * GetThreadStaticAddress2 gets the address of the home for the given + * Thread static in the given Thread. + * + * This function may return CORPROF_E_DATAINCOMPLETE if the given static + * has not been assigned a home in the given Thread. + */ + HRESULT GetThreadStaticAddress2( + [in] ClassID classId, + [in] mdFieldDef fieldToken, + [in] AppDomainID appDomainId, + [in] ThreadID threadId, + [out] void **ppAddress); + + /* + * GetAppDomainsContainingModule returns the AppDomainIDs in which the + * given module has been loaded + */ + HRESULT GetAppDomainsContainingModule( + [in] ModuleID moduleId, + [in] ULONG32 cAppDomainIds, + [out] ULONG32 *pcAppDomainIds, + [out, size_is(cAppDomainIds), length_is(*pcAppDomainIds)] AppDomainID appDomainIds[]); + + + /* + * Retrieve information about a given module. + * + * When the module is loaded from disk, the name returned will be the filename; + * otherwise, the name will be the name from the metadata Module table (i.e., + * the same as the managed System.Reflection.Module.ScopeName). + * + * *pdwModuleFlags will be filled in with a bitmask of values from COR_PRF_MODULE_FLAGS + * that specify some properties of the module. + * + * NOTE: While this function may be called as soon as the moduleId is alive, + * the AssemblyID of the containing assembly will not be available until the + * ModuleAttachedToAssembly callback. + * + */ + HRESULT GetModuleInfo2( + [in] ModuleID moduleId, + [out] LPCBYTE *ppBaseLoadAddress, + [in] ULONG cchName, + [out] ULONG *pcchName, + [out, annotation("_Out_writes_to_(cchName, *pcchName)")] + WCHAR szName[], + [out] AssemblyID *pAssemblyId, + [out] DWORD *pdwModuleFlags); + + +} + + +/* + * This interface lets you iterate over the frozen objects from ngen images. + */ + +[ + object, + uuid(2C6269BD-2D13-4321-AE12-6686365FD6AF), + pointer_default(unique), + local +] +interface ICorProfilerObjectEnum : IUnknown +{ + HRESULT Skip( + [in] ULONG celt); + + HRESULT Reset(); + + HRESULT Clone( + [out] ICorProfilerObjectEnum **ppEnum); + + HRESULT GetCount( + [out] ULONG *pcelt); + + HRESULT Next( + [in] ULONG celt, + [out, size_is(celt), length_is(*pceltFetched)] ObjectID objects[], + [out] ULONG *pceltFetched); +} + + +/* + * This interface lets you iterate over functions in the runtime. + */ + +[ + object, + uuid(FF71301A-B994-429D-A10B-B345A65280EF), + pointer_default(unique), + local +] +interface ICorProfilerFunctionEnum : IUnknown +{ + HRESULT Skip([in] ULONG celt); + + HRESULT Reset(); + + HRESULT Clone([out] ICorProfilerFunctionEnum **ppEnum); + + HRESULT GetCount([out] ULONG *pcelt); + + HRESULT Next([in] ULONG celt, + [out, size_is(celt), length_is(*pceltFetched)] + COR_PRF_FUNCTION ids[], + [out] ULONG * pceltFetched); +}; + +/* + * This interface lets you iterate over modules in the runtime. + */ + +[ + object, + uuid(b0266d75-2081-4493-af7f-028ba34db891), + pointer_default(unique), + local +] +interface ICorProfilerModuleEnum : IUnknown +{ + HRESULT Skip([in] ULONG celt); + + HRESULT Reset(); + + HRESULT Clone([out] ICorProfilerModuleEnum **ppEnum); + + HRESULT GetCount([out] ULONG *pcelt); + + HRESULT Next([in] ULONG celt, + [out, size_is(celt), length_is(*pceltFetched)] + ModuleID ids[], + [out] ULONG * pceltFetched); +}; + +/* + * NOTE: DEPRECATED, now you can use your any allocator. + * + * This is simple allocator that only allows you to allocate memory. + * You may not free it. This was used in conjunction with + * ICorProfilerInfo::SetILFunctionBody. + */ +[ + object, + uuid(A0EFB28B-6EE2-4d7b-B983-A75EF7BEEDB8), + pointer_default(unique), + local +] +interface IMethodMalloc : IUnknown +{ + /* + * Tries to allocate memory above the start address of the module from + * which it was created. It is important to note that this method may + * fail to allocate the memory specified above the start address, and + * may as a result return NULL. + */ + PVOID Alloc( + [in] ULONG cb); +} + +/* + * The CLR implements the ICorProfilerFunctionControl interface. This interface + * is used by a code profiler to communicate with the CLR to control how the + * JIT should generate code when rejitting a specific method. + * + * The ICorProfilerFunctionControl interface implemented by the CLR uses the + * free threaded model. + */ + +[ + object, + uuid(F0963021-E1EA-4732-8581-E01B0BD3C0C6), + pointer_default(unique), + local +] +interface ICorProfilerFunctionControl : IUnknown +{ + /* + * Set one or more flags from COR_PRF_CODEGEN_FLAGS to control code + * generation just for this method. + */ + HRESULT SetCodegenFlags( + [in] DWORD flags); + + /* + * Override the method body. + */ + HRESULT SetILFunctionBody( + [in] ULONG cbNewILMethodHeader, + [in, size_is(cbNewILMethodHeader)] LPCBYTE pbNewILMethodHeader); + + /* + * This is not currently implemented, and will return E_NOTIMPL + */ + HRESULT SetILInstrumentedCodeMap( + [in] ULONG cILMapEntries, + [in, size_is(cILMapEntries)] COR_IL_MAP rgILMapEntries[]); + +} + +/* + * The CLR implements the ICorProfilerInfo4 interface. This interface is + * used by a code profiler to communicate with the CLR to control event + * monitoring and request information. The CLR passes an + * ICorProfilerInfo4 interface to each code profiler during initialization. + * + * A code profiler can call methods on the ICorProfilerInfo4 interface to get + * information about managed code being executed under the control of the CLR + * + * The ICorProfilerInfo4 interface implemented by the CLR uses the free + * threaded model. + * + * The methods implemented on this interface return S_OK on success, or E_FAIL + * on failure. + * + */ + +[ + object, + uuid(0d8fdcaa-6257-47bf-b1bf-94dac88466ee), + pointer_default(unique), + local +] +interface ICorProfilerInfo4 : ICorProfilerInfo3 +{ + HRESULT EnumThreads([out] ICorProfilerThreadEnum **ppEnum); + HRESULT InitializeCurrentThread(); + + /* + * Call RequestReJIT to have the runtime re-JIT a particular set of methods. + * A code profiler can then adjust the code generated when the method is + * re-JITed through the ICorProfilerFunctionControl interface. This does + * not impact currently executing methods, only future invocations. + * + * A return code of S_OK indicates that all of the requested methods were + * attempted to be rejitted. However, the profiler must implement + * ICorProfilerCallback4::ReJITError to determine which of the methods were + * successfully re-JITed. + * + * A failure return value (E_*) indicates some failure that prevents any + * re-JITs. + */ + HRESULT RequestReJIT( + [in] ULONG cFunctions, + [in, size_is(cFunctions)] ModuleID moduleIds[], + [in, size_is(cFunctions)] mdMethodDef methodIds[]); + + /* + * RequestRevert will instruct the runtime to revert to using/calling the + * original method (original IL and flags) rather than whatever was + * ReJITed. This does not change any currently active methods, only future + * invocations. + * + */ + HRESULT RequestRevert( + [in] ULONG cFunctions, + [in, size_is(cFunctions)] ModuleID moduleIds[], + [in, size_is(cFunctions)] mdMethodDef methodIds[], + [out, size_is(cFunctions)] HRESULT status[]); + + /* + * Same as GetCodeInfo2, except instead of always returning the code info + * associated with the original IL/function, you can request the code info + * for a particular re-JITed version of a function. + */ + HRESULT GetCodeInfo3( + [in] FunctionID functionID, + [in] ReJITID reJitId, + [in] ULONG32 cCodeInfos, + [out] ULONG32 * pcCodeInfos, + [out, size_is(cCodeInfos), length_is(*pcCodeInfos)] + COR_PRF_CODE_INFO codeInfos[]); + + /* + * Same as GetFunctionFromIP, but also returns which re-JITed version is + * associated with the IP address. + */ + HRESULT GetFunctionFromIP2( + [in] LPCBYTE ip, + [out] FunctionID * pFunctionId, + [out] ReJITID * pReJitId); + + /* + * GetReJITIDs can be used to find all of the re-JITed versions of the + * given function. + */ + HRESULT GetReJITIDs( + [in] FunctionID functionId, + [in] ULONG cReJitIds, + [out] ULONG * pcReJitIds, + [out, size_is(cReJitIds), length_is(*pcReJitIds)] + ReJITID reJitIds[]); + + /* + * Same as GetILToNativeMapping, but allows the code profiler to specify + * which re-JITed version it applies to. + */ + HRESULT GetILToNativeMapping2( + [in] FunctionID functionId, + [in] ReJITID reJitId, + [in] ULONG32 cMap, + [out] ULONG32 * pcMap, + [out, size_is(cMap),length_is(*pcMap)] + COR_DEBUG_IL_TO_NATIVE_MAP map[]); + + /* + * Returns an enumerator for all previously jitted functions. May overlap with + * functions previously reported via CompilationStarted callbacks. The returned + * enumeration will include values for the COR_PRF_FUNCTION::reJitId field + */ + HRESULT EnumJITedFunctions2([out] ICorProfilerFunctionEnum** ppEnum); + + /* + * The code profiler calls GetObjectSize to obtain the size of an object. + * Note that types like arrays and strings may have a different size for each object. + */ + HRESULT GetObjectSize2( + [in] ObjectID objectId, + [out] SIZE_T *pcSize); + +} + +[ + object, + uuid(07602928-CE38-4B83-81E7-74ADAF781214), + pointer_default(unique), + local +] +interface ICorProfilerInfo5 : ICorProfilerInfo4 +{ + /* + * The code profiler calls GetEventMask2 to obtain the current event + * categories for which it is to receive event notifications from the CLR + * + * *pdwEventsLow is a bitwise combination of values from COR_PRF_MONITOR + * *pdwEventsHigh is a bitwise combination of values from COR_PRF_HIGH_MONITOR + */ + HRESULT GetEventMask2( + [out] DWORD *pdwEventsLow, + [out] DWORD *pdwEventsHigh); + + /* + * The code profiler calls SetEventMask2 to set the event categories for + * which it is set to receive notification from the CLR. + * + * dwEventsLow is a bitwise combination of values from COR_PRF_MONITOR + * dwEventsHigh is a bitwise combination of values from COR_PRF_HIGH_MONITOR + */ + HRESULT SetEventMask2( + [in] DWORD dwEventsLow, + [in] DWORD dwEventsHigh); +}; + + +[ + object, + uuid(F30A070D-BFFB-46A7-B1D8-8781EF7B698A), + pointer_default(unique), + local +] +interface ICorProfilerInfo6 : ICorProfilerInfo5 +{ + /* + * Returns an enumerator for all methods that + * - belong to a given NGen module (inlinersModuleId) and + * - inlined a body of a given method (inlineeModuleId / inlineeMethodId). + * + * If incompleteData is set to TRUE after function is called, it means that the methods enumerator + * doesn't contain all methods inlining a given method. + * It can happen when one or more direct or indirect dependencies of inliners module haven't been loaded yet. + * If profiler needs accurate data it should retry later when more modules are loaded (preferable on each module load). + * + * It can be used to lift limitation on inlining for ReJIT. + */ + HRESULT EnumNgenModuleMethodsInliningThisMethod( + [in] ModuleID inlinersModuleId, + [in] ModuleID inlineeModuleId, + [in] mdMethodDef inlineeMethodId, + [out] BOOL *incompleteData, + [out] ICorProfilerMethodEnum** ppEnum); +}; + +[ + object, + uuid(9AEECC0D-63E0-4187-8C00-E312F503F663), + pointer_default(unique), + local +] +interface ICorProfilerInfo7 : ICorProfilerInfo6 +{ + /* + * Applies the newly emitted Metadata. + * + * This method can be used to apply the newly defined metadata by IMetadataEmit::Define* methods + * to the module. + * + * If metadata changes are made after ModuleLoadFinished callback, + * it is required to call this method before using the new metadata + */ + HRESULT ApplyMetaData( + [in] ModuleID moduleId); + + /* Returns the length of an in-memory symbol stream + * + * If the module has in-memory symbols the length of the stream will + * be placed in pCountSymbolBytes. If the module doesn't have in-memory + * symbols, *pCountSymbolBytes = 0 + * + * Returns S_OK if the length could be determined (even if it is 0) + * + * Note: The current implementation does not support reflection.emit. + * CORPROF_E_MODULE_IS_DYNAMIC will be returned in that case. + */ + HRESULT GetInMemorySymbolsLength( + [in] ModuleID moduleId, + [out] DWORD* pCountSymbolBytes); + + /* Reads bytes from an in-memory symbol stream + * + * This function attempts to read countSymbolBytes of data starting at offset + * symbolsReadOffset within the in-memory stream. The data will be copied into + * pSymbolBytes which is expected to have countSymbolBytes of space available. + * pCountSymbolsBytesRead contains the actual number of bytes read which + * may be less than countSymbolBytes if the end of the stream is reached. + * + * Returns S_OK if a non-zero number of bytes were read. + * + * Note: The current implementation does not support reflection.emit. + * CORPROF_E_MODULE_IS_DYNAMIC will be returned in that case. + */ + HRESULT ReadInMemorySymbols( + [in] ModuleID moduleId, + [in] DWORD symbolsReadOffset, + [out] BYTE* pSymbolBytes, + [in] DWORD countSymbolBytes, + [out] DWORD* pCountSymbolBytesRead); + +}; + +/* +* This interface lets you iterate over methods in the runtime. +*/ + +[ + object, + uuid(FCCEE788-0088-454B-A811-C99F298D1942), + pointer_default(unique), + local +] +interface ICorProfilerMethodEnum : IUnknown +{ + HRESULT Skip([in] ULONG celt); + + HRESULT Reset(); + + HRESULT Clone([out] ICorProfilerMethodEnum **ppEnum); + + HRESULT GetCount([out] ULONG *pcelt); + + HRESULT Next([in] ULONG celt, + [out, size_is(celt), length_is(*pceltFetched)] + COR_PRF_METHOD elements[], + [out] ULONG * pceltFetched); +} + +/* + * This interface lets you iterate over threads in the runtime. + */ + +[ + object, + uuid(571194f7-25ed-419f-aa8b-7016b3159701), + pointer_default(unique), + local +] +interface ICorProfilerThreadEnum : IUnknown +{ + HRESULT Skip([in] ULONG celt); + + HRESULT Reset(); + + HRESULT Clone([out] ICorProfilerThreadEnum **ppEnum); + + HRESULT GetCount([out] ULONG *pcelt); + + HRESULT Next([in] ULONG celt, + [out, size_is(celt), length_is(*pceltFetched)] + ThreadID ids[], + [out] ULONG * pceltFetched); +} + + +/* + * This interface is given to the profiler in the GetAssemblyReferences() callback, to + * allow the profiler to inform the CLR of assembly references that the profiler plans to + * add later on during ModuleLoadFinished. This improves the accuracy of the CLR assembly + * reference closure walker, and its algorithms for determining whether assemblies may be shared + * + * This interface is valid for use only within the GetAssemblyReferences callback that passed + * this interface to the profiler + */ +[ + object, + uuid(66A78C24-2EEF-4F65-B45F-DD1D8038BF3C), + pointer_default(unique), + local +] +interface ICorProfilerAssemblyReferenceProvider : IUnknown +{ + // The profiler calls this for each target assembly it plans to reference from the + // assembly specified in the wszAssemblyPath argument of the GetAssemblyReferences callback. + HRESULT AddAssemblyReference(const COR_PRF_ASSEMBLY_REFERENCE_INFO * pAssemblyRefInfo); +}; |