mirror of https://github.com/UMSKT/xpmgr.git
3171 lines
125 KiB
Plaintext
3171 lines
125 KiB
Plaintext
// ==++==
|
||
//
|
||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
//
|
||
// ==--==
|
||
/**************************************************************************************
|
||
** **
|
||
** 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;
|
||
|
||
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 compatability 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 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;
|
||
|
||
typedef struct _COR_PRF_FUNCTION
|
||
{
|
||
FunctionID functionId;
|
||
UINT_PTR reserved;
|
||
} COR_PRF_FUNCTION;
|
||
|
||
|
||
/*
|
||
* 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 FunctionEnter(
|
||
FunctionID funcID);
|
||
|
||
typedef void FunctionLeave(
|
||
FunctionID funcID);
|
||
|
||
typedef void 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 FunctionEnter2(
|
||
FunctionID funcId,
|
||
UINT_PTR clientData,
|
||
COR_PRF_FRAME_INFO func,
|
||
COR_PRF_FUNCTION_ARGUMENT_INFO *argumentInfo);
|
||
|
||
typedef void FunctionLeave2(
|
||
FunctionID funcId,
|
||
UINT_PTR clientData,
|
||
COR_PRF_FRAME_INFO func,
|
||
COR_PRF_FUNCTION_ARGUMENT_RANGE *retvalRange);
|
||
|
||
typedef void 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 FunctionEnter3(
|
||
FunctionIDOrClientID functionIDOrClientID);
|
||
|
||
typedef void FunctionLeave3(
|
||
FunctionIDOrClientID functionIDOrClientID);
|
||
|
||
typedef void 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 FunctionEnter3WithInfo(
|
||
FunctionIDOrClientID functionIDOrClientID,
|
||
COR_PRF_ELT_INFO eltInfo);
|
||
|
||
typedef void FunctionLeave3WithInfo(
|
||
FunctionIDOrClientID functionIDOrClientID,
|
||
COR_PRF_ELT_INFO eltInfo);
|
||
|
||
typedef void 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,
|
||
|
||
// 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,
|
||
|
||
// V2 MIGRATION WARNING: DEPRECATED
|
||
// ReJIT is not supported. ENABLE_REJIT has no effect.
|
||
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,
|
||
|
||
// 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,
|
||
|
||
// The mask for valid mask bits
|
||
COR_PRF_ALL = 0x7FFFFFFF,
|
||
|
||
// 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_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_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_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 ICorProfilerInfo;
|
||
interface ICorProfilerInfo2;
|
||
interface ICorProfilerInfo3;
|
||
interface ICorProfilerObjectEnum;
|
||
interface ICorProfilerFunctionEnum;
|
||
interface ICorProfilerModuleEnum;
|
||
interface IMethodMalloc;
|
||
/* -------------------------------------------------------------------------- *
|
||
* 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<73> stack is managed). If the application being profiled started
|
||
* life as unmanaged code, which later <20>jumped into<74> 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<33>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.
|
||
*/
|
||
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,
|
||
} 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_ecount_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
|
||
*/
|
||
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();
|
||
};
|
||
|
||
|
||
/*
|
||
* 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);
|
||
|
||
/*
|
||
* 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.
|
||
*/
|
||
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);
|
||
|
||
/*
|
||
* The code profiler calls SetEventMask to sets 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_ecount_part(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_ecount_part(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_ecount_part(cchName, *pcchName)")]
|
||
WCHAR szName[] ,
|
||
[out] AppDomainID *pAppDomainId,
|
||
[out] ModuleID *pModuleId);
|
||
|
||
|
||
/*
|
||
* V2 MIGRATION WARNING: DEPRECATED. Returns E_NOTIMPL always.
|
||
*
|
||
* Marks a function as requiring a re-JIT. The function will be re-JITted
|
||
* at its next invocation. The normal profiller events will give the profiller
|
||
* an opportunity to replace the IL prior to the JIT. By this means, a tool
|
||
* can effectively replace a function at runtime. Note that active instances
|
||
* of the function are not affected by the replacement.
|
||
*
|
||
* NOTE: memory used by the current jitted code for this method will not be
|
||
* released, as it may currently be in use by one or more threads and
|
||
* may have associated data on the stack.
|
||
*/
|
||
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.
|
||
*
|
||
* Though it will not fail, the data returned for array and string classes will
|
||
* not be correct.
|
||
*/
|
||
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.
|
||
*/
|
||
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_ecount_part(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_ecount_part(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);
|
||
}
|
||
|