1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // FILE: ProfToEEInterfaceImpl.cpp
7 // This module implements the ICorProfilerInfo* interfaces, which allow the
8 // Profiler to communicate with the EE. This allows the Profiler DLL to get
9 // access to private EE data structures and other things that should never be
10 // exported outside of the EE.
14 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
15 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
19 // There are strict rules for how to implement ICorProfilerInfo* methods. Please read
20 // https://github.com/dotnet/coreclr/blob/master/Documentation/botr/profilability.md
21 // to understand the rules and why they exist.
23 // As a reminder, here is a short summary of your responsibilities. Every PUBLIC
24 // ENTRYPOINT (from profiler to EE) must have:
26 // - An entrypoint macro at the top (see code:#P2CLRRestrictionsOverview). Your choices are:
27 // PROFILER_TO_CLR_ENTRYPOINT_SYNC (typical choice):
28 // Indicates the method may only be called by the profiler from within
29 // a callback (from EE to profiler).
30 // PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY
31 // Even more restrictive, this indicates the method may only be called
32 // from within the Initialize() callback
33 // PROFILER_TO_CLR_ENTRYPOINT_ASYNC
34 // Indicates this method may be called anytime.
35 // THIS IS DANGEROUS. PLEASE READ ABOVE DOC FOR GUIDANCE ON HOW TO SAFELY
36 // CODE AN ASYNCHRONOUS METHOD.
37 // You may use variants of these macros ending in _EX that accept bit flags (see
38 // code:ProfToClrEntrypointFlags) if you need to specify additional parameters to how
39 // the entrypoint should behave, though typically you can omit the flags and the
40 // default (kP2EENone) will be used.
42 // - A complete contract block with comments over every contract choice. Wherever
43 // possible, use the preferred contracts (if not possible, you must comment why):
48 // (EE_THREAD_(NOT)_REQUIRED are unenforced and are thus optional. If you wish
49 // to specify these, EE_THREAD_NOT_REQUIRED is preferred.)
50 // Note that the preferred contracts in this file are DIFFERENT than the preferred
51 // contracts for eetoprofinterfaceimpl.cpp.
53 // Private helper functions in this file do not have the same preferred contracts as
54 // public entrypoints, and they should be contracted following the same guidelines
55 // as per the rest of the EE.
57 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
58 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
61 // #P2CLRRestrictionsOverview
63 // The public ICorProfilerInfo(N) functions below have different restrictions on when
64 // they're allowed to be called. Listed roughly in order from most to least restrictive:
65 // * PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY: Functions that are only
66 // allowed to be called while the profiler is initializing on startup, from
67 // inside the profiler's ICorProfilerCallback::Initialize method
68 // * PROFILER_TO_CLR_ENTRYPOINT_SYNC: Functions that may be called from within any of
69 // the profiler's callbacks, or anytime from a thread created by the profiler.
70 // These functions may only be called by profilers loaded on startup
71 // * PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach): Same as above,
72 // except these may be called by startup AND attaching profilers.
73 // * PROFILER_TO_CLR_ENTRYPOINT_ASYNC: Functions that may be called at any time and
74 // from any thread by a profiler loaded on startup
75 // * PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach): Same as above,
76 // except these may be called by startup AND attaching profilers.
78 // The above restrictions are lifted for certain tests that run with these environment
79 // variables set. (These are only available on DEBUG builds--including chk--not retail
81 // * COMPlus_TestOnlyEnableSlowELTHooks:
82 // * If nonzero, then on startup the runtime will act as if a profiler was loaded
83 // on startup and requested ELT slow-path (even if no profiler is loaded on
84 // startup). This will also allow the SetEnterLeaveFunctionHooks(2) info
85 // functions to be called outside of Initialize(). If a profiler later
86 // attaches and calls these functions, then the slow-path wrapper will call
87 // into the profiler's ELT hooks.
88 // * COMPlus_TestOnlyEnableObjectAllocatedHook:
89 // * If nonzero, then on startup the runtime will act as if a profiler was loaded
90 // on startup and requested ObjectAllocated callback (even if no profiler is loaded
91 // on startup). If a profiler later attaches and calls these functions, then the
92 // ObjectAllocated notifications will call into the profiler's ObjectAllocated callback.
93 // * COMPlus_TestOnlyEnableICorProfilerInfo:
94 // * If nonzero, then attaching profilers allows to call ICorProfilerInfo inteface,
95 // which would otherwise be disallowed for attaching profilers
96 // * COMPlus_TestOnlyAllowedEventMask
97 // * If a profiler needs to work around the restrictions of either
98 // COR_PRF_ALLOWABLE_AFTER_ATTACH or COR_PRF_MONITOR_IMMUTABLE it may set
99 // this environment variable. Its value should be a bitmask containing all
100 // the flags that are:
101 // * normally immutable or disallowed after attach, AND
102 // * that the test plans to set after startup and / or by an attaching
108 // ======================================================================================
111 #include <posterror.h>
112 #include "proftoeeinterfaceimpl.h"
113 #include "proftoeeinterfaceimpl.inl"
114 #include "dllimport.h"
116 #include "method.hpp"
118 #include "dbginterface.h"
123 #include "eeconfig.h"
124 #include "generics.h"
126 #include "safemath.h"
127 #include "threadsuspend.h"
128 #include "inlinetracking.h"
130 #ifdef PROFILING_SUPPORTED
131 #include "profilinghelper.h"
132 #include "profilinghelper.inl"
133 #include "eetoprofinterfaceimpl.inl"
134 #include "profilingenumerators.h"
137 #include "profdetach.h"
139 #include "metadataexports.h"
141 //---------------------------------------------------------------------------------------
144 // An OR'd combination of these flags may be specified in the _EX entrypoint macros to
145 // customize the behavior.
146 enum ProfToClrEntrypointFlags
148 // Just use the default behavior (this one is used if the non-_EX entrypoint macro is
149 // specified without any flags).
150 kP2EENone = 0x00000000,
152 // By default, Info functions are not allowed to be used by an attaching profiler.
153 // Specify this flag to override the default.
154 kP2EEAllowableAfterAttach = 0x00000001,
156 // This info method has a GC_TRIGGERS contract. Whereas contracts are debug-only,
157 // this flag is used in retail builds as well.
158 kP2EETriggers = 0x00000002,
161 // Default versions of the entrypoint macros use kP2EENone if no
162 // ProfToClrEntrypointFlags are specified
164 #define PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams) \
165 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EENone, logParams)
167 #define PROFILER_TO_CLR_ENTRYPOINT_SYNC(logParams) \
168 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EENone, logParams)
170 // ASYNC entrypoints log and ensure an attaching profiler isn't making a call that's
171 // only supported by startup profilers.
173 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags) \
176 if ((((p2eeFlags) & kP2EEAllowableAfterAttach) == 0) && \
177 (g_profControlBlock.pProfInterface->IsLoadedViaAttach())) \
181 "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER " \
182 "due to a call illegally made by an attaching profiler \n")); \
183 return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER; \
189 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags) \
192 if (!((&g_profControlBlock)->fTestOnlyEnableICorProfilerInfo)) \
194 CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags); \
202 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags) \
205 CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags); \
210 #define PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(p2eeFlags, logParams) \
213 INCONTRACT(AssertTriggersContract(((p2eeFlags) & kP2EETriggers))); \
214 _ASSERTE(g_profControlBlock.curProfStatus.Get() != kProfStatusNone); \
216 /* If profiler was neutered, disallow call */ \
217 if (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \
221 "**PROF: ERROR: Returning CORPROF_E_PROFILER_DETACHING " \
222 "due to a post-neutered profiler call\n")); \
223 return CORPROF_E_PROFILER_DETACHING; \
225 CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags); \
228 // SYNC entrypoints must ensure the current EE Thread shows evidence that we're
229 // inside a callback. If there's no EE Thread, then we automatically "pass"
230 // the check, and the SYNC call is allowed.
231 #define PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(p2eeFlags, logParams) \
234 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(p2eeFlags, logParams); \
235 DWORD __dwExpectedCallbackState = COR_PRF_CALLBACKSTATE_INCALLBACK; \
236 if (((p2eeFlags) & kP2EETriggers) != 0) \
238 __dwExpectedCallbackState |= COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE; \
240 if (!AreCallbackStateFlagsSet(__dwExpectedCallbackState)) \
244 "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE " \
245 "due to illegal asynchronous profiler call\n")); \
246 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE; \
250 // INIT_ONLY entrypoints must ensure we're executing inside the profiler's
251 // Initialize() implementation on startup (attach init doesn't count!).
252 #define PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams) \
255 PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams); \
256 if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad && \
257 g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForAttachLoad) \
259 return CORPROF_E_CALL_ONLY_FROM_INIT; \
263 // This macro is used to ensure that the current thread is not in a forbid
264 // suspend region. Some methods are allowed to be called asynchronously,
265 // but some of them call JIT functions that take a reader lock. So we need to ensure
266 // the current thread hasn't been hijacked by a profiler while it was holding the writer lock.
267 // Checking the ForbidSuspendThread region is a sufficient test for this
268 #define FAIL_IF_IN_FORBID_SUSPEND_REGION() \
271 Thread * __pThread = GetThreadNULLOk(); \
272 if ((__pThread != NULL) && (__pThread->IsInForbidSuspendRegion())) \
274 return CORPROF_E_ASYNCHRONOUS_UNSAFE; \
279 // This type is an overlay onto the exported type COR_PRF_FRAME_INFO.
280 // The first four fields *must* line up with the same fields in the
281 // exported type. After that, we can add to the end as we wish.
283 typedef struct _COR_PRF_FRAME_INFO_INTERNAL {
290 } COR_PRF_FRAME_INFO_INTERNAL, *PCOR_PRF_FRAME_INFO_INTERNAL;
293 // After we ship a product with a certain struct type for COR_PRF_FRAME_INFO_INTERNAL
294 // we have that as a version. If we change that in a later product, we can increment
295 // the counter below and then we can properly do versioning.
297 #define COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION 1
300 //---------------------------------------------------------------------------------------
302 // Converts TypeHandle to a ClassID
305 // th - TypeHandle to convert
308 // Requested ClassID.
311 ClassID TypeHandleToClassID(TypeHandle th)
314 return reinterpret_cast<ClassID> (th.AsPtr());
317 //---------------------------------------------------------------------------------------
319 // Converts TypeHandle for a non-generic type to a ClassID
322 // th - TypeHandle to convert
325 // Requested ClassID. NULL if th represents a generic type
327 #ifdef PROFILING_SUPPORTED
329 static ClassID NonGenericTypeHandleToClassID(TypeHandle th)
338 if ((!th.IsNull()) && (th.HasInstantiation()))
343 return TypeHandleToClassID(th);
346 //---------------------------------------------------------------------------------------
348 // Converts MethodDesc * to FunctionID
351 // pMD - MethodDesc * to convert
354 // Requested FunctionID
357 static FunctionID MethodDescToFunctionID(MethodDesc * pMD)
359 LIMITED_METHOD_CONTRACT;
360 return reinterpret_cast< FunctionID > (pMD);
365 //---------------------------------------------------------------------------------------
367 // Converts FunctionID to MethodDesc *
370 // functionID - FunctionID to convert
373 // MethodDesc * requested
376 MethodDesc *FunctionIdToMethodDesc(FunctionID functionID)
378 LIMITED_METHOD_CONTRACT;
380 MethodDesc *pMethodDesc;
382 pMethodDesc = reinterpret_cast< MethodDesc* >(functionID);
384 _ASSERTE(pMethodDesc != NULL);
388 // (See comments for ArrayKindFromTypeHandle below.)
391 ARRAY_KIND_TYPEDESC, // Normal, garden-variety typedesc array
392 ARRAY_KIND_METHODTABLE, // Weirdo array with its own unshared methodtable (e.g., System.Object[])
393 ARRAY_KIND_NOTARRAY, // Not an array
396 //---------------------------------------------------------------------------------------
398 // A couple Info calls need to understand what constitutes an "array", and what
399 // kinds of arrays there are. ArrayKindFromTypeHandle tries to put some of this
400 // knowledge in a single place
403 // th - TypeHandle to inspect
406 // ARRAY_KIND describing th
409 inline ARRAY_KIND ArrayKindFromTypeHandle(TypeHandle th)
411 LIMITED_METHOD_CONTRACT;
415 return ARRAY_KIND_TYPEDESC;
418 if (!th.IsTypeDesc() && th.GetMethodTable()->IsArray())
420 return ARRAY_KIND_METHODTABLE;
423 return ARRAY_KIND_NOTARRAY;
426 #ifdef PROFILING_SUPPORTED
428 //---------------------------------------------------------------------------------------
429 // ModuleILHeap IUnknown implementation
431 // Function headers unnecessary, as MSDN adequately documents IUnknown
434 ULONG ModuleILHeap::AddRef()
436 // Lifetime of this object is controlled entirely by the CLR. This
437 // is created on first request, and is automatically destroyed when
438 // the profiler is detached.
443 ULONG ModuleILHeap::Release()
445 // Lifetime of this object is controlled entirely by the CLR. This
446 // is created on first request, and is automatically destroyed when
447 // the profiler is detached.
452 HRESULT ModuleILHeap::QueryInterface(REFIID riid, void ** pp)
462 if (riid == IID_IUnknown)
464 *pp = static_cast<IUnknown *>(this);
466 else if (riid == IID_IMethodMalloc)
468 *pp = static_cast<IMethodMalloc *>(this);
477 // CLR manages lifetime of this object, but in case that changes (or
478 // this code gets copied/pasted elsewhere), we'll still AddRef here so
479 // QI remains a good citizen either way.
485 //---------------------------------------------------------------------------------------
486 // Profiler entrypoint to allocate space from this module's heap.
489 // cb - size in bytes of allocation request
492 // pointer to allocated memory, or NULL if there was an error
494 void * STDMETHODCALLTYPE ModuleILHeap::Alloc(ULONG cb)
501 // (see GC_TRIGGERS comment below)
504 // Allocations using loader heaps below enter a critsec, which switches
505 // to preemptive, which is effectively a GC trigger
514 LOG((LF_CORPROF, LL_INFO1000, "**PROF: ModuleILHeap::Alloc 0x%08xp.\n", cb));
521 return new (nothrow) BYTE[cb];
524 //---------------------------------------------------------------------------------------
525 // The one and only instance of the IL heap
527 ModuleILHeap ModuleILHeap::s_Heap;
529 //---------------------------------------------------------------------------------------
530 // Implementation of ProfToEEInterfaceImpl's IUnknown
533 // The VM controls the lifetime of ProfToEEInterfaceImpl, not the
534 // profiler. We'll automatically take care of cleanup when profilers
535 // unload and detach.
538 ULONG STDMETHODCALLTYPE ProfToEEInterfaceImpl::AddRef()
540 LIMITED_METHOD_CONTRACT;
544 ULONG STDMETHODCALLTYPE ProfToEEInterfaceImpl::Release()
546 LIMITED_METHOD_CONTRACT;
550 COM_METHOD ProfToEEInterfaceImpl::QueryInterface(REFIID id, void ** pInterface)
552 if (pInterface == NULL)
557 if (id == IID_ICorProfilerInfo)
559 *pInterface = static_cast<ICorProfilerInfo *>(this);
561 else if (id == IID_ICorProfilerInfo2)
563 *pInterface = static_cast<ICorProfilerInfo2 *>(this);
565 else if (id == IID_ICorProfilerInfo3)
567 *pInterface = static_cast<ICorProfilerInfo3 *>(this);
569 else if (id == IID_ICorProfilerInfo4)
571 *pInterface = static_cast<ICorProfilerInfo4 *>(this);
573 else if (id == IID_ICorProfilerInfo5)
575 *pInterface = static_cast<ICorProfilerInfo5 *>(this);
577 else if (id == IID_ICorProfilerInfo6)
579 *pInterface = static_cast<ICorProfilerInfo6 *>(this);
581 else if (id == IID_ICorProfilerInfo7)
583 *pInterface = static_cast<ICorProfilerInfo7 *>(this);
585 else if (id == IID_ICorProfilerInfo8)
587 *pInterface = static_cast<ICorProfilerInfo8 *>(this);
589 else if (id == IID_ICorProfilerInfo9)
591 *pInterface = static_cast<ICorProfilerInfo9 *>(this);
593 else if (id == IID_ICorProfilerInfo10)
595 *pInterface = static_cast<ICorProfilerInfo10 *>(this);
597 else if (id == IID_IUnknown)
599 *pInterface = static_cast<IUnknown *>(static_cast<ICorProfilerInfo *>(this));
604 return E_NOINTERFACE;
607 // CLR manages lifetime of this object, but in case that changes (or
608 // this code gets copied/pasted elsewhere), we'll still AddRef here so
609 // QI remains a good citizen either way.
614 #endif // PROFILING_SUPPORTED
616 //---------------------------------------------------------------------------------------
618 // GC-related helpers. These are called from elsewhere in the EE to determine profiler
619 // state, and to update the profiling API with info from the GC.
622 //---------------------------------------------------------------------------------------
624 // ProfilerObjectAllocatedCallback is called if a profiler is attached, requesting
625 // ObjectAllocated callbacks.
628 // objref - Reference to newly-allocated object
629 // classId - ClassID of newly-allocated object
632 void __stdcall ProfilerObjectAllocatedCallback(OBJECTREF objref, ClassID classId)
642 TypeHandle th = OBJECTREFToObject(objref)->GetTypeHandle();
644 // WARNING: objref can move as a result of the ObjectAllocated() call below if
645 // the profiler causes a GC, so any operations on the objref should occur above
646 // this comment (unless you're prepared to add a GCPROTECT around the objref).
648 #ifdef PROFILING_SUPPORTED
649 // Notify the profiler of the allocation
652 BEGIN_PIN_PROFILER(CORProfilerTrackAllocations() || CORProfilerTrackLargeAllocations());
653 // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs.
654 // Thus we strip any instantiations of the ClassID (which is really a type handle) here.
655 g_profControlBlock.pProfInterface->ObjectAllocated(
656 (ObjectID) OBJECTREFToObject(objref),
660 #endif // PROFILING_SUPPORTED
663 //---------------------------------------------------------------------------------------
665 // Wrapper around the GC Started callback
668 // generation - Generation being collected
669 // induced - Was this GC induced by GC.Collect?
672 void __stdcall GarbageCollectionStartedCallback(int generation, BOOL induced)
678 MODE_ANY; // can be called even on GC threads
682 #ifdef PROFILING_SUPPORTED
684 // Mark that we are starting a GC. This will allow profilers to do limited object inspection
685 // during callbacks that occur while a GC is happening.
687 g_profControlBlock.fGCInProgress = TRUE;
689 // Notify the profiler of start of the collection
691 BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
692 BOOL generationCollected[COR_PRF_GC_LARGE_OBJECT_HEAP+1];
693 if (generation == COR_PRF_GC_GEN_2)
694 generation = COR_PRF_GC_LARGE_OBJECT_HEAP;
695 for (int gen = 0; gen <= COR_PRF_GC_LARGE_OBJECT_HEAP; gen++)
696 generationCollected[gen] = gen <= generation;
698 g_profControlBlock.pProfInterface->GarbageCollectionStarted(
699 COR_PRF_GC_LARGE_OBJECT_HEAP+1,
701 induced ? COR_PRF_GC_INDUCED : COR_PRF_GC_OTHER);
704 #endif // PROFILING_SUPPORTED
707 //---------------------------------------------------------------------------------------
709 // Wrapper around the GC Finished callback
712 void __stdcall GarbageCollectionFinishedCallback()
718 MODE_ANY; // can be called even on GC threads
722 #ifdef PROFILING_SUPPORTED
723 // Notify the profiler of end of the collection
725 BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
726 g_profControlBlock.pProfInterface->GarbageCollectionFinished();
730 // Mark that GC is finished.
731 g_profControlBlock.fGCInProgress = FALSE;
732 #endif // PROFILING_SUPPORTED
735 #ifdef PROFILING_SUPPORTED
736 //---------------------------------------------------------------------------------------
738 // Describes a GC generation by number and address range
741 struct GenerationDesc
746 BYTE *rangeEndReserved;
749 struct GenerationTable
753 static const ULONG defaultCapacity = 4; // that's the minimum for 3 generation plus the large object heap
754 GenerationTable *prev;
755 GenerationDesc *genDescTable;
758 #define GENERATION_TABLE_MAGIC 0x34781256
759 #define GENERATION_TABLE_BAD_MAGIC 0x55aa55aa
764 //---------------------------------------------------------------------------------------
766 // This is a callback used by the GC when we call GCHeapUtilities::DiagDescrGenerations
767 // (from UpdateGenerationBounds() below). The GC gives us generation information through
768 // this callback, which we use to update the GenerationDesc in the corresponding
772 // context - The containing GenerationTable
773 // generation - Generation number
774 // rangeStart - Address where generation starts
775 // rangeEnd - Address where generation ends
776 // rangeEndReserved - Address where generation reserved space ends
780 static void GenWalkFunc(void * context,
784 BYTE * rangeEndReserved)
790 MODE_ANY; // can be called even on GC threads
791 PRECONDITION(CheckPointer(context));
792 PRECONDITION(0 <= generation && generation <= 3);
793 PRECONDITION(CheckPointer(rangeStart));
794 PRECONDITION(CheckPointer(rangeEnd));
795 PRECONDITION(CheckPointer(rangeEndReserved));
798 GenerationTable *generationTable = (GenerationTable *)context;
800 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
802 ULONG count = generationTable->count;
803 if (count >= generationTable->capacity)
805 ULONG newCapacity = generationTable->capacity == 0 ? GenerationTable::defaultCapacity : generationTable->capacity * 2;
806 GenerationDesc *newGenDescTable = new (nothrow) GenerationDesc[newCapacity];
807 if (newGenDescTable == NULL)
809 // if we can't allocate a bigger table, we'll have to ignore this call
812 memcpy(newGenDescTable, generationTable->genDescTable, sizeof(generationTable->genDescTable[0]) * generationTable->count);
813 delete[] generationTable->genDescTable;
814 generationTable->genDescTable = newGenDescTable;
815 generationTable->capacity = newCapacity;
817 _ASSERTE(count < generationTable->capacity);
819 GenerationDesc *genDescTable = generationTable->genDescTable;
821 genDescTable[count].generation = generation;
822 genDescTable[count].rangeStart = rangeStart;
823 genDescTable[count].rangeEnd = rangeEnd;
824 genDescTable[count].rangeEndReserved = rangeEndReserved;
826 generationTable->count = count + 1;
829 // This is the table of generation bounds updated by the gc
830 // and read by the profiler. So this is a single writer,
831 // multiple readers scenario.
832 static GenerationTable *s_currentGenerationTable;
834 // The generation table is updated atomically by replacing the
835 // pointer to it. The only tricky part is knowing when
836 // the old table can be deleted.
837 static Volatile<LONG> s_generationTableLock;
839 // This is just so we can assert there's a single writer
840 #ifdef ENABLE_CONTRACTS
841 static Volatile<LONG> s_generationTableWriterCount;
843 #endif // PROFILING_SUPPORTED
845 //---------------------------------------------------------------------------------------
847 // This is called from the gc to push a new set of generation bounds
850 void __stdcall UpdateGenerationBounds()
856 MODE_ANY; // can be called even on GC threads
857 #ifdef PROFILING_SUPPORTED
858 PRECONDITION(FastInterlockIncrement(&s_generationTableWriterCount) == 1);
859 POSTCONDITION(FastInterlockDecrement(&s_generationTableWriterCount) == 0);
860 #endif // PROFILING_SUPPORTED
863 #ifdef PROFILING_SUPPORTED
864 // Notify the profiler of start of the collection
865 if (CORProfilerTrackGC() || CORProfilerTrackBasicGC())
867 // generate a new generation table
868 GenerationTable *newGenerationTable = new (nothrow) GenerationTable();
869 if (newGenerationTable == NULL)
871 newGenerationTable->count = 0;
872 newGenerationTable->capacity = GenerationTable::defaultCapacity;
873 // if there is already a current table, use its count as a guess for the capacity
874 if (s_currentGenerationTable != NULL)
875 newGenerationTable->capacity = s_currentGenerationTable->count;
876 newGenerationTable->prev = NULL;
877 newGenerationTable->genDescTable = new (nothrow) GenerationDesc[newGenerationTable->capacity];
878 if (newGenerationTable->genDescTable == NULL)
879 newGenerationTable->capacity = 0;
882 newGenerationTable->magic = GENERATION_TABLE_MAGIC;
884 // fill in the values by calling back into the gc, which will report
885 // the ranges by calling GenWalkFunc for each one
886 IGCHeap *hp = GCHeapUtilities::GetGCHeap();
887 hp->DiagDescrGenerations(GenWalkFunc, newGenerationTable);
889 // remember the old table and plug in the new one
890 GenerationTable *oldGenerationTable = s_currentGenerationTable;
891 s_currentGenerationTable = newGenerationTable;
893 // WARNING: tricky code!
895 // We sample the generation table lock *after* plugging in the new table
896 // We do so using an interlocked operation so the cpu can't reorder
897 // the write to the s_currentGenerationTable with the increment.
898 // If the interlocked increment returns 1, we know nobody can be using
899 // the old table (readers increment the lock before using the table,
900 // and decrement it afterwards). Any new readers coming in
901 // will use the new table. So it's safe to delete the old
903 // On the other hand, if the interlocked increment returns
904 // something other than one, we put the old table on a list
905 // dangling off of the new one. Next time around, we'll try again
906 // deleting any old tables.
907 if (FastInterlockIncrement(&s_generationTableLock) == 1)
909 // We know nobody can be using any of the old tables
910 while (oldGenerationTable != NULL)
912 _ASSERTE(oldGenerationTable->magic == GENERATION_TABLE_MAGIC);
914 oldGenerationTable->magic = GENERATION_TABLE_BAD_MAGIC;
916 GenerationTable *temp = oldGenerationTable;
917 oldGenerationTable = oldGenerationTable->prev;
918 delete[] temp->genDescTable;
924 // put the old table on a list
925 newGenerationTable->prev = oldGenerationTable;
927 FastInterlockDecrement(&s_generationTableLock);
929 #endif // PROFILING_SUPPORTED
933 #ifdef PROFILING_SUPPORTED
935 //---------------------------------------------------------------------------------------
937 // Determines whether we are in a window to allow object inspection.
940 // Returns S_OK if we can determine that we are in a window to allow object
941 // inspection. Otherwise a failure HRESULT is returned
944 HRESULT AllowObjectInspection()
950 MODE_ANY; // tests for preemptive mode dynamically as its main function so contract enforcement is not appropriate
955 // Check first to see if we are in the process of doing a GC and presume that the profiler
956 // is making this object inspection from the same thread that notified of a valid ObjectID.
958 if (g_profControlBlock.fGCInProgress)
964 // Thus we must have a managed thread, and it must be in coop mode.
965 // (That will also guarantee we're in a callback).
967 Thread * pThread = GetThreadNULLOk();
971 return CORPROF_E_NOT_MANAGED_THREAD;
974 // Note this is why we don't enforce the contract of being in cooperative mode the whole point
975 // is that clients of this fellow want to return a robust error if not cooperative
976 // so technically they are mode_any although the only true preemptive support they offer
977 // is graceful failure in that case
978 if (!pThread->PreemptiveGCDisabled())
980 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
986 //---------------------------------------------------------------------------------------
988 // helper functions for the GC events
992 #endif // PROFILING_SUPPORTED
994 #if defined(PROFILING_SUPPORTED) || defined(FEATURE_EVENT_TRACE)
996 //---------------------------------------------------------------------------------------
998 // It's generally unsafe for profiling API code to call Get(GCSafe)TypeHandle() on
999 // objects, since we can encounter objects on the heap whose types belong to unloading
1000 // AppDomains. In such cases, getting the type handle of the object could AV. Use this
1001 // function instead, which will return NULL for potentially unloaded types.
1004 // pObj - Object * whose ClassID is desired
1007 // ClassID of the object, if it's safe to look it up. Else NULL.
1010 ClassID SafeGetClassIDFromObject(Object * pObj)
1019 TypeHandle th = pObj->GetGCSafeTypeHandleIfPossible();
1025 return TypeHandleToClassID(th);
1028 //---------------------------------------------------------------------------------------
1030 // Callback of type walk_fn used by IGCHeap::DiagWalkObject. Keeps a count of each
1031 // object reference found.
1034 // pBO - Object reference encountered in walk
1035 // context - running count of object references encountered
1038 // Always returns TRUE to object walker so it walks the entire object
1041 bool CountContainedObjectRef(Object * pBO, void * context)
1043 LIMITED_METHOD_CONTRACT;
1044 // Increase the count
1045 (*((size_t *)context))++;
1050 //---------------------------------------------------------------------------------------
1052 // Callback of type walk_fn used by IGCHeap::DiagWalkObject. Stores each object reference
1053 // encountered into an array.
1056 // pBO - Object reference encountered in walk
1057 // context - Array of locations within the walked object that point to other
1058 // objects. On entry, (*context) points to the next unfilled array
1059 // entry. On exit, that location is filled, and (*context) is incremented
1060 // to point to the next entry.
1063 // Always returns TRUE to object walker so it walks the entire object
1066 bool SaveContainedObjectRef(Object * pBO, void * context)
1068 LIMITED_METHOD_CONTRACT;
1070 **((Object ***)context) = pBO;
1072 // Now increment the array pointer
1074 // Note that HeapWalkHelper has already walked the references once to count them up,
1075 // and then allocated an array big enough to hold those references. First time this
1076 // callback is called for a given object, (*context) points to the first entry in the
1077 // array. So "blindly" incrementing (*context) here and using it next time around
1078 // for the next reference, over and over again, should be safe.
1079 (*((Object ***)context))++;
1084 typedef struct _ObjectRefOffsetTuple
1087 SIZE_T* pCurObjOffset;
1088 } ObjectRefOffsetTuple;
1090 //---------------------------------------------------------------------------------------
1092 // Callback of type walk_fn used by IGCHeap::DiagWalkObject. Stores each object reference
1093 // encountered into an array.
1096 // o - original object
1097 // pBO - Object reference encountered in walk
1098 // context - Array of locations within the walked object that point to other
1099 // objects. On entry, (*context) points to the next unfilled array
1100 // entry. On exit, that location is filled, and (*context) is incremented
1101 // to point to the next entry.
1104 // Always returns TRUE to object walker so it walks the entire object
1107 bool SaveContainedObjectRef2(Object* o, uint8_t** pBO, void* context)
1109 LIMITED_METHOD_CONTRACT;
1111 auto x = (ObjectRefOffsetTuple*)context;
1112 *((Object **)(x->pCurObjRef)) = (Object *)*pBO;
1113 *((SIZE_T **)(x->pCurObjOffset)) = (SIZE_T*)((uint8_t*)pBO - (uint8_t*)o);
1121 //---------------------------------------------------------------------------------------
1123 // Callback of type walk_fn used by the GC when walking the heap, to help profapi and ETW
1124 // track objects. This guy orchestrates the use of the above callbacks which dig
1125 // into object references contained each object encountered by this callback.
1126 // This method is defined when either GC_PROFILING is defined or FEATURE_EVENT_TRACING
1127 // is defined and can operate fully when only one of the two is defined.
1130 // pBO - Object reference encountered on the heap
1131 // pvContext - Pointer to ProfilerWalkHeapContext, containing ETW context built up
1132 // during this GC, and which remembers if profapi-profiler is supposed to be called.
1135 // BOOL indicating whether the heap walk should continue.
1139 extern bool s_forcedGCInProgress;
1141 bool HeapWalkHelper(Object * pBO, void * pvContext)
1151 OBJECTREF * arrObjRef = NULL;
1152 size_t cNumRefs = 0;
1153 bool bOnStack = false;
1154 MethodTable * pMT = pBO->GetMethodTable();
1156 ProfilerWalkHeapContext * pProfilerWalkHeapContext = (ProfilerWalkHeapContext *) pvContext;
1158 if (pMT->ContainsPointersOrCollectible())
1160 // First round through calculates the number of object refs for this class
1161 GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &CountContainedObjectRef, (void *)&cNumRefs);
1165 // Create an array to contain all of the refs for this object
1166 bOnStack = cNumRefs <= 32 ? true : false;
1170 // It's small enough, so just allocate on the stack
1171 arrObjRef = (OBJECTREF *)_alloca(cNumRefs * sizeof(OBJECTREF));
1175 // Otherwise, allocate from the heap
1176 arrObjRef = new (nothrow) OBJECTREF[cNumRefs];
1184 // Second round saves off all of the ref values
1185 OBJECTREF * pCurObjRef = arrObjRef;
1186 GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &SaveContainedObjectRef, (void *)&pCurObjRef);
1190 HRESULT hr = E_FAIL;
1192 #if defined(GC_PROFILING)
1193 if (pProfilerWalkHeapContext->fProfilerPinned)
1195 // It is not safe and could be overflowed to downcast size_t to ULONG on WIN64.
1196 // However, we have to do this dangerous downcast here to comply with the existing Profiling COM interface.
1197 // We are currently evaluating ways to fix this potential overflow issue.
1198 hr = g_profControlBlock.pProfInterface->ObjectReference(
1200 SafeGetClassIDFromObject(pBO),
1202 (ObjectID *) arrObjRef);
1206 #ifdef FEATURE_EVENT_TRACE
1207 if (s_forcedGCInProgress &&
1208 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
1209 TRACE_LEVEL_INFORMATION,
1210 CLR_GCHEAPDUMP_KEYWORD))
1212 ETW::GCLog::ObjectReference(
1213 pProfilerWalkHeapContext,
1215 (ULONGLONG) SafeGetClassIDFromObject(pBO),
1217 (Object **) arrObjRef);
1220 #endif // FEATURE_EVENT_TRACE
1222 // If the data was not allocated on the stack, need to clean it up.
1223 if ((arrObjRef != NULL) && !bOnStack)
1225 delete [] arrObjRef;
1228 // Return TRUE iff we want to the heap walk to continue. The only way we'd abort the
1229 // heap walk is if we're issuing profapi callbacks, and the profapi profiler
1230 // intentionally returned a failed HR (as its request that we stop the walk). There's
1231 // a potential conflict here. If a profapi profiler and an ETW profiler are both
1232 // monitoring the heap dump, and the profapi profiler requests to abort the walk (but
1233 // the ETW profiler may not want to abort the walk), then what do we do? The profapi
1234 // profiler gets precedence. We don't want to accidentally send more callbacks to a
1235 // profapi profiler that explicitly requested an abort. The ETW profiler will just
1236 // have to deal. In theory, I could make the code more complex by remembering that a
1237 // profapi profiler requested to abort the dump but an ETW profiler is still
1238 // attached, and then intentionally inhibit the remainder of the profapi callbacks
1239 // for this GC. But that's unnecessary complexity. In practice, it should be
1240 // extremely rare that a profapi profiler is monitoring heap dumps AND an ETW
1241 // profiler is also monitoring heap dumps.
1242 return (pProfilerWalkHeapContext->fProfilerPinned) ? SUCCEEDED(hr) : TRUE;
1245 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACING)
1247 #ifdef PROFILING_SUPPORTED
1248 //---------------------------------------------------------------------------------------
1250 // Callback of type walk_fn used by the GC when walking the heap, to help profapi
1251 // track objects. This is really just a wrapper around
1252 // EEToProfInterfaceImpl::AllocByClass, which does the real work
1255 // pBO - Object reference encountered on the heap
1256 // pv - Structure used by EEToProfInterfaceImpl::AllocByClass to do its work.
1259 // BOOL indicating whether the heap walk should continue.
1262 // Currently always returns TRUE
1265 bool AllocByClassHelper(Object * pBO, void * pv)
1274 _ASSERTE(pv != NULL);
1277 BEGIN_PIN_PROFILER(CORProfilerPresent());
1278 // Pass along the call
1279 g_profControlBlock.pProfInterface->AllocByClass(
1281 SafeGetClassIDFromObject(pBO),
1289 #endif // PROFILING_SUPPORTED
1290 #if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1292 //---------------------------------------------------------------------------------------
1294 // Callback of type promote_func called by GC while scanning roots (in GCProfileWalkHeap,
1295 // called after the collection). Wrapper around EEToProfInterfaceImpl::RootReference2,
1296 // which does the real work.
1299 // pObj - Object reference encountered
1300 /// ppRoot - Address that references ppObject (can be interior pointer)
1301 // pSC - ProfilingScanContext * containing the root kind and GCReferencesData used
1302 // by RootReference2
1303 // dwFlags - Properties of the root as GC_CALL* constants (this function converts
1304 // to COR_PRF_GC_ROOT_FLAGS.
1307 void ScanRootsHelper(Object* pObj, Object ** ppRoot, ScanContext *pSC, uint32_t dwFlags)
1317 // RootReference2 can return E_OUTOFMEMORY, and we're swallowing that.
1318 // Furthermore, we can't really handle it because we're callable during GC promotion.
1319 // On the other hand, this only means profiling information will be incomplete,
1320 // so it's ok to swallow E_OUTOFMEMORY.
1324 ProfilingScanContext *pPSC = (ProfilingScanContext *)pSC;
1326 DWORD dwEtwRootFlags = 0;
1327 if (dwFlags & GC_CALL_INTERIOR)
1328 dwEtwRootFlags |= kEtwGCRootFlagsInterior;
1329 if (dwFlags & GC_CALL_PINNED)
1330 dwEtwRootFlags |= kEtwGCRootFlagsPinning;
1332 #if defined(GC_PROFILING)
1333 void *rootID = NULL;
1334 switch (pPSC->dwEtwRootKind)
1336 case kEtwGCRootKindStack:
1340 case kEtwGCRootKindHandle:
1341 _ASSERT(!"Shouldn't see handle here");
1343 case kEtwGCRootKindFinalizer:
1348 // Notify profiling API of the root
1349 if (pPSC->fProfilerPinned)
1351 // Let the profiling code know about this root reference
1352 g_profControlBlock.pProfInterface->
1353 RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId));
1357 #ifdef FEATURE_EVENT_TRACE
1358 // Notify ETW of the root
1359 if (s_forcedGCInProgress &&
1360 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
1361 TRACE_LEVEL_INFORMATION,
1362 CLR_GCHEAPDUMP_KEYWORD))
1364 ETW::GCLog::RootReference(
1365 NULL, // handle is NULL, cuz this is a non-HANDLE root
1366 pObj, // object being rooted
1367 NULL, // pSecondaryNodeForDependentHandle is NULL, cuz this isn't a dependent handle
1368 FALSE, // is dependent handle
1370 dwFlags, // dwGCFlags
1373 #endif // FEATURE_EVENT_TRACE
1376 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1377 #ifdef PROFILING_SUPPORTED
1379 //---------------------------------------------------------------------------------------
1381 // Private ProfToEEInterfaceImpl maintenance functions
1385 //---------------------------------------------------------------------------------------
1387 // Initialize ProfToEEInterfaceImpl (including ModuleILHeap statics)
1390 // HRESULT indicating success
1393 HRESULT ProfToEEInterfaceImpl::Init()
1404 LOG((LF_CORPROF, LL_INFO1000, "**PROF: Init.\n"));
1407 if (ProfilingAPIUtility::ShouldInjectProfAPIFault(kProfAPIFault_StartupInternal))
1409 return E_OUTOFMEMORY;
1417 //---------------------------------------------------------------------------------------
1419 // Destroy ProfToEEInterfaceImpl (including ModuleILHeap statics)
1422 ProfToEEInterfaceImpl::~ProfToEEInterfaceImpl()
1432 LOG((LF_CORPROF, LL_INFO1000, "**PROF: Terminate.\n"));
1435 //---------------------------------------------------------------------------------------
1437 // Obsolete info functions
1440 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionInterface(IUnknown **)
1442 LIMITED_METHOD_CONTRACT;
1446 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionIThisThread(IUnknown **)
1448 LIMITED_METHOD_CONTRACT;
1452 HRESULT ProfToEEInterfaceImpl::BeginInprocDebugging(BOOL, DWORD *)
1454 LIMITED_METHOD_CONTRACT;
1458 HRESULT ProfToEEInterfaceImpl::EndInprocDebugging(DWORD)
1460 LIMITED_METHOD_CONTRACT;
1464 HRESULT ProfToEEInterfaceImpl::SetFunctionReJIT(FunctionID)
1466 LIMITED_METHOD_CONTRACT;
1473 //---------------------------------------------------------------------------------------
1475 // *******************************
1476 // Public Profiler->EE entrypoints
1477 // *******************************
1479 // ProfToEEInterfaceImpl implementation of public ICorProfilerInfo* methods
1481 // NOTE: All ICorProfilerInfo* method implementations must follow the rules stated
1482 // at the top of this file!
1485 // See corprof.idl / MSDN for detailed comments about each of these public
1486 // functions, their parameters, return values, etc.
1488 HRESULT ProfToEEInterfaceImpl::SetEventMask(DWORD dwEventMask)
1502 EE_THREAD_NOT_REQUIRED;
1509 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1512 "**PROF: SetEventMask 0x%08x.\n",
1515 _ASSERTE(CORProfilerPresentOrInitializing());
1517 return g_profControlBlock.pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */);
1520 HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHigh)
1534 EE_THREAD_NOT_REQUIRED;
1541 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1544 "**PROF: SetEventMask2 0x%08x, 0x%08x.\n",
1545 dwEventsLow, dwEventsHigh));
1547 _ASSERTE(CORProfilerPresentOrInitializing());
1549 return g_profControlBlock.pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh);
1553 HRESULT ProfToEEInterfaceImpl::GetHandleFromThread(ThreadID threadId, HANDLE *phThread)
1567 EE_THREAD_NOT_REQUIRED;
1575 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1578 "**PROF: GetHandleFromThread 0x%p.\n",
1581 if (!IsManagedThread(threadId))
1583 return E_INVALIDARG;
1588 HANDLE hThread = ((Thread *)threadId)->GetThreadHandle();
1590 if (hThread == INVALID_HANDLE_VALUE)
1594 *phThread = hThread;
1599 HRESULT ProfToEEInterfaceImpl::GetObjectSize(ObjectID objectId, ULONG *pcSize)
1609 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
1613 EE_THREAD_NOT_REQUIRED;
1621 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1624 "**PROF: GetObjectSize 0x%p.\n",
1627 if (objectId == NULL)
1629 return E_INVALIDARG;
1632 HRESULT hr = AllowObjectInspection();
1638 // Get the object pointer
1639 Object *pObj = reinterpret_cast<Object *>(objectId);
1644 SIZE_T size = pObj->GetSize();
1646 if(size < MIN_OBJECT_SIZE)
1648 size = PtrAlign(size);
1651 if (size > ULONG_MAX)
1653 *pcSize = ULONG_MAX;
1654 return COR_E_OVERFLOW;
1656 *pcSize = (ULONG)size;
1663 HRESULT ProfToEEInterfaceImpl::GetObjectSize2(ObjectID objectId, SIZE_T *pcSize)
1673 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
1677 EE_THREAD_NOT_REQUIRED;
1685 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1688 "**PROF: GetObjectSize2 0x%p.\n",
1691 if (objectId == NULL)
1693 return E_INVALIDARG;
1696 HRESULT hr = AllowObjectInspection();
1702 // Get the object pointer
1703 Object *pObj = reinterpret_cast<Object *>(objectId);
1708 SIZE_T size = pObj->GetSize();
1710 if(size < MIN_OBJECT_SIZE)
1712 size = PtrAlign(size);
1723 HRESULT ProfToEEInterfaceImpl::IsArrayClass(
1724 /* [in] */ ClassID classId,
1725 /* [out] */ CorElementType *pBaseElemType,
1726 /* [out] */ ClassID *pBaseClassId,
1727 /* [out] */ ULONG *pcRank)
1739 EE_THREAD_NOT_REQUIRED;
1747 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1750 "**PROF: IsArrayClass 0x%p.\n",
1755 if (classId == NULL)
1757 return E_INVALIDARG;
1760 TypeHandle th = TypeHandle::FromPtr((void *)classId);
1762 ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(th);
1764 // If this is indeed an array class, get some info about it
1769 _ASSERTE(!"Unexpected return from ArrayKindFromTypeHandle()");
1774 case ARRAY_KIND_TYPEDESC:
1776 // This is actually an array, so cast it up
1777 ArrayTypeDesc *pArr = th.AsArray();
1779 // Fill in the type if they want it
1780 if (pBaseElemType != NULL)
1782 *pBaseElemType = pArr->GetArrayElementTypeHandle().GetVerifierCorElementType();
1785 // If this is an array of classes and they wish to have the base type
1786 // If there is no associated class with this type, then there's no problem
1787 // because GetClass returns NULL which is the default we want to return in
1789 // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
1790 if (pBaseClassId != NULL)
1792 *pBaseClassId = TypeHandleToClassID(pArr->GetTypeParam());
1795 // If they want the number of dimensions of the array
1798 *pcRank = (ULONG) pArr->GetRank();
1801 // S_OK indicates that this was indeed an array
1805 case ARRAY_KIND_METHODTABLE:
1807 MethodTable *pArrMT = th.GetMethodTable();
1809 // Fill in the type if they want it
1810 if (pBaseElemType != NULL)
1812 *pBaseElemType = pArrMT->GetArrayElementType();
1815 // If this is an array of classes and they wish to have the base type.
1816 if (pBaseClassId != NULL)
1818 *pBaseClassId = TypeHandleToClassID(pArrMT->GetApproxArrayElementTypeHandle());
1821 // If they want the number of dimensions of the array
1824 *pcRank = (ULONG) pArrMT->GetRank();
1827 // S_OK indicates that this was indeed an array
1831 case ARRAY_KIND_NOTARRAY:
1833 if (pBaseClassId != NULL)
1835 *pBaseClassId = NULL;
1838 // This is not an array, S_FALSE indicates so.
1847 HRESULT ProfToEEInterfaceImpl::GetThreadInfo(ThreadID threadId, DWORD *pdwWin32ThreadId)
1861 EE_THREAD_NOT_REQUIRED;
1869 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1872 "**PROF: GetThreadInfo 0x%p.\n",
1875 if (!IsManagedThread(threadId))
1877 return E_INVALIDARG;
1880 if (pdwWin32ThreadId)
1882 *pdwWin32ThreadId = ((Thread *)threadId)->GetOSThreadId();
1888 HRESULT ProfToEEInterfaceImpl::GetCurrentThreadID(ThreadID *pThreadId)
1902 EE_THREAD_NOT_REQUIRED;
1910 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1913 "**PROF: GetCurrentThreadID.\n"));
1917 // No longer assert that GetThread doesn't return NULL, since callbacks
1918 // can now occur on non-managed threads (such as the GC helper threads)
1919 Thread * pThread = GetThreadNULLOk();
1921 // If pThread is null, then the thread has never run managed code and
1922 // so has no ThreadID
1923 if (!IsManagedThread(pThread))
1924 hr = CORPROF_E_NOT_MANAGED_THREAD;
1926 // Only provide value if they want it
1928 *pThreadId = (ThreadID) pThread;
1933 //---------------------------------------------------------------------------------------
1935 // Internal helper function to wrap a call into the JIT manager to get information about
1936 // a managed function based on IP
1939 // ip - IP address inside managed function of interest
1940 // ppCodeInfo - [out] information about the managed function based on IP
1943 // HRESULT indicating success or failure.
1947 HRESULT GetFunctionInfoInternal(LPCBYTE ip, EECodeInfo * pCodeInfo)
1954 EE_THREAD_NOT_REQUIRED;
1959 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
1960 // host (SQL). Corners will be cut to ensure this is the case
1961 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
1965 // Before calling into the code manager, ensure the GC heap has been
1966 // initialized--else the code manager will assert trying to get info from the heap.
1967 if (!IsGarbageCollectorFullyInitialized())
1969 return CORPROF_E_NOT_YET_AVAILABLE;
1972 if (ShouldAvoidHostCalls())
1974 ExecutionManager::ReaderLockHolder rlh(NoHostCalls);
1975 if (!rlh.Acquired())
1977 // Couldn't get the info. Try again later
1978 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
1981 pCodeInfo->Init((PCODE)ip, ExecutionManager::ScanNoReaderLock);
1985 pCodeInfo->Init((PCODE)ip);
1988 if (!pCodeInfo->IsValid())
1997 HRESULT GetFunctionFromIPInternal(LPCBYTE ip, EECodeInfo * pCodeInfo, BOOL failOnNoMetadata)
2004 EE_THREAD_NOT_REQUIRED;
2009 _ASSERTE (pCodeInfo != NULL);
2011 HRESULT hr = GetFunctionInfoInternal(ip, pCodeInfo);
2017 if (failOnNoMetadata)
2019 // never return a method that the user of the profiler API cannot use
2020 if (pCodeInfo->GetMethodDesc()->IsNoMetadata())
2030 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP(LPCBYTE ip, FunctionID * pFunctionId)
2044 EE_THREAD_NOT_REQUIRED;
2046 // Querying the code manager requires a reader lock. However, see
2047 // code:#DisableLockOnAsyncCalls
2048 DISABLED(CAN_TAKE_LOCK);
2050 // Asynchronous functions can be called at arbitrary times when runtime
2051 // is holding locks that cannot be reentered without causing deadlock.
2052 // This contract detects any attempts to reenter locks held at the time
2053 // this function was called.
2057 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2058 // host (SQL). Corners will be cut to ensure this is the case
2059 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2063 // See code:#DisableLockOnAsyncCalls
2064 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2066 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2069 "**PROF: GetFunctionFromIP 0x%p.\n",
2072 // This call is allowed asynchronously, but the JIT functions take a reader lock.
2073 // So we need to ensure the current thread hasn't been hijacked by a profiler while
2074 // it was holding the writer lock. Checking the ForbidSuspendThread region is a
2075 // sufficient test for this
2076 FAIL_IF_IN_FORBID_SUSPEND_REGION();
2080 EECodeInfo codeInfo;
2082 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2090 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2097 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP2(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
2104 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2105 // which can switch us to preemptive mode and trigger GCs
2112 EE_THREAD_NOT_REQUIRED;
2114 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2120 // See code:#DisableLockOnAsyncCalls
2121 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2123 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2124 kP2EEAllowableAfterAttach | kP2EETriggers,
2127 "**PROF: GetFunctionFromIP2 0x%p.\n",
2132 EECodeInfo codeInfo;
2134 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2142 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2145 if (pReJitId != NULL)
2147 MethodDesc * pMD = codeInfo.GetMethodDesc();
2148 *pReJitId = ReJitManager::GetReJitId(pMD, codeInfo.GetStartAddress());
2154 //*****************************************************************************
2155 // Given a function id, retrieve the metadata token and a reader api that
2156 // can be used against the token.
2157 //*****************************************************************************
2158 HRESULT ProfToEEInterfaceImpl::GetTokenAndMetaDataFromFunction(
2159 FunctionID functionId,
2176 EE_THREAD_NOT_REQUIRED;
2178 // PEFile::GetRWImporter and GetReadablePublicMetaDataInterface take locks
2184 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2187 "**PROF: GetTokenAndMetaDataFromFunction 0x%p.\n",
2190 if (functionId == NULL)
2192 return E_INVALIDARG;
2197 MethodDesc *pMD = FunctionIdToMethodDesc(functionId);
2199 // it's not safe to examine a methoddesc that has not been restored so do not do so
2200 if (!pMD->IsRestored())
2201 return CORPROF_E_DATAINCOMPLETE;
2205 *pToken = pMD->GetMemberDef();
2208 // don't bother with any of this module fetching if the metadata access isn't requested
2211 Module * pMod = pMD->GetModule();
2212 hr = pMod->GetReadablePublicMetaDataInterface(ofRead, riid, (LPVOID *) ppOut);
2218 //---------------------------------------------------------------------------------------
2219 // What follows are the GetCodeInfo* APIs and their helpers. The two helpers factor out
2220 // some of the common code to validate parameters and then determine the code info from
2221 // the start of the code. Each individual GetCodeInfo* API differs in how it uses these
2222 // helpers, particuarly in how it determines the start of the code (GetCodeInfo3 needs
2223 // to use the rejit manager to determine the code start, whereas the others do not).
2224 // Factoring out like this allows us to have statically determined contracts that differ
2225 // based on whether we need to use the rejit manager, which requires locking and
2227 //---------------------------------------------------------------------------------------
2230 HRESULT ValidateParametersForGetCodeInfo(
2231 MethodDesc * pMethodDesc,
2233 COR_PRF_CODE_INFO codeInfos[])
2235 LIMITED_METHOD_CONTRACT;
2237 if (pMethodDesc == NULL)
2239 return E_INVALIDARG;
2242 if ((cCodeInfos != 0) && (codeInfos == NULL))
2244 return E_INVALIDARG;
2247 // it's not safe to examine a methoddesc that has not been restored so do not do so
2248 if (!pMethodDesc->IsRestored())
2249 return CORPROF_E_DATAINCOMPLETE;
2251 if (pMethodDesc->HasClassOrMethodInstantiation() && pMethodDesc->IsTypicalMethodDefinition())
2253 // In this case, we used to replace pMethodDesc with its canonical instantiation
2254 // (FindOrCreateTypicalSharedInstantiation). However, a profiler should never be able
2255 // to get to this point anyway, since any MethodDesc a profiler gets from us
2256 // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
2257 // We assert here just in case a test proves me wrong, but generally we will
2258 // disallow this code path.
2259 _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetCodeInfo2");
2260 return E_INVALIDARG;
2266 HRESULT GetCodeInfoFromCodeStart(
2269 ULONG32 * pcCodeInfos,
2270 COR_PRF_CODE_INFO codeInfos[])
2278 // We need to take the ExecutionManager reader lock to find the
2279 // appropriate jit manager.
2283 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2284 // host (SQL). Corners will be cut to ensure this is the case
2285 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2289 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2291 ///////////////////////////////////
2292 // Get the code region info for this function. This is a multi step process.
2294 // MethodDesc ==> Code Address ==> JitMananger ==>
2295 // MethodToken ==> MethodRegionInfo
2297 // (Our caller handled the first step: MethodDesc ==> Code Address.)
2301 // On WIN64 we have a choice of where to go to find out the function address range size:
2302 // GC info (which is what we're doing below on all architectures) or the OS unwind
2303 // info, stored in the RUNTIME_FUNCTION structure. The latter produces
2304 // a SMALLER size than the former, because the latter excludes some data from
2305 // the set we report to the OS for unwind info. For example, switch tables can be
2306 // separated out from the regular code and not be reported as OS unwind info, and thus
2307 // those addresses will not appear in the range reported by the RUNTIME_FUNCTION gotten via:
2309 // IJitManager* pJitMan = ExecutionManager::FindJitMan((PBYTE)codeInfos[0].startAddress);
2310 // PRUNTIME_FUNCTION pfe = pJitMan->GetUnwindInfo((PBYTE)codeInfos[0].startAddress);
2311 // *pcCodeInfos = (ULONG) (pfe->EndAddress - pfe->BeginAddress);
2313 // (Note that GCInfo & OS unwind info report the same start address--it's the size that's
2316 // The advantage of using the GC info is that it's available on all architectures,
2317 // and it gives you a more complete picture of the addresses belonging to the function.
2319 // A disadvantage of using GC info is we'll report those extra addresses (like switch
2320 // tables) that a profiler might turn back around and use in a call to
2321 // GetFunctionFromIP. A profiler may expect we'd be able to map back any address
2322 // in the function's GetCodeInfo ranges back to that function's FunctionID (methoddesc). But
2323 // querying these extra addresses will cause GetFunctionFromIP to fail, as they're not
2324 // actually valid instruction addresses that the IP register can be set to.
2326 // The advantage wins out, so we're going with GC info everywhere.
2334 return CORPROF_E_FUNCTION_NOT_COMPILED;
2337 EECodeInfo codeInfo;
2338 hr = GetFunctionInfoInternal(
2341 if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
2343 _ASSERTE(ShouldAvoidHostCalls());
2348 return CORPROF_E_FUNCTION_NOT_COMPILED;
2351 IJitManager::MethodRegionInfo methodRegionInfo;
2352 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
2355 // Fill out the codeInfo structures with valuse from the
2358 // Note that we're assuming that a method will never be split into
2359 // more than two regions ... this is unlikely to change any time in
2362 if (NULL != codeInfos)
2367 // We have to return the two regions in the order that they would appear
2368 // if straight-line compiled
2370 if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2372 codeInfos[0].startAddress =
2373 (UINT_PTR)methodRegionInfo.hotStartAddress;
2374 codeInfos[0].size = methodRegionInfo.hotSize;
2378 _ASSERTE(methodRegionInfo.coldStartAddress != NULL);
2379 codeInfos[0].startAddress =
2380 (UINT_PTR)methodRegionInfo.coldStartAddress;
2381 codeInfos[0].size = methodRegionInfo.coldSize;
2384 if (NULL != methodRegionInfo.coldStartAddress)
2388 if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2390 codeInfos[1].startAddress =
2391 (UINT_PTR)methodRegionInfo.coldStartAddress;
2392 codeInfos[1].size = methodRegionInfo.coldSize;
2396 codeInfos[1].startAddress =
2397 (UINT_PTR)methodRegionInfo.hotStartAddress;
2398 codeInfos[1].size = methodRegionInfo.hotSize;
2405 if (NULL != pcCodeInfos)
2407 *pcCodeInfos = (NULL != methodRegionInfo.coldStartAddress) ? 2 : 1;
2414 //*****************************************************************************
2415 // Gets the location and size of a jitted function
2416 //*****************************************************************************
2418 HRESULT ProfToEEInterfaceImpl::GetCodeInfo(FunctionID functionId, LPCBYTE * pStart, ULONG * pcSize)
2432 EE_THREAD_NOT_REQUIRED;
2434 // (See locking contract comment in GetCodeInfoHelper.)
2435 DISABLED(CAN_TAKE_LOCK);
2437 // (See locking contract comment in GetCodeInfoHelper.)
2441 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2442 // host (SQL). Corners will be cut to ensure this is the case
2443 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2447 // See code:#DisableLockOnAsyncCalls
2448 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2450 // This is called asynchronously, but GetCodeInfoHelper() will
2451 // ensure we're not called at a dangerous time
2452 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2455 "**PROF: GetCodeInfo 0x%p.\n",
2458 // GetCodeInfo may be called asynchronously, and the JIT functions take a reader
2459 // lock. So we need to ensure the current thread hasn't been hijacked by a profiler while
2460 // it was holding the writer lock. Checking the ForbidSuspendThread region is a sufficient test for this
2461 FAIL_IF_IN_FORBID_SUSPEND_REGION();
2463 if (functionId == 0)
2465 return E_INVALIDARG;
2468 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2470 COR_PRF_CODE_INFO codeInfos[2];
2473 HRESULT hr = GetCodeInfoFromCodeStart(
2474 pMethodDesc->GetNativeCode(),
2475 _countof(codeInfos),
2479 if ((FAILED(hr)) || (0 == cCodeInfos))
2486 *pStart = reinterpret_cast< LPCBYTE >(codeInfos[0].startAddress);
2491 if (!FitsIn<ULONG>(codeInfos[0].size))
2493 return E_UNEXPECTED;
2495 *pcSize = static_cast<ULONG>(codeInfos[0].size);
2501 HRESULT ProfToEEInterfaceImpl::GetCodeInfo2(FunctionID functionId,
2503 ULONG32 * pcCodeInfos,
2504 COR_PRF_CODE_INFO codeInfos[])
2518 EE_THREAD_NOT_REQUIRED;
2520 // (See locking contract comment in GetCodeInfoHelper.)
2521 DISABLED(CAN_TAKE_LOCK);
2523 // (See locking contract comment in GetCodeInfoHelper.)
2527 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2528 // host (SQL). Corners will be cut to ensure this is the case
2529 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2531 PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2532 PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2536 // See code:#DisableLockOnAsyncCalls
2537 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2539 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2542 "**PROF: GetCodeInfo2 0x%p.\n",
2549 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2551 hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2554 hr = GetCodeInfoFromCodeStart(
2555 pMethodDesc->GetNativeCode(),
2561 EX_CATCH_HRESULT(hr);
2567 HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId,
2570 ULONG32* pcCodeInfos,
2571 COR_PRF_CODE_INFO codeInfos[])
2580 // We need to access the rejitmanager, which means taking locks, which means we
2588 EE_THREAD_NOT_REQUIRED;
2590 // We need to access the rejitmanager, which means taking locks
2594 PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2595 PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2599 // See code:#DisableLockOnAsyncCalls
2600 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2602 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2603 kP2EEAllowableAfterAttach | kP2EETriggers,
2606 "**PROF: GetCodeInfo3 0x%p 0x%p.\n",
2607 functionId, reJitId));
2613 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2615 hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2618 PCODE pCodeStart = NULL;
2619 CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
2621 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
2623 ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMethodDesc, reJitId);
2625 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMethodDesc);
2626 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
2628 // Now that tiered compilation can create more than one jitted code version for the same rejit id
2629 // we are arbitrarily choosing the first one to return. To address a specific version of native code
2630 // use GetCodeInfo4.
2631 pCodeStart = iter->GetNativeCode();
2636 hr = GetCodeInfoFromCodeStart(pCodeStart,
2642 EX_CATCH_HRESULT(hr);
2648 HRESULT ProfToEEInterfaceImpl::GetEventMask(DWORD * pdwEvents)
2662 EE_THREAD_NOT_REQUIRED;
2671 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2674 "**PROF: GetEventMask.\n"));
2676 if (pdwEvents == NULL)
2678 return E_INVALIDARG;
2681 *pdwEvents = g_profControlBlock.dwEventMask;
2685 HRESULT ProfToEEInterfaceImpl::GetEventMask2(DWORD *pdwEventsLow, DWORD *pdwEventsHigh)
2699 EE_THREAD_NOT_REQUIRED;
2708 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2711 "**PROF: GetEventMask2.\n"));
2713 if ((pdwEventsLow == NULL) || (pdwEventsHigh == NULL))
2715 return E_INVALIDARG;
2718 *pdwEventsLow = g_profControlBlock.dwEventMask;
2719 *pdwEventsHigh = g_profControlBlock.dwEventMaskHigh;
2724 void ProfToEEInterfaceImpl::MethodTableCallback(void* context, void* objectUNSAFE)
2734 // each callback identifies the address of a method table within the frozen object segment
2735 // that pointer is an object ID by definition -- object references point to the method table
2736 CDynArray< ObjectID >* objects = reinterpret_cast< CDynArray< ObjectID >* >(context);
2738 *objects->Append() = reinterpret_cast< ObjectID >(objectUNSAFE);
2742 void ProfToEEInterfaceImpl::ObjectRefCallback(void* context, void* objectUNSAFE)
2744 // we don't care about embedded object references, ignore them
2748 HRESULT ProfToEEInterfaceImpl::EnumModuleFrozenObjects(ModuleID moduleID,
2749 ICorProfilerObjectEnum** ppEnum)
2763 EE_THREAD_NOT_REQUIRED;
2771 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2774 "**PROF: EnumModuleFrozenObjects 0x%p.\n",
2779 return E_INVALIDARG;
2782 Module* pModule = reinterpret_cast< Module* >(moduleID);
2783 if (pModule == NULL || pModule->IsBeingUnloaded())
2785 return CORPROF_E_DATAINCOMPLETE;
2792 // If we don't support frozen objects at all, then just return empty
2794 *ppEnum = new ProfilerObjectEnum();
2796 EX_CATCH_HRESULT(hr);
2804 * GetArrayObjectInfo
2806 * This function returns informatin about array objects. In particular, the dimensions
2807 * and where the data buffer is stored.
2810 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfo(ObjectID objectId,
2811 ULONG32 cDimensionSizes,
2812 ULONG32 pDimensionSizes[],
2813 int pDimensionLowerBounds[],
2824 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
2833 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2836 "**PROF: GetArrayObjectInfo 0x%p.\n",
2839 if (objectId == NULL)
2841 return E_INVALIDARG;
2844 if ((pDimensionSizes == NULL) ||
2845 (pDimensionLowerBounds == NULL) ||
2848 return E_INVALIDARG;
2851 HRESULT hr = AllowObjectInspection();
2857 Object * pObj = reinterpret_cast<Object *>(objectId);
2859 // GC callbacks may come from a non-EE thread, which is considered permanently preemptive.
2860 // We are about calling some object inspection functions, which require to be in co-op mode.
2861 // Given that none managed objects can be changed by managed code until GC resumes the
2862 // runtime, it is safe to violate the mode contract and to inspect managed objects from a
2863 // non-EE thread when GetArrayObjectInfo is called within GC callbacks.
2864 if (NativeThreadInGC())
2866 CONTRACT_VIOLATION(ModeViolation);
2867 return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2870 return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2873 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfoHelper(Object * pObj,
2874 ULONG32 cDimensionSizes,
2875 __out_ecount(cDimensionSizes) ULONG32 pDimensionSizes[],
2876 __out_ecount(cDimensionSizes) int pDimensionLowerBounds[],
2887 // Because of the object pointer parameter, we must be either in CO-OP mode,
2888 // or on a non-EE thread in the process of doing a GC .
2889 if (!NativeThreadInGC()) { MODE_COOPERATIVE; }
2897 // Must have an array.
2898 MethodTable * pMT = pObj->GetMethodTable();
2899 if (!pMT->IsArray())
2901 return E_INVALIDARG;
2904 ArrayBase * pArray = static_cast<ArrayBase*> (pObj);
2906 unsigned rank = pArray->GetRank();
2908 if (cDimensionSizes < rank)
2910 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2913 // Copy range for each dimension (rank)
2914 int * pBounds = pArray->GetBoundsPtr();
2915 int * pLowerBounds = pArray->GetLowerBoundsPtr();
2918 for(i = 0; i < rank; i++)
2920 pDimensionSizes[i] = pBounds[i];
2921 pDimensionLowerBounds[i] = pLowerBounds[i];
2925 *ppData = pArray->GetDataPtr();
2933 * Returns information about how a particular value type is laid out.
2936 HRESULT ProfToEEInterfaceImpl::GetBoxClassLayout(ClassID classId,
2937 ULONG32 *pBufferOffset)
2951 EE_THREAD_NOT_REQUIRED;
2959 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2962 "**PROF: GetBoxClassLayout 0x%p.\n",
2965 if (pBufferOffset == NULL)
2967 return E_INVALIDARG;
2970 if (classId == NULL)
2972 return E_INVALIDARG;
2975 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
2978 // This is the incorrect API for arrays. Use GetArrayInfo and GetArrayLayout.
2980 if (!typeHandle.IsValueType())
2982 return E_INVALIDARG;
2985 *pBufferOffset = Object::GetOffsetOfFirstField();
2991 * GetThreadAppDomain
2993 * Returns the app domain currently associated with the given thread.
2996 HRESULT ProfToEEInterfaceImpl::GetThreadAppDomain(ThreadID threadId,
2997 AppDomainID *pAppDomainId)
3012 EE_THREAD_NOT_REQUIRED;
3020 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3023 "**PROF: GetThreadAppDomain 0x%p.\n",
3026 if (pAppDomainId == NULL)
3028 return E_INVALIDARG;
3033 if (threadId == NULL)
3035 pThread = GetThreadNULLOk();
3039 pThread = (Thread *)threadId;
3043 // If pThread is null, then the thread has never run managed code and
3044 // so has no ThreadID.
3046 if (!IsManagedThread(pThread))
3048 return CORPROF_E_NOT_MANAGED_THREAD;
3051 *pAppDomainId = (AppDomainID)pThread->GetDomain();
3058 * GetRVAStaticAddress
3060 * This function returns the absolute address of the given field in the given
3061 * class. The field must be an RVA Static token.
3064 * classId - the containing class.
3065 * fieldToken - the field we are querying.
3066 * pAddress - location for storing the resulting address location.
3070 * E_INVALIDARG if not an RVA static,
3071 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3074 HRESULT ProfToEEInterfaceImpl::GetRVAStaticAddress(ClassID classId,
3075 mdFieldDef fieldToken,
3089 // FieldDesc::GetStaticAddress takes a lock
3095 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3098 "**PROF: GetRVAStaticAddress 0x%p, 0x%08x.\n",
3103 // Check for NULL parameters
3105 if ((classId == NULL) || (ppAddress == NULL))
3107 return E_INVALIDARG;
3110 if (GetThread() == NULL)
3112 return CORPROF_E_NOT_MANAGED_THREAD;
3115 if (GetAppDomain() == NULL)
3120 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3123 // If this class is not fully restored, that is all the information we can get at this time.
3125 if (!typeHandle.IsRestored())
3127 return CORPROF_E_DATAINCOMPLETE;
3131 // Get the field descriptor object
3133 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3135 if (pFieldDesc == NULL)
3137 return E_INVALIDARG;
3141 // Verify this field is of the right type
3143 if(!pFieldDesc->IsStatic() ||
3144 !pFieldDesc->IsRVA() ||
3145 pFieldDesc->IsThreadStatic())
3147 return E_INVALIDARG;
3150 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3151 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3152 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3155 // Check that the data is available
3157 if (!IsClassOfMethodTableInited(pMethodTable))
3159 return CORPROF_E_DATAINCOMPLETE;
3163 // Store the result and return
3165 PTR_VOID pAddress = pFieldDesc->GetStaticAddress(NULL);
3166 if (pAddress == NULL)
3168 return CORPROF_E_DATAINCOMPLETE;
3171 *ppAddress = pAddress;
3178 * GetAppDomainStaticAddress
3180 * This function returns the absolute address of the given field in the given
3181 * class in the given app domain. The field must be an App Domain Static token.
3184 * classId - the containing class.
3185 * fieldToken - the field we are querying.
3186 * appDomainId - the app domain container.
3187 * pAddress - location for storing the resulting address location.
3191 * E_INVALIDARG if not an app domain static,
3192 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3195 HRESULT ProfToEEInterfaceImpl::GetAppDomainStaticAddress(ClassID classId,
3196 mdFieldDef fieldToken,
3197 AppDomainID appDomainId,
3212 EE_THREAD_NOT_REQUIRED;
3214 // FieldDesc::GetStaticAddress & FieldDesc::GetBase take locks
3220 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3223 "**PROF: GetAppDomainStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3229 // Check for NULL parameters
3231 if ((classId == NULL) || (appDomainId == NULL) || (ppAddress == NULL))
3233 return E_INVALIDARG;
3236 // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3237 // statics. See if the profiler is trying to be naughty.
3238 if (!((BaseDomain*) appDomainId)->IsAppDomain())
3240 return E_INVALIDARG;
3243 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3246 // If this class is not fully restored, that is all the information we can get at this time.
3248 if (!typeHandle.IsRestored())
3250 return CORPROF_E_DATAINCOMPLETE;
3254 // Get the field descriptor object
3256 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3258 if (pFieldDesc == NULL)
3261 // Give specific error code for literals.
3264 if (FAILED(typeHandle.GetModule()->GetMDImport()->GetFieldDefProps(fieldToken, &dwFieldAttrs)))
3266 return E_INVALIDARG;
3269 if (IsFdLiteral(dwFieldAttrs))
3271 return CORPROF_E_LITERALS_HAVE_NO_ADDRESS;
3274 return E_INVALIDARG;
3278 // Verify this field is of the right type
3280 if(!pFieldDesc->IsStatic() ||
3281 pFieldDesc->IsRVA() ||
3282 pFieldDesc->IsThreadStatic())
3284 return E_INVALIDARG;
3287 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3288 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3289 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3290 AppDomain * pAppDomain = (AppDomain *)appDomainId;
3293 // Check that the data is available
3295 if (!IsClassOfMethodTableInited(pMethodTable))
3297 return CORPROF_E_DATAINCOMPLETE;
3303 void *base = (void*)pFieldDesc->GetBase();
3307 return CORPROF_E_DATAINCOMPLETE;
3311 // Store the result and return
3313 PTR_VOID pAddress = pFieldDesc->GetStaticAddress(base);
3314 if (pAddress == NULL)
3316 return E_INVALIDARG;
3319 *ppAddress = pAddress;
3325 * GetThreadStaticAddress
3327 * This function returns the absolute address of the given field in the given
3328 * class on the given thread. The field must be an Thread Static token. threadId
3329 * must be the current thread ID or NULL, which means using curernt thread ID.
3332 * classId - the containing class.
3333 * fieldToken - the field we are querying.
3334 * threadId - the thread container, which has to be the current managed thread or
3335 * NULL, which means to use the current managed thread.
3336 * pAddress - location for storing the resulting address location.
3340 * E_INVALIDARG if not a thread static,
3341 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3344 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress(ClassID classId,
3345 mdFieldDef fieldToken,
3366 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3369 "**PROF: GetThreadStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3375 // Verify the value of threadId, which must be the current thread ID or NULL, which means using curernt thread ID.
3377 if ((threadId != NULL) && (threadId != ((ThreadID)GetThread())))
3379 return E_INVALIDARG;
3382 threadId = reinterpret_cast<ThreadID>(GetThread());
3383 AppDomainID appDomainId = reinterpret_cast<AppDomainID>(GetAppDomain());
3386 // Check for NULL parameters
3388 if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3390 return E_INVALIDARG;
3393 return GetThreadStaticAddress2(classId,
3401 * GetThreadStaticAddress2
3403 * This function returns the absolute address of the given field in the given
3404 * class on the given thread. The field must be an Thread Static token.
3407 * classId - the containing class.
3408 * fieldToken - the field we are querying.
3409 * appDomainId - the AppDomain container.
3410 * threadId - the thread container.
3411 * pAddress - location for storing the resulting address location.
3415 * E_INVALIDARG if not a thread static,
3416 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3419 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress2(ClassID classId,
3420 mdFieldDef fieldToken,
3421 AppDomainID appDomainId,
3442 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3445 "**PROF: GetThreadStaticAddress2 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3452 if (threadId == NULL)
3454 if (GetThread() == NULL)
3456 return CORPROF_E_NOT_MANAGED_THREAD;
3459 threadId = reinterpret_cast<ThreadID>(GetThread());
3463 // Check for NULL parameters
3465 if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3467 return E_INVALIDARG;
3470 // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3471 // statics. See if the profiler is trying to be naughty.
3472 if (!((BaseDomain*) appDomainId)->IsAppDomain())
3474 return E_INVALIDARG;
3477 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3480 // If this class is not fully restored, that is all the information we can get at this time.
3482 if (!typeHandle.IsRestored())
3484 return CORPROF_E_DATAINCOMPLETE;
3488 // Get the field descriptor object
3490 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3492 if (pFieldDesc == NULL)
3494 return E_INVALIDARG;
3498 // Verify this field is of the right type
3500 if(!pFieldDesc->IsStatic() ||
3501 !pFieldDesc->IsThreadStatic() ||
3502 pFieldDesc->IsRVA())
3504 return E_INVALIDARG;
3507 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3508 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3509 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3512 // Check that the data is available
3514 if (!IsClassOfMethodTableInited(pMethodTable))
3516 return CORPROF_E_DATAINCOMPLETE;
3520 // Store the result and return
3522 PTR_VOID pAddress = (void *)(((Thread *)threadId)->GetStaticFieldAddrNoCreate(pFieldDesc));
3523 if (pAddress == NULL)
3525 return E_INVALIDARG;
3528 *ppAddress = pAddress;
3534 * GetContextStaticAddress
3536 * This function returns the absolute address of the given field in the given
3537 * class in the given context. The field must be an Context Static token.
3540 * classId - the containing class.
3541 * fieldToken - the field we are querying.
3542 * contextId - the context container.
3543 * pAddress - location for storing the resulting address location.
3549 HRESULT ProfToEEInterfaceImpl::GetContextStaticAddress(ClassID classId,
3550 mdFieldDef fieldToken,
3551 ContextID contextId,
3571 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3574 "**PROF: GetContextStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3583 * GetAppDomainsContainingModule
3585 * This function returns the AppDomains in which the given module has been loaded
3588 * moduleId - the module with static variables.
3589 * cAppDomainIds - the input size of appDomainIds array.
3590 * pcAppDomainIds - the output size of appDomainIds array.
3591 * appDomainIds - the array to be filled up with AppDomainIDs containing initialized
3592 * static variables from the moduleId's moudle.
3596 * E_INVALIDARG for invalid parameters,
3597 * CORPROF_E_DATAINCOMPLETE if moduleId's module is not yet initialized.
3600 HRESULT ProfToEEInterfaceImpl::GetAppDomainsContainingModule(ModuleID moduleId,
3601 ULONG32 cAppDomainIds,
3602 ULONG32 * pcAppDomainIds,
3603 AppDomainID appDomainIds[])
3610 // This method iterates over AppDomains, which adds, then releases, a reference on
3611 // each AppDomain iterated. This causes locking, and can cause triggering if the
3612 // AppDomain gets destroyed as a result of the release. (See code:AppDomainIterator::Next
3613 // and its call to code:AppDomain::Release.)
3619 // (See comment above GC_TRIGGERS.)
3625 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
3626 kP2EEAllowableAfterAttach | kP2EETriggers,
3629 "**PROF: GetAppDomainsContainingModule 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3637 // Check for NULL parameters
3639 if ((moduleId == NULL) || ((appDomainIds == NULL) && (cAppDomainIds != 0)) || (pcAppDomainIds == NULL))
3641 return E_INVALIDARG;
3644 Module* pModule = reinterpret_cast< Module* >(moduleId);
3645 if (pModule->IsBeingUnloaded())
3647 return CORPROF_E_DATAINCOMPLETE;
3650 // IterateAppDomainContainingModule uses AppDomainIterator, which cannot be called while the current thread
3651 // is holding the ThreadStore lock.
3652 if (ThreadStore::HoldingThreadStore())
3654 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
3657 IterateAppDomainContainingModule iterateAppDomainContainingModule(pModule, cAppDomainIds, pcAppDomainIds, appDomainIds);
3659 return iterateAppDomainContainingModule.PopulateArray();
3665 * GetStaticFieldInfo
3667 * This function returns a bit mask of the type of statics the
3671 * classId - the containing class.
3672 * fieldToken - the field we are querying.
3673 * pFieldInfo - location for storing the resulting bit mask.
3677 * E_INVALIDARG if pFieldInfo is NULL
3680 HRESULT ProfToEEInterfaceImpl::GetStaticFieldInfo(ClassID classId,
3681 mdFieldDef fieldToken,
3682 COR_PRF_STATIC_TYPE *pFieldInfo)
3696 EE_THREAD_NOT_REQUIRED;
3704 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3707 "**PROF: GetStaticFieldInfo 0x%p, 0x%08x.\n",
3712 // Check for NULL parameters
3714 if ((classId == NULL) || (pFieldInfo == NULL))
3716 return E_INVALIDARG;
3719 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3722 // If this class is not fully restored, that is all the information we can get at this time.
3724 if (!typeHandle.IsRestored())
3726 return CORPROF_E_DATAINCOMPLETE;
3730 // Get the field descriptor object
3732 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3734 if (pFieldDesc == NULL)
3736 return E_INVALIDARG;
3739 *pFieldInfo = COR_PRF_FIELD_NOT_A_STATIC;
3741 if (pFieldDesc->IsRVA())
3743 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_RVA_STATIC);
3746 if (pFieldDesc->IsThreadStatic())
3748 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_THREAD_STATIC);
3751 if ((*pFieldInfo == COR_PRF_FIELD_NOT_A_STATIC) && pFieldDesc->IsStatic())
3753 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_APP_DOMAIN_STATIC);
3764 * This function generalizes GetClassIDInfo for all types, both generic and non-generic. It returns
3765 * the module, type token, and an array of instantiation classIDs that were used to instantiate the
3769 * classId - The classId (TypeHandle) to query information about.
3770 * pParentClassId - The ClassID (TypeHandle) of the parent class.
3771 * pModuleId - An optional parameter for returning the module of the class.
3772 * pTypeDefToken - An optional parameter for returning the metadata token of the class.
3773 * cNumTypeArgs - The count of the size of the array typeArgs
3774 * pcNumTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
3775 * the number that would be needed.
3776 * typeArgs - An array to store generic type parameters for the class.
3779 * S_OK if successful.
3781 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo2(ClassID classId,
3782 ModuleID *pModuleId,
3783 mdTypeDef *pTypeDefToken,
3784 ClassID *pParentClassId,
3785 ULONG32 cNumTypeArgs,
3786 ULONG32 *pcNumTypeArgs,
3802 EE_THREAD_NOT_REQUIRED;
3808 PRECONDITION(CheckPointer(pParentClassId, NULL_OK));
3809 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
3810 PRECONDITION(CheckPointer(pTypeDefToken, NULL_OK));
3811 PRECONDITION(CheckPointer(pcNumTypeArgs, NULL_OK));
3812 PRECONDITION(CheckPointer(typeArgs, NULL_OK));
3816 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3819 "**PROF: GetClassIDInfo2 0x%p.\n",
3823 // Verify parameters.
3825 if (classId == NULL)
3827 return E_INVALIDARG;
3830 if ((cNumTypeArgs != 0) && (typeArgs == NULL))
3832 return E_INVALIDARG;
3835 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3838 // If this class is not fully restored, that is all the information we can get at this time.
3840 if (!typeHandle.IsRestored())
3842 return CORPROF_E_DATAINCOMPLETE;
3846 // Handle globals which don't have the instances.
3848 if (classId == PROFILER_GLOBAL_CLASS)
3850 if (pParentClassId != NULL)
3852 *pParentClassId = NULL;
3855 if (pModuleId != NULL)
3857 *pModuleId = PROFILER_GLOBAL_MODULE;
3860 if (pTypeDefToken != NULL)
3862 *pTypeDefToken = mdTokenNil;
3869 // Do not do arrays via this API
3871 ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(typeHandle);
3872 if (arrayKind == ARRAY_KIND_TYPEDESC || arrayKind == ARRAY_KIND_METHODTABLE)
3874 return CORPROF_E_CLASSID_IS_ARRAY;
3877 _ASSERTE (arrayKind == ARRAY_KIND_NOTARRAY);
3879 if (typeHandle.IsTypeDesc())
3881 // Not an array, but still a typedesc? We don't know how to
3883 return CORPROF_E_CLASSID_IS_COMPOSITE;
3887 // Fill in the basic information
3889 if (pParentClassId != NULL)
3891 TypeHandle parentTypeHandle = typeHandle.GetParent();
3892 if (!parentTypeHandle.IsNull())
3894 *pParentClassId = TypeHandleToClassID(parentTypeHandle);
3898 *pParentClassId = NULL;
3902 if (pModuleId != NULL)
3904 *pModuleId = (ModuleID) typeHandle.GetModule();
3905 _ASSERTE(*pModuleId != NULL);
3908 if (pTypeDefToken != NULL)
3910 *pTypeDefToken = typeHandle.GetCl();
3911 _ASSERTE(*pTypeDefToken != NULL);
3915 // See if they are just looking to get the buffer size.
3917 if (cNumTypeArgs == 0)
3919 if (pcNumTypeArgs != NULL)
3921 *pcNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3927 // Adjust the count for the size of the given array.
3929 if (cNumTypeArgs > typeHandle.GetMethodTable()->GetNumGenericArgs())
3931 cNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3934 if (pcNumTypeArgs != NULL)
3936 *pcNumTypeArgs = cNumTypeArgs;
3940 // Copy over the instantiating types.
3943 Instantiation inst = typeHandle.GetMethodTable()->GetInstantiation();
3945 for (count = 0; count < cNumTypeArgs; count ++)
3947 typeArgs[count] = TypeHandleToClassID(inst[count]);
3953 HRESULT ProfToEEInterfaceImpl::GetModuleInfo(ModuleID moduleId,
3954 LPCBYTE * ppBaseLoadAddress,
3957 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
3958 AssemblyID * pAssemblyId)
3968 // See comment in code:ProfToEEInterfaceImpl::GetModuleInfo2
3975 EE_THREAD_NOT_REQUIRED;
3978 PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
3979 PRECONDITION(CheckPointer(ppBaseLoadAddress, NULL_OK));
3980 PRECONDITION(CheckPointer(pcchName, NULL_OK));
3981 PRECONDITION(CheckPointer(wszName, NULL_OK));
3982 PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
3986 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3989 "**PROF: GetModuleInfo 0x%p.\n",
3992 // Paramter validation is taken care of in GetModuleInfo2.
3994 return GetModuleInfo2(
4001 NULL); // Don't need module type
4004 //---------------------------------------------------------------------------------------
4006 // Helper used by GetModuleInfo2 to determine the bitmask of COR_PRF_MODULE_FLAGS for
4007 // the specified module.
4010 // pModule - Module to get the flags for
4013 // Bitmask of COR_PRF_MODULE_FLAGS corresponding to pModule
4016 DWORD ProfToEEInterfaceImpl::GetModuleFlags(Module * pModule)
4022 CAN_TAKE_LOCK; // IsWindowsRuntimeModule accesses metadata directly, which takes locks
4027 PEFile * pPEFile = pModule->GetFile();
4028 if (pPEFile == NULL)
4030 // Hopefully this should never happen; but just in case, don't try to determine the
4031 // flags without a PEFile.
4037 // First, set the flags that are dependent on which PEImage / layout we look at
4038 // inside the Module (disk/ngen/flat)
4040 if (pModule->HasNativeImage())
4043 dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4045 // Intentionally not checking for flat, since NGEN PEImages never have flat
4050 #ifdef FEATURE_READYTORUN
4051 // pModule->HasNativeImage() returns false for ReadyToRun images
4052 if (pModule->IsReadyToRun())
4055 dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4058 // Not NGEN or ReadyToRun.
4059 if (pPEFile->HasOpenedILimage())
4061 PEImage * pILImage = pPEFile->GetOpenedILimage();
4062 if (pILImage->IsFile())
4064 dwRet |= COR_PRF_MODULE_DISK;
4066 if (pPEFile->GetLoadedIL()->IsFlat())
4068 dwRet |= COR_PRF_MODULE_FLAT_LAYOUT;
4073 if (pModule->IsReflection())
4075 dwRet |= COR_PRF_MODULE_DYNAMIC;
4078 if (pModule->IsCollectible())
4080 dwRet |= COR_PRF_MODULE_COLLECTIBLE;
4083 if (pModule->IsResource())
4085 dwRet |= COR_PRF_MODULE_RESOURCE;
4088 if (pModule->IsWindowsRuntimeModule())
4090 dwRet |= COR_PRF_MODULE_WINDOWS_RUNTIME;
4096 HRESULT ProfToEEInterfaceImpl::GetModuleInfo2(ModuleID moduleId,
4097 LPCBYTE * ppBaseLoadAddress,
4100 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
4101 AssemblyID * pAssemblyId,
4102 DWORD * pdwModuleFlags)
4112 // The pModule->GetScopeName() call below can result in locks getting taken to
4113 // access the metadata implementation. However, these locks do not do a mode
4121 EE_THREAD_NOT_REQUIRED;
4124 PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
4125 PRECONDITION(CheckPointer(ppBaseLoadAddress, NULL_OK));
4126 PRECONDITION(CheckPointer(pcchName, NULL_OK));
4127 PRECONDITION(CheckPointer(wszName, NULL_OK));
4128 PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
4132 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4135 "**PROF: GetModuleInfo2 0x%p.\n",
4138 if (moduleId == NULL)
4140 return E_INVALIDARG;
4143 Module * pModule = (Module *) moduleId;
4144 if (pModule->IsBeingUnloaded())
4146 return CORPROF_E_DATAINCOMPLETE;
4154 PEFile * pFile = pModule->GetFile();
4156 // Pick some safe defaults to begin with.
4157 if (ppBaseLoadAddress != NULL)
4158 *ppBaseLoadAddress = 0;
4159 if (wszName != NULL)
4161 if (pcchName != NULL)
4163 if (pAssemblyId != NULL)
4164 *pAssemblyId = PROFILER_PARENT_UNKNOWN;
4166 // Module flags can be determined first without fear of error
4167 if (pdwModuleFlags != NULL)
4168 *pdwModuleFlags = GetModuleFlags(pModule);
4170 // Get the module file name
4171 LPCWSTR wszFileName = pFile->GetPath();
4172 _ASSERTE(wszFileName != NULL);
4173 PREFIX_ASSUME(wszFileName != NULL);
4175 // If there is no filename, which is the case for RefEmit modules and for SQL
4176 // modules, then rather than returning an empty string for the name, just use the
4177 // module name from metadata (a.k.a. Module.ScopeName). This is required to
4178 // support SQL F1 sampling profiling.
4179 StackSString strScopeName;
4180 LPCUTF8 szScopeName = NULL;
4181 if ((*wszFileName == W('\0')) && SUCCEEDED(pModule->GetScopeName(&szScopeName)))
4183 strScopeName.SetUTF8(szScopeName);
4184 strScopeName.Normalize();
4185 wszFileName = strScopeName.GetUnicode();
4188 ULONG trueLen = (ULONG)(wcslen(wszFileName) + 1);
4190 // Return name of module as required.
4191 if (wszName && cchName > 0)
4193 if (cchName < trueLen)
4195 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4199 wcsncpy_s(wszName, cchName, wszFileName, trueLen);
4203 // If they request the actual length of the name
4205 *pcchName = trueLen;
4207 if (ppBaseLoadAddress != NULL && !pFile->IsDynamic())
4209 if (pModule->IsProfilerNotified())
4211 // Set the base load address -- this could be null in certain error conditions
4212 *ppBaseLoadAddress = pModule->GetProfilerBase();
4216 *ppBaseLoadAddress = NULL;
4219 if (*ppBaseLoadAddress == NULL)
4221 hr = CORPROF_E_DATAINCOMPLETE;
4225 // Return the parent assembly for this module if desired.
4226 if (pAssemblyId != NULL)
4228 // Lie and say the assembly isn't avaialable until we are loaded (even though it is.)
4229 // This is for backward compatibilty - we may want to change it
4230 if (pModule->IsProfilerNotified())
4232 Assembly *pAssembly = pModule->GetAssembly();
4233 _ASSERTE(pAssembly);
4235 *pAssemblyId = (AssemblyID) pAssembly;
4239 hr = CORPROF_E_DATAINCOMPLETE;
4243 EX_CATCH_HRESULT(hr);
4250 * Get a metadata interface instance which maps to the given module.
4251 * One may ask for the metadata to be opened in read+write mode, but
4252 * this will result in slower metadata execution of the program, because
4253 * changes made to the metadata cannot be optimized as they were from
4256 HRESULT ProfToEEInterfaceImpl::GetModuleMetaData(ModuleID moduleId,
4272 // Currently, this function is technically EE_THREAD_REQUIRED because
4273 // some functions in synch.cpp assert that there is a Thread object,
4274 // but we might be able to lift that restriction and make this be
4275 // EE_THREAD_NOT_REQUIRED.
4277 // PEFile::GetRWImporter & PEFile::GetEmitter &
4278 // GetReadablePublicMetaDataInterface take locks
4284 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
4287 "**PROF: GetModuleMetaData 0x%p, 0x%08x.\n",
4291 if (moduleId == NULL)
4293 return E_INVALIDARG;
4296 // Check for unsupported bits, and return E_INVALIDARG if present
4297 if ((dwOpenFlags & ~(ofNoTransform | ofRead | ofWrite)) != 0)
4299 return E_INVALIDARG;
4305 pModule = (Module *) moduleId;
4306 _ASSERTE(pModule != NULL);
4307 if (pModule->IsBeingUnloaded())
4309 return CORPROF_E_DATAINCOMPLETE;
4312 // Make sure we can get the importer first
4313 if (pModule->IsResource())
4320 // Decide which type of open mode we are in to see which you require.
4321 if ((dwOpenFlags & ofWrite) == 0)
4323 // Readable interface
4324 return pModule->GetReadablePublicMetaDataInterface(dwOpenFlags, riid, (LPVOID *) ppOut);
4327 // Writeable interface
4328 IUnknown *pObj = NULL;
4331 pObj = pModule->GetValidatedEmitter();
4333 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
4335 // Ask for the interface the caller wanted, only if they provide a out param
4336 if (SUCCEEDED(hr) && ppOut)
4337 hr = pObj->QueryInterface(riid, (void **) ppOut);
4344 * Retrieve a pointer to the body of a method starting at it's header.
4345 * A method is scoped by the module it lives in. Because this function
4346 * is designed to give a tool access to IL before it has been loaded
4347 * by the Runtime, it uses the metadata token of the method to find
4348 * the instance desired. Note that this function has no effect on
4349 * already compiled code.
4351 HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID moduleId,
4352 mdMethodDef methodId,
4353 LPCBYTE *ppMethodHeader,
4354 ULONG *pcbMethodSize)
4367 // PEFile::CheckLoaded & Module::GetDynamicIL both take a lock
4374 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4375 kP2EEAllowableAfterAttach,
4378 "**PROF: GetILFunctionBody 0x%p, 0x%08x.\n",
4382 Module * pModule; // Working pointer for real class.
4383 ULONG RVA; // Return RVA of the method body.
4384 DWORD dwImplFlags; // Flags for the item.
4386 if ((moduleId == NULL) ||
4387 (methodId == mdMethodDefNil) ||
4389 (TypeFromToken(methodId) != mdtMethodDef))
4391 return E_INVALIDARG;
4394 pModule = (Module *) moduleId;
4395 _ASSERTE(pModule != NULL && methodId != mdMethodDefNil);
4396 if (pModule->IsBeingUnloaded())
4398 return CORPROF_E_DATAINCOMPLETE;
4401 // Find the method body based on metadata.
4402 IMDInternalImport *pImport = pModule->GetMDImport();
4405 PEFile *pFile = pModule->GetFile();
4407 if (!pFile->CheckLoaded())
4408 return (CORPROF_E_DATAINCOMPLETE);
4410 LPCBYTE pbMethod = NULL;
4412 // Don't return rewritten IL, use the new API to get that.
4413 pbMethod = (LPCBYTE) pModule->GetDynamicIL(methodId, FALSE);
4415 // Method not overriden - get the original copy of the IL by going to metadata
4416 if (pbMethod == NULL)
4419 IfFailRet(pImport->GetMethodImplProps(methodId, &RVA, &dwImplFlags));
4421 // Check to see if the method has associated IL
4422 if ((RVA == 0 && !pFile->IsDynamic()) || !(IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags) || IsMiInternalCall(dwImplFlags)))
4424 return (CORPROF_E_FUNCTION_NOT_IL);
4429 // Get the location of the IL
4430 pbMethod = (LPCBYTE) (pModule->GetIL(RVA));
4432 EX_CATCH_HRESULT(hr);
4440 // Fill out param if provided
4442 *ppMethodHeader = pbMethod;
4444 // Calculate the size of the method itself.
4447 if (!FitsIn<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod)))
4449 return E_UNEXPECTED;
4451 *pcbMethodSize = static_cast<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod));
4456 //---------------------------------------------------------------------------------------
4457 // Retrieves an IMethodMalloc pointer around a ModuleILHeap instance that will own
4458 // allocating heap space for this module (for IL rewriting).
4461 // moduleId - ModuleID this allocator shall allocate for
4462 // ppMalloc - [out] IMethodMalloc pointer the profiler will use for allocation requests
4463 // against this module
4466 // HRESULT indicating success / failure
4469 // IL method bodies used to have the requirement that they must be referenced as
4470 // RVA's to the loaded module, which means they come after the module within
4471 // METHOD_MAX_RVA. In order to make it easier for a tool to swap out the body of
4472 // a method, this allocator will ensure memory allocated after that point.
4474 // Now that requirement is completely gone, so there's nothing terribly special
4475 // about this allocator, we just keep it around for legacy purposes.
4477 HRESULT ProfToEEInterfaceImpl::GetILFunctionBodyAllocator(ModuleID moduleId,
4478 IMethodMalloc ** ppMalloc)
4485 // ModuleILHeap::FindOrCreateHeap may take a Crst if it
4486 // needs to create a new allocator and add it to the list. Taking a crst
4487 // switches to preemptive, which is effectively a GC trigger
4494 EE_THREAD_NOT_REQUIRED;
4496 // (see GC_TRIGGERS comment)
4502 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4503 kP2EEAllowableAfterAttach | kP2EETriggers,
4506 "**PROF: GetILFunctionBodyAllocator 0x%p.\n",
4509 if ((moduleId == NULL) || (ppMalloc == NULL))
4511 return E_INVALIDARG;
4514 Module * pModule = (Module *) moduleId;
4516 if (pModule->IsBeingUnloaded() ||
4517 !pModule->GetFile()->CheckLoaded())
4519 return (CORPROF_E_DATAINCOMPLETE);
4522 *ppMalloc = &ModuleILHeap::s_Heap;
4527 * Replaces the method body for a function in a module. This will replace
4528 * the RVA of the method in the metadata to point to this new method body,
4529 * and adjust any internal data structures as required. This function can
4530 * only be called on those methods which have never been compiled by a JITTER.
4531 * Please use the GetILFunctionBodyAllocator to allocate space for the new method to
4532 * ensure the buffer is compatible.
4534 HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId,
4535 mdMethodDef methodId,
4536 LPCBYTE pbNewILMethodHeader)
4540 // PEFile::GetEmitter, Module::SetDynamicIL all throw
4543 // Locks are taken (see CAN_TAKE_LOCK below), which may cause mode switch to
4544 // preemptive, which is triggers.
4550 // Module::SetDynamicIL & PEFile::CheckLoaded & PEFile::GetEmitter take locks
4556 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4557 kP2EEAllowableAfterAttach | kP2EETriggers,
4560 "**PROF: SetILFunctionBody 0x%p, 0x%08x.\n",
4564 if ((moduleId == NULL) ||
4565 (methodId == mdMethodDefNil) ||
4566 (TypeFromToken(methodId) != mdtMethodDef) ||
4567 (pbNewILMethodHeader == NULL))
4569 return E_INVALIDARG;
4572 Module *pModule; // Working pointer for real class.
4575 // Cannot set the body for anything other than a method def
4576 if (TypeFromToken(methodId) != mdtMethodDef)
4577 return (E_INVALIDARG);
4579 // Cast module to appropriate type
4580 pModule = (Module *) moduleId;
4581 _ASSERTE (pModule != NULL); // Enforced in CorProfInfo::SetILFunctionBody
4582 if (pModule->IsBeingUnloaded())
4584 return CORPROF_E_DATAINCOMPLETE;
4587 // Remember the profiler is doing this, as that means we must never detach it!
4588 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
4590 // This action is not temporary!
4591 // If the profiler want to be able to revert, they need to use
4592 // the new ReJIT APIs.
4593 pModule->SetDynamicIL(methodId, (TADDR)pbNewILMethodHeader, FALSE);
4599 * Sets the codemap for the replaced IL function body
4601 HRESULT ProfToEEInterfaceImpl::SetILInstrumentedCodeMap(FunctionID functionId,
4603 ULONG cILMapEntries,
4604 COR_IL_MAP rgILMapEntries[])
4608 // Debugger::SetILInstrumentedCodeMap throws
4611 // Debugger::SetILInstrumentedCodeMap triggers
4618 EE_THREAD_NOT_REQUIRED;
4620 // Debugger::SetILInstrumentedCodeMap takes a lock when it calls Debugger::GetOrCreateMethodInfo
4626 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4627 kP2EEAllowableAfterAttach | kP2EETriggers,
4630 "**PROF: SetILInstrumentedCodeMap 0x%p, %d.\n",
4634 if (functionId == NULL)
4636 return E_INVALIDARG;
4639 if (cILMapEntries >= (MAXULONG / sizeof(COR_IL_MAP)))
4641 // Too big! The allocation below would overflow when calculating the size.
4642 return E_INVALIDARG;
4646 #ifdef DEBUGGING_SUPPORTED
4648 MethodDesc *pMethodDesc = FunctionIdToMethodDesc(functionId);
4650 // it's not safe to examine a methoddesc that has not been restored so do not do so
4651 if (!pMethodDesc ->IsRestored())
4652 return CORPROF_E_DATAINCOMPLETE;
4654 if (g_pDebugInterface == NULL)
4656 return CORPROF_E_DEBUGGING_DISABLED;
4659 COR_IL_MAP * rgNewILMapEntries = new (nothrow) COR_IL_MAP[cILMapEntries];
4661 if (rgNewILMapEntries == NULL)
4662 return E_OUTOFMEMORY;
4664 memcpy_s(rgNewILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries, rgILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries);
4666 return g_pDebugInterface->SetILInstrumentedCodeMap(pMethodDesc,
4671 #else //DEBUGGING_SUPPORTED
4673 #endif //DEBUGGING_SUPPORTED
4676 HRESULT ProfToEEInterfaceImpl::ForceGC()
4680 // GC calls "new" which throws
4683 // Uh duh, look at the name of the function, dude
4690 EE_THREAD_NOT_REQUIRED;
4692 // Initiating a GC causes a runtime suspension which requires the
4693 // mother of all locks: the thread store lock.
4699 ASSERT_NO_EE_LOCKS_HELD();
4701 // We need to use IsGarbageCollectorFullyInitialized() instead of IsGCHeapInitialized() because
4702 // there are other GC initialization being done after IsGCHeapInitialized() becomes TRUE,
4703 // and before IsGarbageCollectorFullyInitialized() becomes TRUE.
4704 if (!IsGarbageCollectorFullyInitialized())
4706 return CORPROF_E_NOT_YET_AVAILABLE;
4709 // Disallow the cases where a profiler calls this off a hijacked CLR thread
4710 // or inside a profiler callback. (Allow cases where this is a native thread, or a
4711 // thread which previously successfully called ForceGC.)
4712 Thread * pThread = GetThreadNULLOk();
4713 if ((pThread != NULL) &&
4714 (!AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED)) &&
4715 (pThread->GetFrame() != FRAME_TOP
4716 || AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_INCALLBACK)))
4720 "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE "
4721 "due to illegal hijacked profiler call or call from inside another callback\n"));
4722 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
4725 // NOTE: We cannot use the standard macro PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX
4726 // here because the macro ensures that either the current thread is not an
4727 // EE thread, or, if it is, that the CALLBACK flag is set. In classic apps
4728 // a profiler-owned native thread will not get an EE thread associated with
4729 // it, however, in AppX apps, during the first call into the GC on a
4730 // profiler-owned thread, the EE will associate an EE-thread with the profiler
4731 // thread. As a consequence the second call to ForceGC on the same thread
4732 // would fail, since this is now an EE thread and this API is not called from
4735 // First part of the PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX macro:
4736 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4737 kP2EEAllowableAfterAttach | kP2EETriggers,
4740 "**PROF: ForceGC.\n"));
4742 #ifdef FEATURE_EVENT_TRACE
4743 // This helper, used by ETW and profAPI ensures a managed thread gets created for
4744 // this thread before forcing the GC (to work around Jupiter issues where it's
4745 // expected this thread is already managed before starting the GC).
4746 HRESULT hr = ETW::GCLog::ForceGCForDiagnostics();
4747 #else // !FEATURE_EVENT_TRACE
4748 HRESULT hr = E_FAIL;
4749 #endif // FEATURE_EVENT_TRACE
4751 // If a Thread object was just created for this thread, remember the fact that it
4752 // was a ForceGC() thread, so we can be more lenient when doing
4753 // COR_PRF_CALLBACKSTATE_INCALLBACK later on from other APIs
4754 pThread = GetThreadNULLOk();
4755 if (pThread != NULL)
4757 pThread->SetProfilerCallbackStateFlags(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED);
4765 * Returns the ContextID for the current thread.
4767 HRESULT ProfToEEInterfaceImpl::GetThreadContext(ThreadID threadId,
4768 ContextID *pContextId)
4782 EE_THREAD_NOT_REQUIRED;
4790 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4793 "**PROF: GetThreadContext 0x%p.\n",
4796 if (!IsManagedThread(threadId))
4798 return E_INVALIDARG;
4801 // Cast to right type
4802 Thread *pThread = reinterpret_cast<Thread *>(threadId);
4804 // Get the context for the Thread* provided
4805 AppDomain *pContext = pThread->GetDomain(); // Context is same as AppDomain in CoreCLR
4808 // If there's no current context, return incomplete info
4810 return (CORPROF_E_DATAINCOMPLETE);
4812 // Set the result and return
4814 *pContextId = reinterpret_cast<ContextID>(pContext);
4819 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo(ClassID classId,
4820 ModuleID *pModuleId,
4821 mdTypeDef *pTypeDefToken)
4835 EE_THREAD_NOT_REQUIRED;
4843 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4846 "**PROF: GetClassIDInfo 0x%p.\n",
4849 if (classId == NULL)
4851 return E_INVALIDARG;
4854 if (pModuleId != NULL)
4859 if (pTypeDefToken != NULL)
4861 *pTypeDefToken = NULL;
4864 // Handle globals which don't have the instances.
4865 if (classId == PROFILER_GLOBAL_CLASS)
4867 if (pModuleId != NULL)
4869 *pModuleId = PROFILER_GLOBAL_MODULE;
4872 if (pTypeDefToken != NULL)
4874 *pTypeDefToken = mdTokenNil;
4877 else if (classId == NULL)
4879 return E_INVALIDARG;
4881 // Get specific data.
4884 TypeHandle th = TypeHandle::FromPtr((void *)classId);
4886 if (!th.IsTypeDesc())
4891 // If this class is not fully restored, that is all the information we can get at this time.
4893 if (!th.IsRestored())
4895 return CORPROF_E_DATAINCOMPLETE;
4898 if (pModuleId != NULL)
4900 *pModuleId = (ModuleID) th.GetModule();
4901 _ASSERTE(*pModuleId != NULL);
4904 if (pTypeDefToken != NULL)
4906 *pTypeDefToken = th.GetCl();
4907 _ASSERTE(*pTypeDefToken != NULL);
4917 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo(FunctionID functionId,
4919 ModuleID *pModuleId,
4934 EE_THREAD_NOT_REQUIRED;
4942 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4945 "**PROF: GetFunctionInfo 0x%p.\n",
4948 if (functionId == NULL)
4950 return E_INVALIDARG;
4953 MethodDesc *pMDesc = (MethodDesc *) functionId;
4954 if (!pMDesc->IsRestored())
4956 return CORPROF_E_DATAINCOMPLETE;
4959 MethodTable *pMT = pMDesc->GetMethodTable();
4960 if (!pMT->IsRestored())
4962 return CORPROF_E_DATAINCOMPLETE;
4965 ClassID classId = PROFILER_GLOBAL_CLASS;
4969 classId = NonGenericTypeHandleToClassID(TypeHandle(pMT));
4972 if (pClassId != NULL)
4974 *pClassId = classId;
4977 if (pModuleId != NULL)
4979 *pModuleId = (ModuleID) pMDesc->GetModule();
4984 *pToken = pMDesc->GetMemberDef();
4991 * GetILToNativeMapping returns a map from IL offsets to native
4992 * offsets for this code. An array of COR_DEBUG_IL_TO_NATIVE_MAP
4993 * structs will be returned, and some of the ilOffsets in this array
4994 * may be the values specified in CorDebugIlToNativeMappingTypes.
4996 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping(FunctionID functionId,
4998 ULONG32 * pcMap, // [out]
4999 COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
5003 // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
5006 // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
5007 // called from here. Since the profiler has a valid functionId, the methoddesc for
5008 // this code will already have been created. We should be able to enforce this by
5009 // passing allowCreate=FALSE to FindOrCreateTypicalSharedInstantiation.
5010 DISABLED(GC_NOTRIGGER);
5015 // The call to g_pDebugInterface->GetILToNativeMapping() below may call
5016 // Debugger::AcquireDebuggerLock
5022 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5025 "**PROF: GetILToNativeMapping 0x%p.\n",
5028 return GetILToNativeMapping2(functionId, 0, cMap, pcMap, map);
5031 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId,
5034 ULONG32 * pcMap, // [out]
5035 COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
5039 // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
5042 // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
5043 // called from here. Since the profiler has a valid functionId, the methoddesc for
5044 // this code will already have been created. We should be able to enforce this by
5045 // passing allowCreate=FALSE to FindOrCreateTypicalSharedInstantiation.
5046 DISABLED(GC_NOTRIGGER);
5051 // The call to g_pDebugInterface->GetILToNativeMapping() below may call
5052 // Debugger::AcquireDebuggerLock
5058 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5061 "**PROF: GetILToNativeMapping2 0x%p 0x%p.\n",
5062 functionId, reJitId));
5064 if (functionId == NULL)
5066 return E_INVALIDARG;
5070 ((pcMap == NULL) || (map == NULL)))
5072 return E_INVALIDARG;
5079 // Cast to proper type
5080 MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
5082 if (pMD->HasClassOrMethodInstantiation() && pMD->IsTypicalMethodDefinition())
5084 // In this case, we used to replace pMD with its canonical instantiation
5085 // (FindOrCreateTypicalSharedInstantiation). However, a profiler should never be able
5086 // to get to this point anyway, since any MethodDesc a profiler gets from us
5087 // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
5088 // We assert here just in case a test proves me wrong, but generally we will
5089 // disallow this code path.
5090 _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetILToNativeMapping2");
5095 PCODE pCodeStart = NULL;
5096 CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
5097 ILCodeVersion ilCodeVersion = NULL;
5099 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
5101 pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
5103 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
5104 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
5106 // Now that tiered compilation can create more than one jitted code version for the same rejit id
5107 // we are arbitrarily choosing the first one to return. To address a specific version of native code
5108 // use GetILToNativeMapping3.
5109 pCodeStart = iter->GetNativeCode();
5114 hr = GetILToNativeMapping3(pCodeStart, cMap, pcMap, map);
5117 EX_CATCH_HRESULT(hr);
5124 //*****************************************************************************
5125 // Given an ObjectID, go get the EE ClassID for it.
5126 //*****************************************************************************
5127 HRESULT ProfToEEInterfaceImpl::GetClassFromObject(ObjectID objectId,
5138 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
5141 // Object::GetTypeHandle takes a lock
5147 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5150 "**PROF: GetClassFromObject 0x%p.\n",
5153 if (objectId == NULL)
5155 return E_INVALIDARG;
5158 HRESULT hr = AllowObjectInspection();
5164 // Cast the ObjectID as a Object
5165 Object *pObj = reinterpret_cast<Object *>(objectId);
5167 // Set the out param and indicate success
5168 // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
5171 *pClassId = SafeGetClassIDFromObject(pObj);
5177 //*****************************************************************************
5178 // Given a module and a token for a class, go get the EE data structure for it.
5179 //*****************************************************************************
5180 HRESULT ProfToEEInterfaceImpl::GetClassFromToken(ModuleID moduleId,
5189 // ClassLoader::LoadTypeDefOrRefThrowing triggers
5195 // ClassLoader::LoadTypeDefOrRefThrowing takes a lock
5201 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5202 kP2EEAllowableAfterAttach | kP2EETriggers,
5205 "**PROF: GetClassFromToken 0x%p, 0x%08x.\n",
5209 if ((moduleId == NULL) || (typeDef == mdTypeDefNil) || (typeDef == NULL))
5211 return E_INVALIDARG;
5214 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5216 return CORPROF_E_RUNTIME_UNINITIALIZED;
5220 Module *pModule = (Module *) moduleId;
5222 // No module, or it's disassociated from metadata
5223 if ((pModule == NULL) || (pModule->IsBeingUnloaded()))
5225 return CORPROF_E_DATAINCOMPLETE;
5228 // First, check the RID map. This is important since it
5229 // works during teardown (and the below doesn't)
5231 th = pModule->LookupTypeDef(typeDef);
5237 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, typeDef,
5238 ClassLoader::ThrowIfNotFound,
5239 ClassLoader::PermitUninstDefOrRef);
5241 EX_CATCH_HRESULT(hr);
5249 if (!th.GetMethodTable())
5251 return CORPROF_E_DATAINCOMPLETE;
5255 // Check if it is generic
5257 ClassID classId = NonGenericTypeHandleToClassID(th);
5259 if (classId == NULL)
5261 return CORPROF_E_TYPE_IS_PARAMETERIZED;
5264 // Return value if necessary
5267 *pClassId = classId;
5274 HRESULT ProfToEEInterfaceImpl::GetClassFromTokenAndTypeArgs(ModuleID moduleID,
5285 // LoadGenericInstantiationThrowing may load
5291 // ClassLoader::LoadGenericInstantiationThrowing takes a lock
5297 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5298 kP2EEAllowableAfterAttach | kP2EETriggers,
5301 "**PROF: GetClassFromTokenAndTypeArgs 0x%p, 0x%08x.\n",
5305 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5307 return CORPROF_E_RUNTIME_UNINITIALIZED;
5310 Module* pModule = reinterpret_cast< Module* >(moduleID);
5312 if (pModule == NULL || pModule->IsBeingUnloaded())
5314 return CORPROF_E_DATAINCOMPLETE;
5317 // This array needs to be accessible at least until the call to
5318 // ClassLoader::LoadGenericInstantiationThrowing
5319 TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5320 NewArrayHolder< TypeHandle > holder(genericParameters);
5322 if (NULL == genericParameters)
5324 return E_OUTOFMEMORY;
5327 for (ULONG32 i = 0; i < cTypeArgs; ++i)
5329 genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5333 // nickbe 11/24/2003 10:12:56
5335 // In RTM/Everett we decided to load the class if it hadn't been loaded yet
5336 // (see ProfToEEInterfaceImpl::GetClassFromToken). For compatibility we're
5337 // going to make the same decision here. It's potentially confusing to tell
5338 // someone a type doesn't exist at one point in time, but does exist later,
5339 // and there is no good way for us to determing that a class may eventually
5340 // be loaded without going ahead and loading it
5347 // Not sure if this is a valid override or not - making this a VIOLATION
5348 // until we're sure.
5349 CONTRACT_VIOLATION(LoadsTypeViolation);
5351 if (GetThreadNULLOk() == NULL)
5353 // Type system will try to validate as part of its contract if the current
5354 // AppDomain returned by GetAppDomain can load types in specified module's
5355 // assembly. On a non-EE thread it results in an AV in a check build
5356 // since the type system tries to dereference NULL returned by GetAppDomain.
5357 // More importantly, loading a type on a non-EE thread is not allowed.
5359 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE() states that callers will not
5360 // try to load a type, so that type system will not try to test type
5361 // loadability in the current AppDomain. However,
5362 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE does not prevent callers from
5363 // loading a type. It is profiler's responsibility not to attempt to load
5364 // a type in unsupported ways (e.g. from a non-EE thread). It doesn't
5365 // impact retail builds, in which contracts are not available.
5366 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5368 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE also defines FAULT_FORBID, which
5369 // causes Scanruntime to flag a fault violation in AssemblySpec::InitializeSpec,
5370 // which is defined as FAULTS. It only happens in a type-loading path, which
5371 // is not supported on a non-EE thread. Suppressing a contract violation in an
5372 // unsupported execution path is more preferable than causing AV when calling
5373 // GetClassFromTokenAndTypeArgs on a non-EE thread in a check build. See Dev10
5374 // 682526 for more details.
5377 th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5379 Instantiation(genericParameters, cTypeArgs),
5380 ClassLoader::LoadTypes);
5384 th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5386 Instantiation(genericParameters, cTypeArgs),
5387 ClassLoader::LoadTypes);
5390 EX_CATCH_HRESULT(hr);
5399 // Hmm, the type isn't loaded yet.
5400 return CORPROF_E_DATAINCOMPLETE;
5403 *pClassID = TypeHandleToClassID(th);
5408 //*****************************************************************************
5409 // Given the token for a method, return the fucntion id.
5410 //*****************************************************************************
5411 HRESULT ProfToEEInterfaceImpl::GetFunctionFromToken(ModuleID moduleId,
5413 FunctionID *pFunctionId)
5427 EE_THREAD_NOT_REQUIRED;
5435 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5438 "**PROF: GetFunctionFromToken 0x%p, 0x%08x.\n",
5442 if ((moduleId == NULL) || (typeDef == mdTokenNil))
5444 return E_INVALIDARG;
5447 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5449 return CORPROF_E_RUNTIME_UNINITIALIZED;
5456 Module *pModule = (Module *) moduleId;
5458 // No module, or disassociated from metadata
5459 if (pModule == NULL || pModule->IsBeingUnloaded())
5461 return CORPROF_E_DATAINCOMPLETE;
5464 // Default return value of NULL
5465 MethodDesc *pDesc = NULL;
5467 // Different lookup depending on whether it's a Def or Ref
5468 if (TypeFromToken(typeDef) == mdtMethodDef)
5470 pDesc = pModule->LookupMethodDef(typeDef);
5472 else if (TypeFromToken(typeDef) == mdtMemberRef)
5474 pDesc = pModule->LookupMemberRefAsMethod(typeDef);
5478 return E_INVALIDARG;
5483 return E_INVALIDARG;
5487 // Check that this is a non-generic method
5489 if (pDesc->HasClassOrMethodInstantiation())
5491 return CORPROF_E_FUNCTION_IS_PARAMETERIZED;
5494 if (pFunctionId && SUCCEEDED(hr))
5496 *pFunctionId = MethodDescToFunctionID(pDesc);
5502 HRESULT ProfToEEInterfaceImpl::GetFunctionFromTokenAndTypeArgs(ModuleID moduleID,
5503 mdMethodDef funcDef,
5507 FunctionID* pFunctionID)
5514 // It can trigger type loads
5520 // MethodDesc::FindOrCreateAssociatedMethodDesc enters a Crst
5526 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5527 kP2EEAllowableAfterAttach | kP2EETriggers,
5530 "**PROF: GetFunctionFromTokenAndTypeArgs 0x%p, 0x%08x, 0x%p.\n",
5535 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
5536 Module* pModule = reinterpret_cast< Module* >(moduleID);
5538 if ((pModule == NULL) || typeHandle.IsNull())
5540 return E_INVALIDARG;
5543 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5545 return CORPROF_E_RUNTIME_UNINITIALIZED;
5548 if (pModule->IsBeingUnloaded())
5550 return CORPROF_E_DATAINCOMPLETE;
5553 MethodDesc* pMethodDesc = NULL;
5555 if (mdtMethodDef == TypeFromToken(funcDef))
5557 pMethodDesc = pModule->LookupMethodDef(funcDef);
5559 else if (mdtMemberRef == TypeFromToken(funcDef))
5561 pMethodDesc = pModule->LookupMemberRefAsMethod(funcDef);
5565 return E_INVALIDARG;
5568 MethodTable* pMethodTable = typeHandle.GetMethodTable();
5570 if (pMethodTable == NULL || !pMethodTable->IsRestored() ||
5571 pMethodDesc == NULL || !pMethodDesc->IsRestored())
5573 return CORPROF_E_DATAINCOMPLETE;
5576 // This array needs to be accessible at least until the call to
5577 // MethodDesc::FindOrCreateAssociatedMethodDesc
5578 TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5579 NewArrayHolder< TypeHandle > holder(genericParameters);
5581 if (NULL == genericParameters)
5583 return E_OUTOFMEMORY;
5586 for (ULONG32 i = 0; i < cTypeArgs; ++i)
5588 genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5591 MethodDesc* result = NULL;
5596 result = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethodDesc,
5599 Instantiation(genericParameters, cTypeArgs),
5602 EX_CATCH_HRESULT(hr);
5606 *pFunctionID = MethodDescToFunctionID(result);
5612 //*****************************************************************************
5613 // Retrieve information about a given application domain, which is like a
5615 //*****************************************************************************
5616 HRESULT ProfToEEInterfaceImpl::GetAppDomainInfo(AppDomainID appDomainId,
5619 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5620 ProcessID *pProcessId)
5627 // AppDomain::GetFriendlyNameForDebugger triggers
5633 // AppDomain::GetFriendlyNameForDebugger takes a lock
5639 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5640 kP2EEAllowableAfterAttach | kP2EETriggers,
5643 "**PROF: GetAppDomainInfo 0x%p.\n",
5646 if (appDomainId == NULL)
5648 return E_INVALIDARG;
5651 BaseDomain *pDomain; // Internal data structure.
5655 // Right now, this ID is not a true AppDomain, since we use the old
5656 // AppDomain/SystemDomain model in the profiling API. This means that
5657 // the profiler exposes the SharedDomain and the SystemDomain to the
5658 // outside world. It's not clear whether this is actually the right thing
5659 // to do or not. - seantrow
5664 pDomain = (BaseDomain *) appDomainId;
5666 // Make sure they've passed in a valid appDomainId
5667 if (pDomain == NULL)
5668 return (E_INVALIDARG);
5670 // Pick sensible defaults.
5678 LPCWSTR szFriendlyName;
5679 if (pDomain == SystemDomain::System())
5680 szFriendlyName = g_pwBaseLibrary;
5682 szFriendlyName = ((AppDomain*)pDomain)->GetFriendlyNameForDebugger();
5684 if (szFriendlyName != NULL)
5686 // Get the module file name
5687 ULONG trueLen = (ULONG)(wcslen(szFriendlyName) + 1);
5689 // Return name of module as required.
5690 if (szName && cchName > 0)
5692 ULONG copyLen = trueLen;
5694 if (copyLen >= cchName)
5696 copyLen = cchName - 1;
5699 wcsncpy_s(szName, cchName, szFriendlyName, copyLen);
5702 // If they request the actual length of the name
5704 *pcchName = trueLen;
5707 // If we don't have a friendly name but the call was requesting it, then return incomplete data HR
5710 if ((szName != NULL && cchName > 0) || pcchName)
5711 hr = CORPROF_E_DATAINCOMPLETE;
5715 *pProcessId = (ProcessID) GetCurrentProcessId();
5721 //*****************************************************************************
5722 // Retrieve information about an assembly, which is a collection of dll's.
5723 //*****************************************************************************
5724 HRESULT ProfToEEInterfaceImpl::GetAssemblyInfo(AssemblyID assemblyId,
5727 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5728 AppDomainID *pAppDomainId,
5729 ModuleID *pModuleId)
5733 // SString::SString throws
5743 EE_THREAD_NOT_REQUIRED;
5745 // PEAssembly::GetSimpleName() enters a lock via use of the metadata interface
5751 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5754 "**PROF: GetAssemblyInfo 0x%p.\n",
5757 if (assemblyId == NULL)
5759 return E_INVALIDARG;
5764 Assembly *pAssembly; // Internal data structure for assembly.
5766 pAssembly = (Assembly *) assemblyId;
5767 _ASSERTE(pAssembly != NULL);
5769 if (pcchName || szName)
5771 // Get the friendly name of the assembly
5772 SString name(SString::Utf8, pAssembly->GetSimpleName());
5774 const COUNT_T nameLength = name.GetCount() + 1;
5776 if ((NULL != szName) && (cchName > 0))
5778 wcsncpy_s(szName, cchName, name.GetUnicode(), min(nameLength, cchName - 1));
5781 if (NULL != pcchName)
5783 *pcchName = nameLength;
5787 // Get the parent application domain.
5790 *pAppDomainId = (AppDomainID) pAssembly->GetDomain();
5791 _ASSERTE(*pAppDomainId != NULL);
5794 // Find the module the manifest lives in.
5797 *pModuleId = (ModuleID) pAssembly->GetManifestModule();
5799 // This is the case where the profiler has called GetAssemblyInfo
5800 // on an assembly that has been completely created yet.
5802 hr = CORPROF_E_DATAINCOMPLETE;
5808 // Setting ELT hooks is only allowed from within Initialize(). However, test-only
5809 // profilers may need to set those hooks from an attaching profiling. See
5810 // code:ProfControlBlock#TestOnlyELT
5811 #ifdef PROF_TEST_ONLY_FORCE_ELT
5812 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT(logParams) \
5815 if (g_profControlBlock.fTestOnlyForceEnterLeave) \
5817 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, logParams); \
5821 PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams); \
5824 #else // PROF_TEST_ONLY_FORCE_ELT
5825 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT \
5826 PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY
5827 #endif // PROF_TEST_ONLY_FORCE_ELT
5830 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
5831 FunctionLeave * pFuncLeave,
5832 FunctionTailcall * pFuncTailcall)
5846 EE_THREAD_NOT_REQUIRED;
5853 // The profiler must call SetEnterLeaveFunctionHooks during initialization, since
5854 // the enter/leave events are immutable and must also be set during initialization.
5855 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5857 "**PROF: SetEnterLeaveFunctionHooks 0x%p, 0x%p, 0x%p.\n",
5862 return g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall);
5866 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
5867 FunctionLeave2 * pFuncLeave,
5868 FunctionTailcall2 * pFuncTailcall)
5882 EE_THREAD_NOT_REQUIRED;
5889 // The profiler must call SetEnterLeaveFunctionHooks2 during initialization, since
5890 // the enter/leave events are immutable and must also be set during initialization.
5891 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5893 "**PROF: SetEnterLeaveFunctionHooks2 0x%p, 0x%p, 0x%p.\n",
5899 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall);
5903 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
5904 FunctionLeave3 * pFuncLeave3,
5905 FunctionTailcall3 * pFuncTailcall3)
5919 EE_THREAD_NOT_REQUIRED;
5926 // The profiler must call SetEnterLeaveFunctionHooks3 during initialization, since
5927 // the enter/leave events are immutable and must also be set during initialization.
5928 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5930 "**PROF: SetEnterLeaveFunctionHooks3 0x%p, 0x%p, 0x%p.\n",
5936 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3,
5943 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
5944 FunctionLeave3WithInfo * pFuncLeave3WithInfo,
5945 FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
5959 EE_THREAD_NOT_REQUIRED;
5966 // The profiler must call SetEnterLeaveFunctionHooks3WithInfo during initialization, since
5967 // the enter/leave events are immutable and must also be set during initialization.
5968 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5970 "**PROF: SetEnterLeaveFunctionHooks3WithInfo 0x%p, 0x%p, 0x%p.\n",
5971 pFuncEnter3WithInfo,
5972 pFuncLeave3WithInfo,
5973 pFuncTailcall3WithInfo));
5976 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo,
5977 pFuncLeave3WithInfo,
5978 pFuncTailcall3WithInfo);
5982 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper(FunctionIDMapper *pFunc)
5996 EE_THREAD_NOT_REQUIRED;
6004 PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF,
6006 "**PROF: SetFunctionIDMapper 0x%p.\n",
6009 g_profControlBlock.pProfInterface->SetFunctionIDMapper(pFunc);
6014 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper2(FunctionIDMapper2 *pFunc, void * clientData)
6028 EE_THREAD_NOT_REQUIRED;
6036 PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF,
6038 "**PROF: SetFunctionIDMapper2. pFunc: 0x%p. clientData: 0x%p.\n",
6042 g_profControlBlock.pProfInterface->SetFunctionIDMapper2(pFunc, clientData);
6050 * This function takes the frameInfo returned from a profiler callback and splays it
6051 * out into as much information as possible.
6054 * funcId - The function that is being requested.
6055 * frameInfo - Frame specific information from a callback (for resolving generics).
6056 * pClassId - An optional parameter for returning the class id of the function.
6057 * pModuleId - An optional parameter for returning the module of the function.
6058 * pToken - An optional parameter for returning the metadata token of the function.
6059 * cTypeArgs - The count of the size of the array typeArgs
6060 * pcTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
6061 * the number that would be needed.
6062 * typeArgs - An array to store generic type parameters for the function.
6065 * S_OK if successful.
6067 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo2(FunctionID funcId,
6068 COR_PRF_FRAME_INFO frameInfo,
6070 ModuleID *pModuleId,
6073 ULONG32 *pcTypeArgs,
6088 EE_THREAD_NOT_REQUIRED;
6090 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6091 // reads metadata which causes us to take a reader lock. However, see
6092 // code:#DisableLockOnAsyncCalls
6093 DISABLED(CAN_TAKE_LOCK);
6095 // Asynchronous functions can be called at arbitrary times when runtime
6096 // is holding locks that cannot be reentered without causing deadlock.
6097 // This contract detects any attempts to reenter locks held at the time
6098 // this function was called.
6102 PRECONDITION(CheckPointer(pClassId, NULL_OK));
6103 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6104 PRECONDITION(CheckPointer(pToken, NULL_OK));
6105 PRECONDITION(CheckPointer(pcTypeArgs, NULL_OK));
6106 PRECONDITION(CheckPointer(typeArgs, NULL_OK));
6110 // See code:#DisableLockOnAsyncCalls
6111 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6113 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6116 "**PROF: GetFunctionInfo2 0x%p.\n",
6120 // Verify parameters.
6122 COR_PRF_FRAME_INFO_INTERNAL *pFrameInfo = (COR_PRF_FRAME_INFO_INTERNAL *)frameInfo;
6124 if ((funcId == NULL) ||
6125 ((pFrameInfo != NULL) && (pFrameInfo->funcID != funcId)))
6127 return E_INVALIDARG;
6130 MethodDesc *pMethDesc = FunctionIdToMethodDesc(funcId);
6132 if (pMethDesc == NULL)
6134 return E_INVALIDARG;
6137 if ((cTypeArgs != 0) && (typeArgs == NULL))
6139 return E_INVALIDARG;
6142 // it's not safe to examine a methoddesc that has not been restored so do not do so
6143 if (!pMethDesc ->IsRestored())
6144 return CORPROF_E_DATAINCOMPLETE;
6147 // Find the exact instantiation of this function.
6149 TypeHandle specificClass;
6150 MethodDesc* pActualMethod;
6152 ClassID classId = NULL;
6154 if (pMethDesc->IsSharedByGenericInstantiations())
6157 OBJECTREF pThis = NULL;
6159 if (pFrameInfo != NULL)
6161 // If FunctionID represents a generic methoddesc on a struct, then pFrameInfo->thisArg
6162 // isn't an Object*. It's a pointer directly into the struct's members (i.e., it's not pointing at the
6163 // method table). That means pFrameInfo->thisArg cannot be casted to an OBJECTREF for
6164 // use by Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation. However,
6165 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation won't even need a this pointer
6166 // for the methoddesc it's processing if the methoddesc is on a value type. So we
6167 // can safely pass NULL for the methoddesc's this in such a case.
6168 if (pMethDesc->GetMethodTable()->IsValueType())
6170 _ASSERTE(!pMethDesc->AcquiresInstMethodTableFromThis());
6171 _ASSERTE(pThis == NULL);
6175 pThis = ObjectToOBJECTREF((PTR_Object)(pFrameInfo->thisArg));
6179 exactMatch = Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
6182 PTR_VOID((pFrameInfo != NULL) ? pFrameInfo->extraArg : NULL),
6188 classId = TypeHandleToClassID(specificClass);
6190 else if (!specificClass.HasInstantiation() || !specificClass.IsSharedByGenericInstantiations())
6193 // In this case we could not get the type args for the method, but if the class
6194 // is not a generic class or is instantiated with value types, this value is correct.
6196 classId = TypeHandleToClassID(specificClass);
6201 // We could not get any class information.
6208 TypeHandle typeHandle(pMethDesc->GetMethodTable());
6209 classId = TypeHandleToClassID(typeHandle);
6210 pActualMethod = pMethDesc;
6215 // Fill in the ClassId, if desired
6217 if (pClassId != NULL)
6219 *pClassId = classId;
6223 // Fill in the ModuleId, if desired.
6225 if (pModuleId != NULL)
6227 *pModuleId = (ModuleID)pMethDesc->GetModule();
6231 // Fill in the token, if desired.
6235 *pToken = (mdToken)pMethDesc->GetMemberDef();
6238 if ((cTypeArgs == 0) && (pcTypeArgs != NULL))
6241 // They are searching for the size of the array needed, we can return that now and
6242 // short-circuit all the work below.
6244 if (pcTypeArgs != NULL)
6246 *pcTypeArgs = pActualMethod->GetNumGenericMethodArgs();
6252 // If no place to store resulting count, quit now.
6254 if (pcTypeArgs == NULL)
6260 // Fill in the type args
6262 DWORD cArgsToFill = pActualMethod->GetNumGenericMethodArgs();
6264 if (cArgsToFill > cTypeArgs)
6266 cArgsToFill = cTypeArgs;
6269 *pcTypeArgs = cArgsToFill;
6271 if (cArgsToFill == 0)
6276 Instantiation inst = pActualMethod->GetMethodInstantiation();
6278 for (DWORD i = 0; i < cArgsToFill; i++)
6280 typeArgs[i] = TypeHandleToClassID(inst[i]);
6289 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6290 * or LCG method and returns true in the pHasNoMetadata if it is indeed a metadata-less
6294 * functionId - The function that is being requested.
6295 * isDynamic - An optional parameter for returning if the function has metadata or not.
6298 * S_OK if successful.
6300 HRESULT ProfToEEInterfaceImpl::IsFunctionDynamic(FunctionID functionId, BOOL *isDynamic)
6307 EE_THREAD_NOT_REQUIRED;
6309 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6310 // reads metadata which causes us to take a reader lock. However, see
6311 // code:#DisableLockOnAsyncCalls
6312 DISABLED(CAN_TAKE_LOCK);
6314 // Asynchronous functions can be called at arbitrary times when runtime
6315 // is holding locks that cannot be reentered without causing deadlock.
6316 // This contract detects any attempts to reenter locks held at the time
6317 // this function was called.
6321 PRECONDITION(CheckPointer(isDynamic, NULL_OK));
6325 // See code:#DisableLockOnAsyncCalls
6326 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6328 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6331 "**PROF: IsFunctionDynamic 0x%p.\n",
6335 // Verify parameters.
6338 if (functionId == NULL)
6340 return E_INVALIDARG;
6343 MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6345 if (pMethDesc == NULL)
6347 return E_INVALIDARG;
6350 // it's not safe to examine a methoddesc that has not been restored so do not do so
6351 if (!pMethDesc->IsRestored())
6352 return CORPROF_E_DATAINCOMPLETE;
6355 // Fill in the pHasNoMetadata, if desired.
6357 if (isDynamic != NULL)
6359 *isDynamic = pMethDesc->IsNoMetadata();
6366 * GetFunctionFromIP3
6368 * This function takes an IP and determines if it is a managed function returning its
6369 * FunctionID. This method is different from GetFunctionFromIP in that will return
6370 * FunctionIDs even if they have no associated metadata.
6373 * ip - The instruction pointer.
6374 * pFunctionId - An optional parameter for returning the FunctionID.
6375 * pReJitId - The ReJIT id.
6378 * S_OK if successful.
6380 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP3(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
6386 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6387 // which can switch us to preemptive mode and trigger GCs
6390 EE_THREAD_NOT_REQUIRED;
6392 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6398 // See code:#DisableLockOnAsyncCalls
6399 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6401 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6402 kP2EEAllowableAfterAttach | kP2EETriggers,
6405 "**PROF: GetFunctionFromIP3 0x%p.\n",
6410 EECodeInfo codeInfo;
6412 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ FALSE);
6420 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
6423 if (pReJitId != NULL)
6425 MethodDesc * pMD = codeInfo.GetMethodDesc();
6426 *pReJitId = ReJitManager::GetReJitId(pMD, codeInfo.GetStartAddress());
6433 * GetDynamicFunctionInfo
6435 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6436 * or LCG method and gives information about it without failing like GetFunctionInfo.
6439 * functionId - The function that is being requested.
6440 * pModuleId - An optional parameter for returning the module of the function.
6441 * ppvSig - An optional parameter for returning the signature of the function.
6442 * pbSig - An optional parameter for returning the size of the signature of the function.
6443 * cchName - A parameter for indicating the size of buffer for the wszName parameter.
6444 * pcchName - An optional parameter for returning the true size of the wszName parameter.
6445 * wszName - A parameter to the caller allocated buffer of size cchName
6448 * S_OK if successful.
6450 HRESULT ProfToEEInterfaceImpl::GetDynamicFunctionInfo(FunctionID functionId,
6451 ModuleID *pModuleId,
6452 PCCOR_SIGNATURE* ppvSig,
6456 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[])
6463 EE_THREAD_NOT_REQUIRED;
6465 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6466 // reads metadata which causes us to take a reader lock. However, see
6467 // code:#DisableLockOnAsyncCalls
6468 DISABLED(CAN_TAKE_LOCK);
6470 // Asynchronous functions can be called at arbitrary times when runtime
6471 // is holding locks that cannot be reentered without causing deadlock.
6472 // This contract detects any attempts to reenter locks held at the time
6473 // this function was called.
6477 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6478 PRECONDITION(CheckPointer(ppvSig, NULL_OK));
6479 PRECONDITION(CheckPointer(pbSig, NULL_OK));
6480 PRECONDITION(CheckPointer(pcchName, NULL_OK));
6484 // See code:#DisableLockOnAsyncCalls
6485 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6487 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6490 "**PROF: GetDynamicFunctionInfo 0x%p.\n",
6494 // Verify parameters.
6497 if (functionId == NULL)
6499 return E_INVALIDARG;
6502 MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6504 if (pMethDesc == NULL)
6506 return E_INVALIDARG;
6509 // it's not safe to examine a methoddesc that has not been restored so do not do so
6510 if (!pMethDesc->IsRestored())
6511 return CORPROF_E_DATAINCOMPLETE;
6514 if (!pMethDesc->IsNoMetadata())
6515 return E_INVALIDARG;
6518 // Fill in the ModuleId, if desired.
6520 if (pModuleId != NULL)
6522 *pModuleId = (ModuleID)pMethDesc->GetModule();
6526 // Fill in the ppvSig and pbSig, if desired
6528 if (ppvSig != NULL && pbSig != NULL)
6530 pMethDesc->GetSig(ppvSig, pbSig);
6537 if (wszName != NULL)
6539 if (pcchName != NULL)
6543 ss.SetUTF8(pMethDesc->GetName());
6545 LPCWSTR methodName = ss.GetUnicode();
6547 ULONG trueLen = (ULONG)(wcslen(methodName) + 1);
6549 // Return name of method as required.
6550 if (wszName && cchName > 0)
6552 if (cchName < trueLen)
6554 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6558 wcsncpy_s(wszName, cchName, methodName, trueLen);
6562 // If they request the actual length of the name
6564 *pcchName = trueLen;
6566 EX_CATCH_HRESULT(hr);
6572 * GetNativeCodeStartAddresses
6574 * Gets all of the native code addresses associated with a particular function. iered compilation
6575 * potentially creates different native code versions for a method, and this function allows profilers
6576 * to view all native versions of a method.
6579 * functionID - The function that is being requested.
6580 * reJitId - The ReJIT id.
6581 * cCodeStartAddresses - A parameter for indicating the size of buffer for the codeStartAddresses parameter.
6582 * pcCodeStartAddresses - An optional parameter for returning the true size of the codeStartAddresses parameter.
6583 * codeStartAddresses - The array to be filled up with native code addresses.
6586 * S_OK if successful
6589 HRESULT ProfToEEInterfaceImpl::GetNativeCodeStartAddresses(FunctionID functionID,
6591 ULONG32 cCodeStartAddresses,
6592 ULONG32 *pcCodeStartAddresses,
6593 UINT_PTR codeStartAddresses[])
6600 EE_THREAD_NOT_REQUIRED;
6604 PRECONDITION(CheckPointer(pcCodeStartAddresses, NULL_OK));
6605 PRECONDITION(CheckPointer(codeStartAddresses, NULL_OK));
6609 if (functionID == NULL)
6611 return E_INVALIDARG;
6614 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6617 "**PROF: GetNativeCodeStartAddresses 0x%p 0x%p.\n",
6618 functionID, reJitId));
6624 if (pcCodeStartAddresses != NULL)
6626 *pcCodeStartAddresses = 0;
6629 MethodDesc * methodDesc = FunctionIdToMethodDesc(functionID);
6630 PTR_MethodDesc pMD = PTR_MethodDesc(methodDesc);
6631 ULONG32 trueLen = 0;
6632 StackSArray<UINT_PTR> addresses;
6634 CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
6636 ILCodeVersion ilCodeVersion = NULL;
6638 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
6640 ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
6642 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
6643 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
6645 addresses.Append((*iter).GetNativeCode());
6651 if (pcCodeStartAddresses != NULL)
6653 *pcCodeStartAddresses = trueLen;
6656 if (codeStartAddresses != NULL)
6658 if (cCodeStartAddresses < trueLen)
6660 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6664 for(ULONG32 i = 0; i < trueLen; ++i)
6666 codeStartAddresses[i] = addresses[i];
6671 EX_CATCH_HRESULT(hr);
6677 * GetILToNativeMapping3
6679 * This overload behaves the same as GetILToNativeMapping2, except it allows the profiler
6680 * to address specific native code versions instead of defaulting to the first one.
6683 * pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
6684 * cMap - size of the map array
6685 * pcMap - how many items are returned in the map array
6686 * map - an array to store the il to native mappings in
6689 * S_OK if successful
6692 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping3(UINT_PTR pNativeCodeStartAddress,
6695 COR_DEBUG_IL_TO_NATIVE_MAP map[])
6700 DISABLED(GC_NOTRIGGER);
6705 PRECONDITION(CheckPointer(pcMap, NULL_OK));
6706 PRECONDITION(CheckPointer(map, NULL_OK));
6710 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
6713 "**PROF: GetILToNativeMapping3 0x%p.\n",
6714 pNativeCodeStartAddress));
6716 if (pNativeCodeStartAddress == NULL)
6718 return E_INVALIDARG;
6722 ((pcMap == NULL) || (map == NULL)))
6724 return E_INVALIDARG;
6727 #ifdef DEBUGGING_SUPPORTED
6728 if (g_pDebugInterface == NULL)
6730 return CORPROF_E_DEBUGGING_DISABLED;
6733 return (g_pDebugInterface->GetILToNativeMapping(pNativeCodeStartAddress, cMap, pcMap, map));
6742 * Gets the location and size of a jitted function. Tiered compilation potentially creates different native code
6743 * versions for a method, and this overload allows profilers to specify which native version it would like the
6747 * pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
6748 * cCodeInfos - size of the codeInfos array
6749 * pcCodeInfos - how many items are returned in the codeInfos array
6750 * codeInfos - an array to store the code infos in
6753 * S_OK if successful
6756 HRESULT ProfToEEInterfaceImpl::GetCodeInfo4(UINT_PTR pNativeCodeStartAddress,
6758 ULONG32* pcCodeInfos,
6759 COR_PRF_CODE_INFO codeInfos[])
6766 EE_THREAD_NOT_REQUIRED;
6770 PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
6771 PRECONDITION(CheckPointer(codeInfos, NULL_OK));
6775 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6776 kP2EEAllowableAfterAttach | kP2EETriggers,
6779 "**PROF: GetCodeInfo4 0x%p.\n",
6780 pNativeCodeStartAddress));
6782 if ((cCodeInfos != 0) && (codeInfos == NULL))
6784 return E_INVALIDARG;
6787 return GetCodeInfoFromCodeStart(pNativeCodeStartAddress,
6794 * GetObjectReferences
6796 * Gets the object references (if any) from the ObjectID.
6799 * objectId - object id of interest
6800 * cNumReferences - count of references for which the profiler has allocated buffer space
6801 * pcNumReferences - actual count of references
6802 * references - filled array of object references
6805 * S_OK if successful
6808 HRESULT ProfToEEInterfaceImpl::GetObjectReferences(ObjectID objectId, ULONG32 cNumReferences, ULONG32 *pcNumReferences, ObjectID references[], SIZE_T offsets[])
6815 EE_THREAD_NOT_REQUIRED;
6820 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6821 kP2EEAllowableAfterAttach,
6824 "**PROF: GetObjectReferences 0x%p.\n",
6827 if (cNumReferences > 0 && (pcNumReferences == nullptr || references == nullptr || offsets == nullptr))
6829 return E_INVALIDARG;
6832 Object* pBO = (Object*)objectId;
6833 MethodTable *pMT = pBO->GetMethodTable();
6835 if (pMT->ContainsPointersOrCollectible())
6837 if (cNumReferences == 0)
6839 *pcNumReferences = 0;
6840 GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &CountContainedObjectRef, (void*)pcNumReferences);
6844 ObjectRefOffsetTuple t;
6845 t.pCurObjRef = (Object*)references;
6846 t.pCurObjOffset = offsets;
6848 GCHeapUtilities::GetGCHeap()->DiagWalkObject2(pBO, &SaveContainedObjectRef2, (void*)&t);
6853 *pcNumReferences = 0;
6862 * Determines whether the object is in a read-only segment
6865 * objectId - object id of interest
6868 * S_OK if successful
6871 HRESULT ProfToEEInterfaceImpl::IsFrozenObject(ObjectID objectId, BOOL *pbFrozen)
6878 EE_THREAD_NOT_REQUIRED;
6883 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6884 kP2EEAllowableAfterAttach,
6887 "**PROF: IsFrozenObject 0x%p.\n",
6890 *pbFrozen = GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)objectId) ? TRUE : FALSE;
6896 * GetLOHObjectSizeThreshold
6898 * Gets the value of the configured LOH Threshold.
6901 * pThreshold - value of the threshold in bytes
6904 * S_OK if successful
6907 HRESULT ProfToEEInterfaceImpl::GetLOHObjectSizeThreshold(DWORD *pThreshold)
6914 EE_THREAD_NOT_REQUIRED;
6919 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6920 kP2EEAllowableAfterAttach,
6923 "**PROF: GetLOHObjectSizeThreshold\n"));
6925 if (pThreshold == nullptr)
6927 return E_INVALIDARG;
6930 *pThreshold = g_pConfig->GetGCLOHThreshold();
6938 * This function describes to a profiler the internal layout of a string.
6941 * pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
6942 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
6943 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
6946 * S_OK if successful.
6948 HRESULT ProfToEEInterfaceImpl::GetStringLayout(ULONG *pBufferLengthOffset,
6949 ULONG *pStringLengthOffset,
6950 ULONG *pBufferOffset)
6964 EE_THREAD_NOT_REQUIRED;
6970 PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
6971 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
6972 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
6976 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
6979 "**PROF: GetStringLayout.\n"));
6981 return this->GetStringLayoutHelper(pBufferLengthOffset, pStringLengthOffset, pBufferOffset);
6987 * This function describes to a profiler the internal layout of a string.
6990 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
6991 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
6994 * S_OK if successful.
6996 HRESULT ProfToEEInterfaceImpl::GetStringLayout2(ULONG *pStringLengthOffset,
6997 ULONG *pBufferOffset)
7011 EE_THREAD_NOT_REQUIRED;
7017 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7018 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
7022 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7025 "**PROF: GetStringLayout2.\n"));
7027 ULONG dummyBufferLengthOffset;
7028 return this->GetStringLayoutHelper(&dummyBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7032 * GetStringLayoutHelper
7034 * This function describes to a profiler the internal layout of a string.
7037 * pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7038 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7039 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7042 * S_OK if successful.
7044 HRESULT ProfToEEInterfaceImpl::GetStringLayoutHelper(ULONG *pBufferLengthOffset,
7045 ULONG *pStringLengthOffset,
7046 ULONG *pBufferOffset)
7060 EE_THREAD_NOT_REQUIRED;
7066 PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7067 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7068 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
7072 // The String class no longer has a bufferLength field in it.
7073 // We are returning the offset of the stringLength because that is the closest we can get
7074 // This is most certainly a breaking change and a new method
7075 // ICorProfilerInfo3::GetStringLayout2 has been added on the interface ICorProfilerInfo3
7076 if (pBufferLengthOffset != NULL)
7078 *pBufferLengthOffset = StringObject::GetStringLengthOffset();
7081 if (pStringLengthOffset != NULL)
7083 *pStringLengthOffset = StringObject::GetStringLengthOffset();
7086 if (pBufferOffset != NULL)
7088 *pBufferOffset = StringObject::GetBufferOffset();
7097 * This function describes to a profiler the internal layout of a class.
7100 * classID - The class that is being queried. It is really a TypeHandle.
7101 * rFieldOffset - An array to store information about each field in the class.
7102 * cFieldOffset - Count of the number of elements in rFieldOffset.
7103 * pcFieldOffset - Upon return contains the number of elements filled in, or if
7104 * cFieldOffset is zero, the number of elements needed.
7105 * pulClassSize - Optional parameter for containing the size in bytes of the underlying
7106 * internal class structure.
7109 * S_OK if successful.
7111 HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID,
7112 COR_FIELD_OFFSET rFieldOffset[],
7114 ULONG *pcFieldOffset,
7115 ULONG *pulClassSize)
7129 EE_THREAD_NOT_REQUIRED;
7135 PRECONDITION(CheckPointer(rFieldOffset, NULL_OK));
7136 PRECONDITION(CheckPointer(pcFieldOffset));
7137 PRECONDITION(CheckPointer(pulClassSize, NULL_OK));
7141 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7144 "**PROF: GetClassLayout 0x%p.\n",
7148 // Verify parameters
7150 if ((pcFieldOffset == NULL) || (classID == NULL))
7152 return E_INVALIDARG;
7155 if ((cFieldOffset != 0) && (rFieldOffset == NULL))
7157 return E_INVALIDARG;
7160 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classID);
7163 // This is the incorrect API for arrays or strings. Use GetArrayObjectInfo, and GetStringLayout
7165 if (typeHandle.IsTypeDesc() || typeHandle.AsMethodTable()->IsArray())
7167 return E_INVALIDARG;
7171 // We used to have a bug where this API incorrectly succeeded for strings during startup. Profilers
7172 // took dependency on this bug. Let the API to succeed for strings during startup for backward compatibility.
7174 if (typeHandle.AsMethodTable()->IsString() && g_profControlBlock.fBaseSystemClassesLoaded)
7176 return E_INVALIDARG;
7180 // If this class is not fully restored, that is all the information we can get at this time.
7182 if (!typeHandle.IsRestored())
7184 return CORPROF_E_DATAINCOMPLETE;
7187 // Types can be pre-restored, but they still aren't expected to handle queries before
7188 // eager fixups have run. This is a targetted band-aid for a bug intellitrace was
7189 // running into - attempting to get the class layout for all types at module load time.
7190 // If we don't detect this the runtime will AV during the field iteration below. Feel
7191 // free to eliminate this check when a more complete solution is available.
7192 if (MethodTable::IsParentMethodTableTagged(typeHandle.AsMethodTable()))
7194 return CORPROF_E_DATAINCOMPLETE;
7197 // !IsValueType = IsArray || IsReferenceType Since IsArry has been ruled out above, it must
7198 // be a reference type if !IsValueType.
7199 BOOL fReferenceType = !typeHandle.IsValueType();
7202 // Fill in class size now
7204 // Move after the check for typeHandle.GetMethodTable()->IsRestored()
7205 // because an unrestored MethodTable may have a bad EE class pointer
7206 // which will be used by MethodTable::GetNumInstanceFieldBytes
7208 if (pulClassSize != NULL)
7212 // aligned size including the object header for reference types
7213 *pulClassSize = typeHandle.GetMethodTable()->GetBaseSize();
7217 // unboxed and unaligned size for value types
7218 *pulClassSize = typeHandle.GetMethodTable()->GetNumInstanceFieldBytes();
7222 ApproxFieldDescIterator fieldDescIterator(typeHandle.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
7224 ULONG cFields = fieldDescIterator.Count();
7227 // If they are looking to just get the count, return that.
7229 if ((cFieldOffset == 0) || (rFieldOffset == NULL))
7231 *pcFieldOffset = cFields;
7236 // Dont put too many in the array.
7238 if (cFields > cFieldOffset)
7240 cFields = cFieldOffset;
7243 *pcFieldOffset = cFields;
7246 // Now fill in the array
7251 for (i = 0; i < cFields; i++)
7253 pField = fieldDescIterator.Next();
7254 rFieldOffset[i].ridOfField = (ULONG)pField->GetMemberDef();
7255 rFieldOffset[i].ulOffset = (ULONG)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
7262 typedef struct _PROFILER_STACK_WALK_DATA
7264 StackSnapshotCallback *callback;
7266 ULONG32 contextFlags;
7269 #ifdef WIN64EXCEPTIONS
7270 StackFrame sfParent;
7272 } PROFILER_STACK_WALK_DATA;
7276 * ProfilerStackWalkCallback
7278 * This routine is used as the callback from the general stack walker for
7279 * doing snapshot stack walks
7282 StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_DATA *pData)
7286 NOTHROW; // throw is RIGHT out... the throw at minimum allocates the thrown object which we *must* not do
7287 GC_NOTRIGGER; // the stack is not necessarily crawlable at this state !!!) we must not induce a GC
7291 MethodDesc *pFunc = pCf->GetFunction();
7293 COR_PRF_FRAME_INFO_INTERNAL frameInfo;
7294 ULONG32 contextSize = 0;
7295 BYTE *context = NULL;
7297 UINT_PTR currentIP = 0;
7298 REGDISPLAY *pRegDisplay = pCf->GetRegisterSet();
7299 #if defined(_TARGET_X86_)
7300 CONTEXT builtContext;
7304 // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want
7305 // to return to the profiler as the context seed if it wants to walk the unmanaged
7306 // stack frame, so we report the functionId as NULL to indicate this.
7308 if (pCf->IsNativeMarker())
7314 // Skip all Lightweight reflection/emit functions
7316 if ((pFunc != NULL) && pFunc->IsNoMetadata())
7318 return SWA_CONTINUE;
7322 // If this is not a transition of any sort and not a managed
7323 // method, ignore it.
7325 if (!pCf->IsNativeMarker() && !pCf->IsFrameless())
7327 return SWA_CONTINUE;
7330 currentIP = (UINT_PTR)pRegDisplay->ControlPC;
7332 frameInfo.size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
7333 frameInfo.version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
7337 frameInfo.funcID = MethodDescToFunctionID(pFunc);
7338 frameInfo.extraArg = NULL;
7342 frameInfo.funcID = NULL;
7343 frameInfo.extraArg = NULL;
7346 frameInfo.IP = currentIP;
7347 frameInfo.thisArg = NULL;
7349 if (pData->infoFlags & COR_PRF_SNAPSHOT_REGISTER_CONTEXT)
7351 #if defined(_TARGET_X86_)
7353 // X86 stack walking does not keep the context up-to-date during the
7354 // walk. Instead it keeps the REGDISPLAY up-to-date. Thus, we need to
7355 // build a CONTEXT from the REGDISPLAY.
7358 memset(&builtContext, 0, sizeof(builtContext));
7359 builtContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
7360 CopyRegDisplay(pRegDisplay, NULL, &builtContext);
7361 context = (BYTE *)(&builtContext);
7363 context = (BYTE *)pRegDisplay->pCurrentContext;
7365 contextSize = sizeof(CONTEXT);
7368 // NOTE: We are intentionally not setting any callback state flags here (i.e., not using
7369 // SetCallbackStateFlagsHolder), as we want the DSS callback to "inherit" the
7370 // same callback state that DSS has: if DSS was called asynchronously, then consider
7371 // the DSS callback to be called asynchronously.
7372 if (pData->callback(frameInfo.funcID,
7374 (COR_PRF_FRAME_INFO)&frameInfo,
7377 pData->clientData) == S_OK)
7379 return SWA_CONTINUE;
7387 //---------------------------------------------------------------------------------------
7388 // Normally, calling GetFunction() on the frame is sufficient to ensure
7389 // HelperMethodFrames are intialized. However, sometimes we need to be able to specify
7390 // that we should not enter the host while initializing, so we need to initialize such
7391 // frames more directly. This small helper function directly forces the initialization,
7392 // and ensures we don't enter the host as a result if we're executing in an asynchronous
7393 // call (i.e., hijacked thread)
7396 // pFrame - Frame to initialize.
7399 // TRUE iff pFrame was successfully initialized (or was already initialized). If
7400 // pFrame is not a HelperMethodFrame (or derived type), this returns TRUE
7401 // immediately. FALSE indicates we tried to initialize w/out entering the host, and
7402 // had to abort as a result when a reader lock was needed but unavailable.
7405 static BOOL EnsureFrameInitialized(Frame * pFrame)
7412 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7413 // host (SQL). Corners will be cut to ensure this is the case
7414 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7420 if (pFrame->GetFrameType() != Frame::TYPE_HELPER_METHOD_FRAME)
7422 // This frame is not a HelperMethodFrame or a frame derived from
7423 // HelperMethodFrame, so HMF-specific lazy initialization is not an issue.
7427 HelperMethodFrame * pHMF = (HelperMethodFrame *) pFrame;
7429 if (pHMF->InsureInit(
7430 false, // initialInit
7431 NULL, // unwindState
7432 (ShouldAvoidHostCalls() ?
7437 // InsureInit() succeeded and found the return address
7441 // No return address was found. It must be because we asked InsureInit() to bail if
7442 // it would have entered the host
7443 _ASSERTE(ShouldAvoidHostCalls());
7447 //---------------------------------------------------------------------------------------
7449 // Implements the COR_PRF_SNAPSHOT_X86_OPTIMIZED algorithm called by DoStackSnapshot.
7450 // Does a simple EBP walk, rather than invoking all of StackWalkFramesEx.
7453 // pThreadToSnapshot - Thread whose stack should be walked
7454 // pctxSeed - Register context with which to seed the walk
7455 // callback - Function to call at each frame found during the walk
7456 // clientData - Parameter to pass through to callback
7459 // HRESULT indicating success or failure.
7462 HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
7463 Thread * pThreadToSnapshot,
7465 StackSnapshotCallback * callback,
7473 EE_THREAD_NOT_REQUIRED;
7475 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7476 // host (SQL). Corners will be cut to ensure this is the case
7477 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7483 // We haven't set the stackwalker thread type flag yet (see next line), so it shouldn't be set. Only
7484 // exception to this is if the current call is made by a hijacking profiler which
7485 // redirected this thread while it was previously in the middle of another stack walk
7486 _ASSERTE(IsCalledAsynchronously() || !IsStackWalkerThread());
7488 // Remember that we're walking the stack. This holder will reinstate the original
7489 // value of the stackwalker flag (from the thread type mask) in its destructor.
7490 ClrFlsValueSwitch _threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThreadToSnapshot);
7492 // This flag remembers if we reported a managed frame since the last unmanaged block
7493 // we reported. It's used to avoid reporting two unmanaged blocks in a row.
7494 BOOL fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7496 Frame * pFrameCur = pThreadToSnapshot->GetFrame();
7499 ZeroMemory(&ctxCur, sizeof(ctxCur));
7501 // Use seed if we got one. Otherwise, EE explicit Frame chain will seed the walk.
7502 if (pctxSeed != NULL)
7504 ctxCur.Ebp = pctxSeed->Ebp;
7505 ctxCur.Eip = pctxSeed->Eip;
7506 ctxCur.Esp = pctxSeed->Esp;
7511 // At each iteration of the loop:
7512 // * Analyze current frame (get managed data if it's a managed frame)
7513 // * Report current frame via callback()
7514 // * Walk down to next frame
7516 // **** Managed or unmanaged frame? ****
7518 EECodeInfo codeInfo;
7519 MethodDesc * pMethodDescCur = NULL;
7521 if (ctxCur.Eip != 0)
7523 hr = GetFunctionInfoInternal(
7524 (LPCBYTE) ctxCur.Eip,
7526 if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
7528 _ASSERTE(ShouldAvoidHostCalls());
7533 pMethodDescCur = codeInfo.GetMethodDesc();
7537 // **** Report frame to profiler ****
7540 // Make sure the frame gave us an IP
7541 (ctxCur.Eip != 0) &&
7543 // Make sure any managed frame isn't for an IL stub or LCG
7544 ((pMethodDescCur == NULL) || !pMethodDescCur->IsNoMetadata()) &&
7546 // Only report unmanaged frames if the last frame we reported was managed
7547 // (avoid reporting two unmanaged blocks in a row)
7548 ((pMethodDescCur != NULL) || fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock))
7550 // Around the call to the profiler, temporarily clear the
7551 // ThreadType_StackWalker type flag, as we have no control over what the
7552 // profiler may do inside its callback (it could theoretically attempt to
7553 // load other types, though I don't personally know of profilers that
7554 // currently do this).
7556 CLEAR_THREAD_TYPE_STACKWALKER();
7558 (FunctionID) pMethodDescCur,
7560 NULL, // COR_PRF_FRAME_INFO
7561 sizeof(ctxCur), // contextSize,
7562 (LPBYTE) &ctxCur, // context,
7564 SET_THREAD_TYPE_STACKWALKER(pThreadToSnapshot);
7570 if (pMethodDescCur == NULL)
7572 // Just reported an unmanaged block, so reset the flag
7573 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7577 // Just reported a managed block, so remember it
7578 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = TRUE;
7582 // **** Walk down to next frame ****
7584 // Is current frame managed or unmanaged?
7585 if (pMethodDescCur == NULL)
7587 // Unmanaged frame. Use explicit EE Frame chain to help
7590 ZeroMemory(&frameRD, sizeof(frameRD));
7592 while (pFrameCur != FRAME_TOP)
7594 // Frame is only useful if it will contain register context info
7595 if (!pFrameCur->NeedsUpdateRegDisplay())
7601 // This should be the first call we make to the Frame, as it will
7602 // ensure we force lazy initialize of HelperMethodFrames
7603 if (!EnsureFrameInitialized(pFrameCur))
7605 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7608 // This frame is only useful if it gives us an actual return address,
7609 // and is situated on the stack at or below our current ESP (stack
7611 if ((pFrameCur->GetReturnAddress() != NULL) &&
7612 (dac_cast<TADDR>(pFrameCur) >= dac_cast<TADDR>(ctxCur.Esp)))
7614 pFrameCur->UpdateRegDisplay(&frameRD);
7619 pFrameCur = pFrameCur->PtrNextFrame();
7622 if (pFrameCur == FRAME_TOP)
7624 // No more frames. Stackwalk is over
7628 // Update ctxCur based on frame
7629 ctxCur.Eip = pFrameCur->GetReturnAddress();
7630 ctxCur.Ebp = GetRegdisplayFP(&frameRD);
7631 ctxCur.Esp = GetRegdisplaySP(&frameRD);
7637 // GC info will assist us in determining whether this is a non-EBP frame and
7638 // info about pushed arguments.
7639 GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
7640 PTR_VOID gcInfo = gcInfoToken.Info;
7642 unsigned uiMethodSizeDummy;
7643 PTR_CBYTE table = PTR_CBYTE(gcInfo);
7644 table += decodeUnsigned(table, &uiMethodSizeDummy);
7645 table = decodeHeader(table, gcInfoToken.Version, &header);
7647 // Ok, GCInfo, can we do a simple EBP walk or what?
7649 if ((codeInfo.GetRelOffset() < header.prologSize) ||
7650 (!header.ebpFrame && !header.doubleAlign))
7652 // We're either in the prolog or we're not in an EBP frame, in which case
7653 // we'll just defer to the code manager to unwind for us. This condition
7654 // is relatively rare, but can occur if:
7656 // * The profiler did a DSS from its Enter hook, in which case we're
7657 // still inside the prolog, OR
7658 // * The seed context or explicit EE Frame chain seeded us with a
7659 // non-EBP frame function. In this case, using a naive EBP
7660 // unwinding algorithm would actually skip over the next EBP
7661 // frame, and would get SP all wrong as we try skipping over
7662 // the pushed parameters. So let's just ask the code manager for
7665 // Note that there are yet more conditions (much more rare) where the EBP
7666 // walk could get lost (e.g., we're inside an epilog). But we only care
7667 // about the most likely cases, and it's ok if the unlikely cases result
7668 // in truncated stacks, as unlikely cases will be statistically
7669 // irrelevant to CPU performance sampling profilers
7670 CodeManState codeManState;
7671 codeManState.dwIsSet = 0;
7673 ZeroMemory(&rd, sizeof(rd));
7675 rd.SetEbpLocation(&ctxCur.Ebp);
7677 rd.ControlPC = ctxCur.Eip;
7679 codeInfo.GetCodeManager()->UnwindStackFrame(
7682 SpeculativeStackwalk,
7686 ctxCur.Ebp = *rd.GetEbpLocation();
7688 ctxCur.Eip = rd.ControlPC;
7692 // We're in an actual EBP frame, so we can simplistically walk down to
7693 // the next frame using EBP.
7695 // Return address is stored just below saved EBP (stack grows up)
7696 ctxCur.Eip = *(DWORD *) (ctxCur.Ebp + sizeof(DWORD));
7699 // Stack location where current function pushed its EBP
7702 // Skip past that EBP
7705 // Skip past return address pushed by caller
7708 // Skip past arguments to current function that were pushed by caller.
7709 // (Caller will pop varargs, so don't count those.)
7710 (header.varargs ? 0 : (header.argCount * sizeof(DWORD)));
7712 // EBP for frame below us (stack grows up) has been saved onto our own
7713 // frame. Dereference it now.
7714 ctxCur.Ebp = *(DWORD *) ctxCur.Ebp;
7719 #endif // _TARGET_X86_
7721 //*****************************************************************************
7722 // The profiler stackwalk Wrapper
7723 //*****************************************************************************
7724 HRESULT ProfToEEInterfaceImpl::ProfilerStackWalkFramesWrapper(Thread * pThreadToSnapshot, PROFILER_STACK_WALK_DATA * pData, unsigned flags)
7726 STATIC_CONTRACT_WRAPPER;
7728 StackWalkAction swaRet = pThreadToSnapshot->StackWalkFrames(
7729 (PSTACKWALKFRAMESCALLBACK)ProfilerStackWalkCallback,
7737 _ASSERTE(!"Unexpected StackWalkAction returned from Thread::StackWalkFrames");
7744 return CORPROF_E_STACKSNAPSHOT_ABORTED;
7751 //---------------------------------------------------------------------------------------
7753 // DoStackSnapshot helper to call FindJitMan to determine if the specified
7754 // context is in managed code.
7757 // pCtx - Context to look at
7758 // hostCallPreference - Describes how to acquire the reader lock--either AllowHostCalls
7759 // or NoHostCalls (see code:HostCallPreference).
7762 // S_OK: The context is in managed code
7763 // S_FALSE: The context is not in managed code.
7764 // Error: Unable to determine (typically because hostCallPreference was NoHostCalls
7765 // and the reader lock was unattainable without yielding)
7768 HRESULT IsContextInManagedCode(const CONTEXT * pCtx, HostCallPreference hostCallPreference)
7770 WRAPPER_NO_CONTRACT;
7771 BOOL fFailedReaderLock = FALSE;
7773 // if there's no Jit Manager for the IP, it's not managed code.
7774 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(pCtx), hostCallPreference, &fFailedReaderLock);
7775 if (fFailedReaderLock)
7777 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7780 return fIsManagedCode ? S_OK : S_FALSE;
7783 //*****************************************************************************
7784 // Perform a stack walk, calling back to callback at each managed frame.
7785 //*****************************************************************************
7786 HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread,
7787 StackSnapshotCallback *callback,
7791 ULONG32 contextSize)
7794 #if !defined(FEATURE_HIJACK)
7796 // DoStackSnapshot needs Thread::Suspend/ResumeThread functionality.
7797 // On platforms w/o support for these APIs return E_NOTIMPL.
7800 #else // !defined(FEATURE_HIJACK)
7804 // Yay! (Note: NOTHROW is vital. The throw at minimum allocates
7805 // the thrown object which we *must* not do.)
7808 // Yay! (Note: this is called asynchronously to view the stack at arbitrary times,
7809 // so the stack is not necessarily crawlable for GC at this state!)
7816 EE_THREAD_NOT_REQUIRED;
7818 // #DisableLockOnAsyncCalls
7819 // This call is allowed asynchronously, however it does take locks. Therefore,
7820 // we will hit contract asserts if we happen to be in a CANNOT_TAKE_LOCK zone when
7821 // a hijacking profiler hijacks this thread to run DoStackSnapshot. CANNOT_RETAKE_LOCK
7822 // is a more granular locking contract that says "I promise that if I take locks, I
7823 // won't reenter any locks that were taken before this function was called".
7824 DISABLED(CAN_TAKE_LOCK);
7826 // Asynchronous functions can be called at arbitrary times when runtime
7827 // is holding locks that cannot be reentered without causing deadlock.
7828 // This contract detects any attempts to reenter locks held at the time
7829 // this function was called.
7835 // This CONTRACT_VIOLATION is still needed because DISABLED(CAN_TAKE_LOCK) does not
7836 // turn off contract violations.
7837 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
7839 LPCONTEXT pctxSeed = reinterpret_cast<LPCONTEXT> (pbContext);
7841 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7844 "**PROF: DoStackSnapshot 0x%p, 0x%p, 0x%08x, 0x%p, 0x%p, 0x%08x.\n",
7852 HRESULT hr = E_UNEXPECTED;
7853 // (hr assignment is to appease the compiler; we won't actually return without explicitly setting hr again)
7855 Thread *pThreadToSnapshot = NULL;
7856 Thread * pCurrentThread = GetThreadNULLOk();
7857 BOOL fResumeThread = FALSE;
7858 INDEBUG(ULONG ulForbidTypeLoad = 0;)
7859 BOOL fResetSnapshotThreadExternalCount = FALSE;
7860 int cRefsSnapshotThread = 0;
7862 // Remember whether we've already determined the current context of the target thread
7863 // is in managed (S_OK), not in managed (S_FALSE), or unknown (error).
7864 HRESULT hrCurrentContextIsManaged = E_FAIL;
7867 memset(&ctxCurrent, 0, sizeof(ctxCurrent));
7871 PROFILER_STACK_WALK_DATA data;
7875 // no managed code has run and things are likely in a very bad have loaded state
7876 // this is a bad time to try to walk the stack
7878 // Returning directly as there is nothing to cleanup yet
7879 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7882 if (!CORProfilerStackSnapshotEnabled())
7884 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7885 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
7890 pThreadToSnapshot = pCurrentThread;
7894 pThreadToSnapshot = (Thread *)thread;
7898 if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT | COR_PRF_SNAPSHOT_X86_OPTIMIZED)) != 0)
7900 if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT)) != 0)
7903 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7904 return E_INVALIDARG;
7907 if (!IsManagedThread(pThreadToSnapshot) || !IsGarbageCollectorFullyInitialized())
7910 // No managed frames, return now.
7912 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7916 // We must make sure no other thread tries to hijack the thread we're about to walk
7917 // Hijacking means Thread::HijackThread, i.e. bashing return addresses which would break the stack walk
7918 Thread::HijackLockHolder hijackLockHolder(pThreadToSnapshot);
7919 if (!hijackLockHolder.Acquired())
7921 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7922 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7925 if (pThreadToSnapshot != pCurrentThread // Walking separate thread
7926 && pCurrentThread != NULL // Walker (current) thread is a managed / VM thread
7927 && ThreadSuspend::SysIsSuspendInProgress()) // EE is trying suspend itself
7929 // Since we're walking a separate thread, we'd have to suspend it first (see below).
7930 // And since the current thread is a VM thread, that means the current thread's
7931 // m_dwForbidSuspendThread count will go up while it's trying to suspend the
7932 // target thread (see Thread::SuspendThread). THAT means no one will be able
7933 // to suspend the current thread until its m_dwForbidSuspendThread is decremented
7934 // (which happens as soon as the target thread of DoStackSnapshot has been suspended).
7935 // Since we're in the process of suspending the entire runtime, now would be a bad time to
7936 // make the walker thread un-suspendable (see VsWhidbey bug 454936). So let's just abort
7937 // now. Note that there is no synchronization around calling Thread::SysIsSuspendInProgress().
7938 // So we will get occasional false positives or false negatives. But that's benign, as the worst
7939 // that might happen is we might occasionally delay the EE suspension a little bit, or we might
7940 // too eagerly fail from ProfToEEInterfaceImpl::DoStackSnapshot sometimes. But there won't
7941 // be any corruption or AV.
7943 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7944 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7947 // We only allow stackwalking if:
7948 // 1) Target thread to walk == current thread OR Target thread is suspended, AND
7949 // 2) Target thread to walk is currently executing JITted / NGENd code, AND
7950 // 3) Target thread to walk is seeded OR currently NOT unwinding the stack, AND
7951 // 4) Target thread to walk != current thread OR current thread is NOT in a can't stop or forbid suspend region
7953 // If the thread is in a forbid suspend region, it's dangerous to do anything:
7954 // - The code manager datastructures accessed during the stackwalk may be in inconsistent state.
7955 // - Thread::Suspend won't be able to suspend the thread.
7956 if (pThreadToSnapshot->IsInForbidSuspendRegion())
7958 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
7962 HostCallPreference hostCallPreference;
7964 // First, check "1) Target thread to walk == current thread OR Target thread is suspended"
7965 if (pThreadToSnapshot != pCurrentThread)
7967 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7971 // Walking separate thread, so it must be suspended. First, ensure that
7972 // target thread exists.
7974 // NOTE: We're using the "dangerous" variant of this refcount function, because we
7975 // rely on the profiler to ensure it never tries to walk a thread being destroyed.
7976 // (Profiler must block in its ThreadDestroyed() callback until all uses of that thread,
7977 // such as walking its stack, are complete.)
7978 cRefsSnapshotThread = pThreadToSnapshot->IncExternalCountDANGEROUSProfilerOnly();
7979 fResetSnapshotThreadExternalCount = TRUE;
7981 if (cRefsSnapshotThread == 1 || !pThreadToSnapshot->HasValidThreadHandle())
7983 // At this point, we've modified the VM state based on bad input
7984 // (pThreadToSnapshot) from the profiler. This could cause
7985 // memory corruption and leave us vulnerable to security problems.
7986 // So destroy the process.
7987 _ASSERTE(!"Profiler trying to walk destroyed thread");
7988 EEPOLICY_HANDLE_FATAL_ERROR(CORPROF_E_STACKSNAPSHOT_INVALID_TGT_THREAD);
7991 // Thread::SuspendThread() ensures that no one else should try to suspend us
7992 // while we're suspending pThreadToSnapshot.
7994 // TRUE: OneTryOnly. Don't loop waiting for others to get out of our way in
7995 // order to suspend the thread. If it's not safe, just return an error immediately.
7996 Thread::SuspendThreadResult str = pThreadToSnapshot->SuspendThread(TRUE);
7997 if (str == Thread::STR_Success)
7999 fResumeThread = TRUE;
8003 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8006 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8009 hostCallPreference =
8010 ShouldAvoidHostCalls() ?
8011 NoHostCalls : // Async call: Ensure this thread won't yield & re-enter host
8012 AllowHostCalls; // Synchronous calls may re-enter host just fine
8014 // If target thread is in pre-emptive mode, the profiler's seed context is unnecessary
8015 // because our frame chain is good enough: it will give us at least as accurate a
8016 // starting point as the profiler could. Also, since profiler contexts cannot be
8017 // trusted, we don't want to set the thread's profiler filter context to this, as a GC
8018 // that interrupts the profiler's stackwalk will end up using the profiler's (potentially
8019 // bogus) filter context.
8020 if (!pThreadToSnapshot->PreemptiveGCDisabledOther())
8022 // Thread to be walked is in preemptive mode. Throw out seed.
8025 else if (pThreadToSnapshot != pCurrentThread)
8027 // With cross-thread stack-walks, the target thread's context could be unreliable.
8028 // That would shed doubt on either a profiler-provided context, or a default
8029 // context we chose. So check if we're in a potentially unreliable case, and return
8032 // These heurisitics are based on an actual bug where GetThreadContext returned a
8033 // self-consistent, but stale, context for a thread suspended after being redirected by
8034 // the GC (TFS Dev 10 bug # 733263).
8036 // (Note that this whole block is skipped if pThreadToSnapshot is in preemptive mode (the IF
8037 // above), as the context is unused in such a case--the EE Frame chain is used
8038 // to seed the walk instead.)
8039 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8043 if (!pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8045 LOG((LF_CORPROF, LL_INFO100, "**PROF: GetSafelyRedirectableThreadContext failure leads to CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8046 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8050 hrCurrentContextIsManaged = IsContextInManagedCode(&ctxCurrent, hostCallPreference);
8051 if (FAILED(hrCurrentContextIsManaged))
8053 // Couldn't get the info. Try again later
8054 _ASSERTE(ShouldAvoidHostCalls());
8055 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8059 if ((hrCurrentContextIsManaged == S_OK) &&
8060 (!pThreadToSnapshot->PreemptiveGCDisabledOther()))
8062 // Thread is in preemptive mode while executing managed code?! This lie is
8063 // an early warning sign that the context is bogus. Bail.
8064 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus. Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8065 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8069 Frame * pFrame = pThreadToSnapshot->GetFrame();
8070 if (pFrame != FRAME_TOP)
8072 TADDR spTargetThread = GetSP(&ctxCurrent);
8073 if (dac_cast<TADDR>(pFrame) < spTargetThread)
8075 // An Explicit EE Frame is more recent on the stack than the current
8076 // stack pointer itself? This lie is an early warning sign that the
8077 // context is bogus. Bail.
8078 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus. Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8079 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8084 // If the profiler did not specify a seed context of its own, use the current one we
8087 // Failing to seed the walk can cause us to to "miss" functions on the stack. This is
8088 // because StackWalkFrames(), when doing an unseeded stackwalk, sets the
8089 // starting regdisplay's IP/SP to 0. This, in turn causes StackWalkFramesEx
8090 // to set cf.isFrameless = (pEEJM != NULL); (which is FALSE, since we have no
8091 // jit manager, since we have no IP). Once frameless is false, we look solely to
8092 // the Frame chain for our goodies, rather than looking at the code actually
8093 // being executed by the thread. The problem with the frame chain is that some
8094 // frames (e.g., GCFrame) don't point to any functions being executed. So
8095 // StackWalkFramesEx just skips such frames and moves to the next one. That
8096 // can cause a chunk of calls to be skipped. To prevent this from happening, we
8097 // "fake" a seed by just seeding the thread with its current context. This forces
8098 // StackWalkFramesEx() to look at the IP rather than just the frame chain.
8099 if (pctxSeed == NULL)
8101 pctxSeed = &ctxCurrent;
8103 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8106 // Second, check "2) Target thread to walk is currently executing JITted / NGENd code"
8107 // To do this, we need to find the proper context to investigate. Start with
8108 // the seeded context, if available. If not, use the target thread's current context.
8109 if (pctxSeed != NULL)
8111 BOOL fSeedIsManaged;
8113 // Short cut: If we're just using the current context as the seed, we may
8114 // already have determined whether it's in managed code. If so, just use that
8115 // result rather than calculating it again
8116 if ((pctxSeed == &ctxCurrent) && SUCCEEDED(hrCurrentContextIsManaged))
8118 fSeedIsManaged = (hrCurrentContextIsManaged == S_OK);
8122 hr = IsContextInManagedCode(pctxSeed, hostCallPreference);
8125 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8128 fSeedIsManaged = (hr == S_OK);
8131 if (!fSeedIsManaged)
8133 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8140 // Sanity check: If we are doing a cross-thread walk and there is no seed context, then
8141 // we better not be in managed code, otw we do not have a Frame on the stack from which to start
8142 // walking and we may miss the leaf-most chain of managed calls due to the way StackWalkFrames
8143 // is implemented. However, there is an exception when the leaf-most EE frame of pThreadToSnapshot
8144 // is an InlinedCallFrame, which has an active call, implying pThreadToShanpshot is inside an
8145 // inlined P/Invoke. In this case, the InlinedCallFrame will be used to help start off our
8146 // stackwalk at the top of the stack.
8148 if (pThreadToSnapshot != pCurrentThread)
8150 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8154 if (pctxSeed == NULL)
8156 if (pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8158 BOOL fFailedReaderLock = FALSE;
8159 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(&ctxCurrent), hostCallPreference, &fFailedReaderLock);
8161 if (!fFailedReaderLock)
8163 // not in jitted or ngend code or inside an inlined P/Invoke (the leaf-most EE Frame is
8164 // an InlinedCallFrame with an active call)
8165 _ASSERTE(!fIsManagedCode ||
8166 (InlinedCallFrame::FrameHasActiveCall(pThreadToSnapshot->GetFrame())));
8170 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8173 // Third, verify the target thread is seeded or not in the midst of an unwind.
8174 if (pctxSeed == NULL)
8176 ThreadExceptionState* pExState = pThreadToSnapshot->GetExceptionState();
8178 // this tests to see if there is an exception in flight
8179 if (pExState->IsExceptionInProgress() && pExState->GetFlags()->UnwindHasStarted())
8181 EHClauseInfo *pCurrentEHClauseInfo = pThreadToSnapshot->GetExceptionState()->GetCurrentEHClauseInfo();
8183 // if the exception code is telling us that we have entered a managed context then all is well
8184 if (!pCurrentEHClauseInfo->IsManagedCodeEntered())
8186 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8192 // Check if the exception state is consistent. See the comment for ThreadExceptionFlag for more information.
8193 if (pThreadToSnapshot->GetExceptionState()->HasThreadExceptionFlag(ThreadExceptionState::TEF_InconsistentExceptionState))
8195 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8199 data.callback = callback;
8200 data.infoFlags = infoFlags;
8201 data.contextFlags = 0;
8202 data.clientData = clientData;
8203 #ifdef WIN64EXCEPTIONS
8204 data.sfParent.Clear();
8207 // workaround: The ForbidTypeLoad book keeping in the stackwalker is not robust against exceptions.
8208 // Unfortunately, it is hard to get it right in the stackwalker since it has to be exception
8209 // handling free (frame unwinding may never return). We restore the ForbidTypeLoad counter here
8210 // in case it got messed up by exception thrown during the stackwalk.
8211 INDEBUG(if (pCurrentThread) ulForbidTypeLoad = pCurrentThread->m_ulForbidTypeLoad;)
8214 // An AV during a profiler stackwalk is an isolated event and shouldn't bring
8215 // down the runtime. Need to place the holder here, outside of ProfilerStackWalkFramesWrapper
8216 // since ProfilerStackWalkFramesWrapper uses __try, which doesn't like objects
8217 // with destructors.
8218 AVInRuntimeImplOkayHolder AVOkay;
8220 hr = DoStackSnapshotHelper(
8223 HANDLESKIPPEDFRAMES |
8225 NOTIFY_ON_U2M_TRANSITIONS |
8226 ((pThreadToSnapshot == pCurrentThread) ?
8228 ALLOW_ASYNC_STACK_WALK | THREAD_IS_SUSPENDED) |
8229 THREAD_EXECUTING_MANAGED_CODE |
8230 PROFILER_DO_STACK_SNAPSHOT |
8231 ALLOW_INVALID_OBJECTS, // stack walk logic should not look at objects - we could be in the middle of a gc.
8235 INDEBUG(if (pCurrentThread) pCurrentThread->m_ulForbidTypeLoad = ulForbidTypeLoad;)
8238 #if defined(PLATFORM_SUPPORTS_SAFE_THREADSUSPEND)
8241 pThreadToSnapshot->ResumeThread();
8243 #endif // PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8244 if (fResetSnapshotThreadExternalCount)
8246 pThreadToSnapshot->DecExternalCountDANGEROUSProfilerOnly();
8251 #endif // !defined(FEATURE_HIJACK)
8255 //---------------------------------------------------------------------------------------
8257 // Exception swallowing wrapper around the profiler stackwalk
8260 // pThreadToSnapshot - Thread whose stack should be walked
8261 // pData - data for stack walker
8262 // flags - flags parameter to pass to StackWalkFramesEx, and StackFrameIterator
8263 // pctxSeed - Register context with which to seed the walk
8266 // HRESULT indicating success or failure.
8268 HRESULT ProfToEEInterfaceImpl::DoStackSnapshotHelper(Thread * pThreadToSnapshot,
8269 PROFILER_STACK_WALK_DATA * pData,
8273 STATIC_CONTRACT_NOTHROW;
8275 // We want to catch and swallow AVs here. For example, if the profiler gives
8276 // us a bogus seed context (this happens), we could AV when inspecting memory pointed to
8277 // by the (bogus) EBP register.
8279 // EX_TRY/EX_CATCH does a lot of extras that we do not need and that can go wrong for us.
8280 // E.g. It asserts in debug build for AVs in mscorwks or it synthetizes an object for the exception.
8281 // We use a plain PAL_TRY/PAL_EXCEPT since it is all we need.
8284 Thread * pThreadToSnapshot;
8285 PROFILER_STACK_WALK_DATA * pData;
8287 ProfToEEInterfaceImpl * pProfToEE;
8289 BOOL fResetProfilerFilterContext;
8293 param.hr = E_UNEXPECTED;
8294 param.pThreadToSnapshot = pThreadToSnapshot;
8295 param.pData = pData;
8296 param.flags = flags;
8297 param.pProfToEE = this;
8298 param.pctxSeed = pctxSeed;
8299 param.fResetProfilerFilterContext = FALSE;
8301 PAL_TRY(Param *, pParam, ¶m)
8303 if ((pParam->pData->infoFlags & COR_PRF_SNAPSHOT_X86_OPTIMIZED) != 0)
8305 #ifndef _TARGET_X86_
8306 // If check in the begining of DoStackSnapshot (to return E_INVALIDARG) should
8307 // make this unreachable
8308 _ASSERTE(!"COR_PRF_SNAPSHOT_X86_OPTIMIZED on non-X86 should be unreachable!");
8310 // New, simple EBP walker
8311 pParam->hr = pParam->pProfToEE->ProfilerEbpWalker(
8312 pParam->pThreadToSnapshot,
8314 pParam->pData->callback,
8315 pParam->pData->clientData);
8316 #endif // _TARGET_X86_
8320 // We're now fairly confident the stackwalk should be ok, so set
8321 // the context seed, if one was provided or cooked up.
8322 if (pParam->pctxSeed != NULL)
8324 pParam->pThreadToSnapshot->SetProfilerFilterContext(pParam->pctxSeed);
8325 pParam->fResetProfilerFilterContext = TRUE;
8328 // Whidbey-style walker, uses StackWalkFramesEx
8329 pParam->hr = pParam->pProfToEE->ProfilerStackWalkFramesWrapper(
8330 pParam->pThreadToSnapshot,
8335 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8337 param.hr = E_UNEXPECTED;
8341 // Undo the context seeding & thread suspend we did (if any)
8342 // to ensure that the thread we walked stayed suspended
8343 if (param.fResetProfilerFilterContext)
8345 pThreadToSnapshot->SetProfilerFilterContext(NULL);
8352 HRESULT ProfToEEInterfaceImpl::GetGenerationBounds(ULONG cObjectRanges,
8353 ULONG *pcObjectRanges,
8354 COR_PRF_GC_GENERATION_RANGE ranges[])
8368 EE_THREAD_NOT_REQUIRED;
8374 PRECONDITION(CheckPointer(pcObjectRanges));
8375 PRECONDITION(cObjectRanges <= 0 || ranges != NULL);
8376 PRECONDITION(s_generationTableLock >= 0);
8380 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8383 "**PROF: GetGenerationBounds.\n"));
8385 // Announce we are using the generation table now
8386 CounterHolder genTableLock(&s_generationTableLock);
8388 GenerationTable *generationTable = s_currentGenerationTable;
8390 if (generationTable == NULL)
8395 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8397 GenerationDesc *genDescTable = generationTable->genDescTable;
8398 ULONG count = min(generationTable->count, cObjectRanges);
8399 for (ULONG i = 0; i < count; i++)
8401 ranges[i].generation = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8402 ranges[i].rangeStart = (ObjectID)genDescTable[i].rangeStart;
8403 ranges[i].rangeLength = genDescTable[i].rangeEnd - genDescTable[i].rangeStart;
8404 ranges[i].rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8407 *pcObjectRanges = generationTable->count;
8413 HRESULT ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo(COR_PRF_EX_CLAUSE_INFO * pinfo)
8430 PRECONDITION(CheckPointer(pinfo));
8434 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
8436 "**PROF: GetNotifiedExceptionClauseInfo.\n"));
8440 ThreadExceptionState* pExState = NULL;
8441 EHClauseInfo* pCurrentEHClauseInfo = NULL;
8443 // notification requires that we are on a managed thread with an exception in flight
8444 Thread *pThread = GetThread();
8446 // If pThread is null, then the thread has never run managed code
8447 if (pThread == NULL)
8449 hr = CORPROF_E_NOT_MANAGED_THREAD;
8453 pExState = pThread->GetExceptionState();
8454 if (!pExState->IsExceptionInProgress())
8456 // no exception is in flight -- successful failure
8461 pCurrentEHClauseInfo = pExState->GetCurrentEHClauseInfo();
8462 if (pCurrentEHClauseInfo->GetClauseType() == COR_PRF_CLAUSE_NONE)
8464 // no exception is in flight -- successful failure
8469 pinfo->clauseType = pCurrentEHClauseInfo->GetClauseType();
8470 pinfo->programCounter = pCurrentEHClauseInfo->GetIPForEHClause();
8471 pinfo->framePointer = pCurrentEHClauseInfo->GetFramePointerForEHClause();
8472 pinfo->shadowStackPointer = 0;
8477 memset(pinfo, 0, sizeof(*pinfo));
8482 HRESULT ProfToEEInterfaceImpl::GetObjectGeneration(ObjectID objectId,
8483 COR_PRF_GC_GENERATION_RANGE *range)
8497 EE_THREAD_NOT_REQUIRED;
8503 PRECONDITION(objectId != NULL);
8504 PRECONDITION(CheckPointer(range));
8505 PRECONDITION(s_generationTableLock >= 0);
8509 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8512 "**PROF: GetObjectGeneration 0x%p.\n",
8515 BEGIN_GETTHREAD_ALLOWED;
8516 _ASSERTE((GetThread() == NULL) || (GetThread()->PreemptiveGCDisabled()));
8517 END_GETTHREAD_ALLOWED;
8519 // Announce we are using the generation table now
8520 CounterHolder genTableLock(&s_generationTableLock);
8522 GenerationTable *generationTable = s_currentGenerationTable;
8524 if (generationTable == NULL)
8529 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8531 GenerationDesc *genDescTable = generationTable->genDescTable;
8532 ULONG count = generationTable->count;
8533 for (ULONG i = 0; i < count; i++)
8535 if (genDescTable[i].rangeStart <= (BYTE *)objectId && (BYTE *)objectId < genDescTable[i].rangeEndReserved)
8537 range->generation = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8538 range->rangeStart = (ObjectID)genDescTable[i].rangeStart;
8539 range->rangeLength = genDescTable[i].rangeEnd - genDescTable[i].rangeStart;
8540 range->rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8549 HRESULT ProfToEEInterfaceImpl::GetReJITIDs(
8550 FunctionID functionId, // in
8551 ULONG cReJitIds, // in
8552 ULONG * pcReJitIds, // out
8553 ReJITID reJitIds[]) // out
8560 // taking a lock causes a GC
8566 // The rejit tables use a lock
8570 PRECONDITION(CheckPointer(pcReJitIds, NULL_OK));
8571 PRECONDITION(CheckPointer(reJitIds, NULL_OK));
8576 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8577 kP2EEAllowableAfterAttach,
8580 "**PROF: GetReJITIDs 0x%p.\n",
8583 if (functionId == 0)
8585 return E_INVALIDARG;
8588 if ((cReJitIds == 0) || (pcReJitIds == NULL) || (reJitIds == NULL))
8590 return E_INVALIDARG;
8593 MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
8595 return ReJitManager::GetReJITIDs(pMD, cReJitIds, pcReJitIds, reJitIds);
8598 HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG cFunctions, // in
8599 ModuleID moduleIds[], // in
8600 mdMethodDef methodIds[]) // in
8607 // When we suspend the runtime we drop into premptive mode
8613 // We need to suspend the runtime, this takes a lot of locks!
8617 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8618 PRECONDITION(CheckPointer(methodIds, NULL_OK));
8622 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8623 kP2EETriggers | kP2EEAllowableAfterAttach,
8626 "**PROF: RequestReJIT.\n"));
8628 if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
8630 return CORPROF_E_CALLBACK4_REQUIRED;
8633 if (!CORProfilerEnableRejit())
8635 return CORPROF_E_REJIT_NOT_ENABLED;
8638 // Request at least 1 method to reJIT!
8639 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8641 return E_INVALIDARG;
8644 // Remember the profiler is doing this, as that means we must never detach it!
8645 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8648 return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds);
8651 HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG cFunctions, // in
8652 ModuleID moduleIds[], // in
8653 mdMethodDef methodIds[], // in
8654 HRESULT rgHrStatuses[]) // out
8661 // The rejit manager requires a lock to iterate through methods to revert, and
8662 // taking the lock can drop us into preemptive mode.
8668 // The rejit manager requires a lock to iterate through methods to revert
8672 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8673 PRECONDITION(CheckPointer(methodIds, NULL_OK));
8674 PRECONDITION(CheckPointer(rgHrStatuses, NULL_OK));
8678 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8679 kP2EEAllowableAfterAttach | kP2EETriggers,
8682 "**PROF: RequestRevert.\n"));
8684 if (!CORProfilerEnableRejit())
8686 return CORPROF_E_REJIT_NOT_ENABLED;
8689 // Request at least 1 method to revert!
8690 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8692 return E_INVALIDARG;
8695 // Remember the profiler is doing this, as that means we must never detach it!
8696 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8698 // Initialize the status array
8699 if (rgHrStatuses != NULL)
8701 memset(rgHrStatuses, 0, sizeof(HRESULT) * cFunctions);
8702 _ASSERTE(S_OK == rgHrStatuses[0]);
8706 return ReJitManager::RequestRevert(cFunctions, moduleIds, methodIds, rgHrStatuses);
8710 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions(ICorProfilerFunctionEnum ** ppEnum)
8723 // If we're in preemptive mode we need to take a read lock to safely walk
8724 // the JIT data structures.
8728 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8733 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8736 "**PROF: EnumJITedFunctions.\n"));
8740 return E_INVALIDARG;
8745 NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8746 if (pJitEnum == NULL)
8748 return E_OUTOFMEMORY;
8751 if (!pJitEnum->Init())
8753 return E_OUTOFMEMORY;
8756 // Ownership transferred to [out] param. Caller must Release() when done with this.
8757 *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8762 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions2(ICorProfilerFunctionEnum ** ppEnum)
8769 // Gathering rejitids requires taking a lock and that lock might switch to
8770 // preemptimve mode...
8776 // If we're in preemptive mode we need to take a read lock to safely walk
8777 // the JIT data structures.
8778 // Gathering RejitIDs also takes a lock.
8782 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8787 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8788 kP2EEAllowableAfterAttach | kP2EETriggers,
8791 "**PROF: EnumJITedFunctions.\n"));
8795 return E_INVALIDARG;
8800 NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8801 if (pJitEnum == NULL)
8803 return E_OUTOFMEMORY;
8806 if (!pJitEnum->Init(TRUE /* fWithReJITIDs */))
8808 // If it fails, it's because of OOM.
8809 return E_OUTOFMEMORY;
8812 // Ownership transferred to [out] param. Caller must Release() when done with this.
8813 *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8818 HRESULT ProfToEEInterfaceImpl::EnumModules(ICorProfilerModuleEnum ** ppEnum)
8825 // This method populates the enumerator, which requires iterating over
8826 // AppDomains, which adds, then releases, a reference on each AppDomain iterated.
8827 // This causes locking, and can cause triggering if the AppDomain gets destroyed
8828 // as a result of the release. (See code:AppDomainIterator::Next and its call to
8829 // code:AppDomain::Release.)
8835 // (See comment above GC_TRIGGERS.)
8839 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8844 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8845 kP2EEAllowableAfterAttach | kP2EETriggers,
8848 "**PROF: EnumModules.\n"));
8854 return E_INVALIDARG;
8859 // ProfilerModuleEnum uese AppDomainIterator, which cannot be called while the current thead
8860 // is holding the ThreadStore lock.
8861 if (ThreadStore::HoldingThreadStore())
8863 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
8866 NewHolder<ProfilerModuleEnum> pModuleEnum(new (nothrow) ProfilerModuleEnum);
8867 if (pModuleEnum == NULL)
8869 return E_OUTOFMEMORY;
8872 hr = pModuleEnum->Init();
8878 // Ownership transferred to [out] param. Caller must Release() when done with this.
8879 *ppEnum = (ICorProfilerModuleEnum *) pModuleEnum.Extract();
8884 HRESULT ProfToEEInterfaceImpl::GetRuntimeInformation(USHORT * pClrInstanceId,
8885 COR_PRF_RUNTIME_TYPE * pRuntimeType,
8886 USHORT * pMajorVersion,
8887 USHORT * pMinorVersion,
8888 USHORT * pBuildNumber,
8889 USHORT * pQFEVersion,
8890 ULONG cchVersionString,
8891 ULONG * pcchVersionString,
8892 __out_ecount_part_opt(cchVersionString, *pcchVersionString) WCHAR szVersionString[])
8906 EE_THREAD_NOT_REQUIRED;
8914 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8917 "**PROF: GetRuntimeInformation.\n"));
8919 if ((szVersionString != NULL) && (pcchVersionString == NULL))
8921 return E_INVALIDARG;
8924 if (pcchVersionString != NULL)
8926 HRESULT hr = GetCORVersionInternal(szVersionString, (DWORD)cchVersionString, (DWORD *)pcchVersionString);
8931 if (pClrInstanceId != NULL)
8932 *pClrInstanceId = static_cast<USHORT>(GetClrInstanceId());
8934 if (pRuntimeType != NULL)
8936 *pRuntimeType = COR_PRF_CORE_CLR;
8939 if (pMajorVersion != NULL)
8940 *pMajorVersion = CLR_MAJOR_VERSION;
8942 if (pMinorVersion != NULL)
8943 *pMinorVersion = CLR_MINOR_VERSION;
8945 if (pBuildNumber != NULL)
8946 *pBuildNumber = CLR_BUILD_VERSION;
8948 if (pQFEVersion != NULL)
8949 *pQFEVersion = CLR_BUILD_VERSION_QFE;
8955 HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds)
8962 // Crst is used in ProfilingAPIDetach::RequestProfilerDetach so GC may be triggered
8969 EE_THREAD_NOT_REQUIRED;
8971 // Crst is used in ProfilingAPIDetach::RequestProfilerDetach
8976 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8977 kP2EEAllowableAfterAttach | kP2EETriggers,
8980 "**PROF: RequestProfilerDetach.\n"));
8982 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
8983 return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds);
8984 #else // FEATURE_PROFAPI_ATTACH_DETACH
8986 #endif // FEATURE_PROFAPI_ATTACH_DETACH
8989 typedef struct _COR_PRF_ELT_INFO_INTERNAL
8991 // Point to a platform dependent structure ASM helper push on the stack
8992 void * platformSpecificHandle;
8994 // startAddress of COR_PRF_FUNCTION_ARGUMENT_RANGE structure needs to point
8995 // TO the argument value, not BE the argument value. So, when the argument
8996 // is this, we need to point TO this. Because of the calling sequence change
8997 // in ELT3, we need to reserve the pointer here instead of using one of our
9001 // Reserve space for output parameter COR_PRF_FRAME_INFO of
9002 // GetFunctionXXXX3Info functions
9003 COR_PRF_FRAME_INFO_INTERNAL frameInfo;
9005 } COR_PRF_ELT_INFO_INTERNAL;
9007 //---------------------------------------------------------------------------------------
9009 // ProfilingGetFunctionEnter3Info provides frame information and argument infomation of
9010 // the function ELT callback is inspecting. It is called either by the profiler or the
9011 // C helper function.
9014 // * functionId - [in] FunctionId of the function being inspected by ELT3
9015 // * eltInfo - [in] The opaque pointer FunctionEnter3WithInfo callback passed to the profiler
9016 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9018 // * pcbArgumentInfo - [in, out] Pointer to ULONG that specifies the size of structure
9019 // pointed by pArgumentInfo
9020 // * pArgumentInfo - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_INFO structure the profiler
9021 // must preserve enough space for the function it is inspecting
9024 // HRESULT indicating success or failure.
9027 HRESULT ProfilingGetFunctionEnter3Info(FunctionID functionId, // in
9028 COR_PRF_ELT_INFO eltInfo, // in
9029 COR_PRF_FRAME_INFO * pFrameInfo, // out
9030 ULONG * pcbArgumentInfo, // in, out
9031 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo) // out
9044 // ProfileArgIterator::ProfileArgIterator may take locks
9051 if ((functionId == NULL) || (eltInfo == NULL))
9053 return E_INVALIDARG;
9056 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9057 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9059 // The loader won't trigger a GC or throw for already loaded argument types.
9060 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9063 // Find the method this is referring to, so we can get the signature
9065 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9066 MetaSig metaSig(pMethodDesc);
9068 NewHolder<ProfileArgIterator> pProfileArgIterator;
9071 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9074 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9076 if (pProfileArgIterator == NULL)
9078 return E_UNEXPECTED;
9082 if (CORProfilerFrameInfoEnabled())
9084 if (pFrameInfo == NULL)
9086 return E_INVALIDARG;
9090 // Setup the COR_PRF_FRAME_INFO structure first.
9092 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9094 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9095 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9096 pCorPrfFrameInfo->funcID = functionId;
9097 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9098 pCorPrfFrameInfo->extraArg = pProfileArgIterator->GetHiddenArgValue();
9099 pCorPrfFrameInfo->thisArg = pProfileArgIterator->GetThis();
9101 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9105 // Do argument processing if desired.
9107 if (CORProfilerFunctionArgsEnabled())
9109 if (pcbArgumentInfo == NULL)
9111 return E_INVALIDARG;
9114 if ((*pcbArgumentInfo != 0) && (pArgumentInfo == NULL))
9116 return E_INVALIDARG;
9119 ULONG32 count = pProfileArgIterator->GetNumArgs();
9121 if (metaSig.HasThis())
9126 ULONG ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + (count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE));
9128 if (*pcbArgumentInfo < ulArgInfoSize)
9130 *pcbArgumentInfo = ulArgInfoSize;
9131 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
9134 _ASSERTE(pArgumentInfo != NULL);
9136 pArgumentInfo->numRanges = count;
9137 pArgumentInfo->totalArgumentSize = 0;
9141 if (metaSig.HasThis())
9143 pELTInfo->pThis = pProfileArgIterator->GetThis();
9144 pArgumentInfo->ranges[count].startAddress = (UINT_PTR) (&(pELTInfo->pThis));
9146 UINT length = sizeof(pELTInfo->pThis);
9147 pArgumentInfo->ranges[count].length = length;
9148 pArgumentInfo->totalArgumentSize += length;
9152 while (count < pArgumentInfo->numRanges)
9154 pArgumentInfo->ranges[count].startAddress = (UINT_PTR)(pProfileArgIterator->GetNextArgAddr());
9156 UINT length = pProfileArgIterator->GetArgSize();
9157 pArgumentInfo->ranges[count].length = length;
9158 pArgumentInfo->totalArgumentSize += length;
9168 HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId, // in
9169 COR_PRF_ELT_INFO eltInfo, // in
9170 COR_PRF_FRAME_INFO * pFrameInfo, // out
9171 ULONG * pcbArgumentInfo, // in, out
9172 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo) // out
9185 // ProfilingGetFunctionEnter3Info may take locks
9192 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9194 "**PROF: GetFunctionEnter3Info.\n"));
9196 _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL);
9198 if (!CORProfilerELT3SlowPathEnterEnabled())
9200 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9203 return ProfilingGetFunctionEnter3Info(functionId, eltInfo, pFrameInfo, pcbArgumentInfo, pArgumentInfo);
9206 //---------------------------------------------------------------------------------------
9208 // ProfilingGetFunctionLeave3Info provides frame information and return value infomation
9209 // of the function ELT callback is inspecting. It is called either by the profiler or the
9210 // C helper function.
9213 // * functionId - [in] FunctionId of the function being inspected by ELT3
9214 // * eltInfo - [in] The opaque pointer FunctionLeave3WithInfo callback passed to the profiler
9215 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9217 // * pRetvalRange - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_RANGE to store return value
9220 // HRESULT indicating success or failure.
9223 HRESULT ProfilingGetFunctionLeave3Info(FunctionID functionId, // in
9224 COR_PRF_ELT_INFO eltInfo, // in
9225 COR_PRF_FRAME_INFO * pFrameInfo, // out
9226 COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange) // out
9239 // ProfileArgIterator::ProfileArgIterator may take locks
9245 if ((pFrameInfo == NULL) || (eltInfo == NULL))
9247 return E_INVALIDARG;
9250 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9251 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9253 // The loader won't trigger a GC or throw for already loaded argument types.
9254 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9257 // Find the method this is referring to, so we can get the signature
9259 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9260 MetaSig metaSig(pMethodDesc);
9262 NewHolder<ProfileArgIterator> pProfileArgIterator;
9265 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9268 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9270 if (pProfileArgIterator == NULL)
9272 return E_UNEXPECTED;
9276 if (CORProfilerFrameInfoEnabled())
9278 if (pFrameInfo == NULL)
9280 return E_INVALIDARG;
9283 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9286 // Setup the COR_PRF_FRAME_INFO structure first.
9288 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9289 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9290 pCorPrfFrameInfo->funcID = functionId;
9291 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9293 // Upon entering Leave hook, the register assigned to store this pointer on function calls may
9294 // already be reused and is likely not to contain this pointer.
9295 pCorPrfFrameInfo->extraArg = NULL;
9296 pCorPrfFrameInfo->thisArg = NULL;
9298 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9302 // Do argument processing if desired.
9304 if (CORProfilerFunctionReturnValueEnabled())
9306 if (pRetvalRange == NULL)
9308 return E_INVALIDARG;
9311 if (!metaSig.IsReturnTypeVoid())
9313 pRetvalRange->length = metaSig.GetReturnTypeSize();
9314 pRetvalRange->startAddress = (UINT_PTR)pProfileArgIterator->GetReturnBufferAddr();
9318 pRetvalRange->length = 0;
9319 pRetvalRange->startAddress = 0;
9327 HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId, // in
9328 COR_PRF_ELT_INFO eltInfo, // in
9329 COR_PRF_FRAME_INFO * pFrameInfo, // out
9330 COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange) // out
9343 // ProfilingGetFunctionLeave3Info may take locks
9350 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9352 "**PROF: GetFunctionLeave3Info.\n"));
9354 _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL);
9356 if (!CORProfilerELT3SlowPathLeaveEnabled())
9358 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9361 return ProfilingGetFunctionLeave3Info(functionId, eltInfo, pFrameInfo, pRetvalRange);
9364 //---------------------------------------------------------------------------------------
9366 // ProfilingGetFunctionTailcall3Info provides frame information of the function ELT callback
9367 // is inspecting. It is called either by the profiler or the C helper function.
9370 // * functionId - [in] FunctionId of the function being inspected by ELT3
9371 // * eltInfo - [in] The opaque pointer FunctionTailcall3WithInfo callback passed to the
9373 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9377 // HRESULT indicating success or failure.
9380 HRESULT ProfilingGetFunctionTailcall3Info(FunctionID functionId, // in
9381 COR_PRF_ELT_INFO eltInfo, // in
9382 COR_PRF_FRAME_INFO * pFrameInfo) // out
9395 // ProfileArgIterator::ProfileArgIterator may take locks
9402 if ((functionId == NULL) || (eltInfo == NULL) || (pFrameInfo == NULL))
9404 return E_INVALIDARG;
9407 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9408 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9410 // The loader won't trigger a GC or throw for already loaded argument types.
9411 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9414 // Find the method this is referring to, so we can get the signature
9416 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9417 MetaSig metaSig(pMethodDesc);
9419 NewHolder<ProfileArgIterator> pProfileArgIterator;
9422 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9425 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9427 if (pProfileArgIterator == NULL)
9429 return E_UNEXPECTED;
9433 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9436 // Setup the COR_PRF_FRAME_INFO structure first.
9438 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9439 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9440 pCorPrfFrameInfo->funcID = functionId;
9441 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9443 // Tailcall is designed to report the caller, not the callee. But the taillcall hook is invoked
9444 // with registers containing parameters passed to the callee before calling into the callee.
9445 // This pointer we get here is for the callee. Because of the constraints imposed on tailcall
9446 // optimization, this pointer passed to the callee accidentally happens to be the same this pointer
9447 // passed to the caller.
9449 // It is a fragile coincidence we should not depend on because JIT is free to change the
9450 // implementation details in the future.
9451 pCorPrfFrameInfo->extraArg = NULL;
9452 pCorPrfFrameInfo->thisArg = NULL;
9454 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9460 HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId, // in
9461 COR_PRF_ELT_INFO eltInfo, // in
9462 COR_PRF_FRAME_INFO * pFrameInfo) // out
9475 // ProfilingGetFunctionTailcall3Info may take locks
9482 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9484 "**PROF: GetFunctionTailcall3Info.\n"));
9486 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL);
9488 if (!CORProfilerELT3SlowPathTailcallEnabled())
9490 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9493 return ProfilingGetFunctionTailcall3Info(functionId, eltInfo, pFrameInfo);
9496 HRESULT ProfToEEInterfaceImpl::EnumThreads(
9497 /* out */ ICorProfilerThreadEnum ** ppEnum)
9511 // Need to acquire the thread store lock
9515 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
9520 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9521 kP2EEAllowableAfterAttach,
9524 "**PROF: EnumThreads.\n"));
9530 return E_INVALIDARG;
9535 NewHolder<ProfilerThreadEnum> pThreadEnum(new (nothrow) ProfilerThreadEnum);
9536 if (pThreadEnum == NULL)
9538 return E_OUTOFMEMORY;
9541 hr = pThreadEnum->Init();
9547 // Ownership transferred to [out] param. Caller must Release() when done with this.
9548 *ppEnum = (ICorProfilerThreadEnum *) pThreadEnum.Extract();
9553 // This function needs to be called on any thread before making any ICorProfilerInfo* calls and must be
9554 // made before any thread is suspended by this profiler.
9555 // As you might have already figured out, this is done to avoid deadlocks situation when
9556 // the suspended thread holds on the loader lock / heap lock while the current thread is trying to obtain
9558 HRESULT ProfToEEInterfaceImpl::InitializeCurrentThread()
9572 // May take thread store lock and OS APIs may also take locks
9579 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9580 kP2EEAllowableAfterAttach,
9583 "**PROF: InitializeCurrentThread.\n"));
9589 CExecutionEngine::SetupTLSForThread(GetThread());
9591 EX_CATCH_HRESULT(hr);
9599 struct InternalProfilerModuleEnum : public ProfilerModuleEnum
9601 CDynArray<ModuleID> *GetRawElementsArray()
9607 HRESULT ProfToEEInterfaceImpl::EnumNgenModuleMethodsInliningThisMethod(
9608 ModuleID inlinersModuleId,
9609 ModuleID inlineeModuleId,
9610 mdMethodDef inlineeMethodId,
9611 BOOL *incompleteData,
9612 ICorProfilerMethodEnum** ppEnum)
9620 PRECONDITION(CheckPointer(ppEnum));
9624 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: EnumNgenModuleMethodsInliningThisMethod.\n"));
9628 return E_INVALIDARG;
9633 Module *inlineeOwnerModule = reinterpret_cast<Module *>(inlineeModuleId);
9634 if (inlineeOwnerModule == NULL)
9636 return E_INVALIDARG;
9638 if (inlineeOwnerModule->IsBeingUnloaded())
9640 return CORPROF_E_DATAINCOMPLETE;
9643 Module *inlinersModule = reinterpret_cast<Module *>(inlinersModuleId);
9644 if (inlinersModule == NULL)
9646 return E_INVALIDARG;
9648 if(inlinersModule->IsBeingUnloaded())
9650 return CORPROF_E_DATAINCOMPLETE;
9653 if (!inlinersModule->HasInlineTrackingMap())
9655 return CORPROF_E_DATAINCOMPLETE;
9658 CDynArray<COR_PRF_METHOD> results;
9659 const COUNT_T staticBufferSize = 10;
9660 MethodInModule staticBuffer[staticBufferSize];
9661 NewArrayHolder<MethodInModule> dynamicBuffer;
9662 MethodInModule *methodsBuffer = staticBuffer;
9665 // Trying to use static buffer
9666 COUNT_T methodsAvailable = inlinersModule->GetInliners(inlineeOwnerModule, inlineeMethodId, staticBufferSize, staticBuffer, incompleteData);
9668 // If static buffer is not enough, allocate an array.
9669 if (methodsAvailable > staticBufferSize)
9671 DWORD dynamicBufferSize = methodsAvailable;
9672 dynamicBuffer = methodsBuffer = new MethodInModule[dynamicBufferSize];
9673 methodsAvailable = inlinersModule->GetInliners(inlineeOwnerModule, inlineeMethodId, dynamicBufferSize, dynamicBuffer, incompleteData);
9674 if (methodsAvailable > dynamicBufferSize)
9676 _ASSERTE(!"Ngen image inlining info changed, this shouldn't be possible.");
9677 methodsAvailable = dynamicBufferSize;
9681 //Go through all inliners found in the inlinersModule and prepare them to export via results.
9682 results.AllocateBlockThrowing(methodsAvailable);
9683 for (COUNT_T j = 0; j < methodsAvailable; j++)
9685 COR_PRF_METHOD *newPrfMethod = &results[j];
9686 newPrfMethod->moduleId = reinterpret_cast<ModuleID>(methodsBuffer[j].m_module);
9687 newPrfMethod->methodId = methodsBuffer[j].m_methodDef;
9689 *ppEnum = new ProfilerMethodEnum(&results);
9691 EX_CATCH_HRESULT(hr);
9696 HRESULT ProfToEEInterfaceImpl::GetInMemorySymbolsLength(
9698 DWORD* pCountSymbolBytes)
9710 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9711 kP2EEAllowableAfterAttach,
9714 "**PROF: GetInMemorySymbolsLength.\n"));
9717 if (pCountSymbolBytes == NULL)
9719 return E_INVALIDARG;
9721 *pCountSymbolBytes = 0;
9723 Module* pModule = reinterpret_cast< Module* >(moduleId);
9724 if (pModule == NULL)
9726 return E_INVALIDARG;
9728 if (pModule->IsBeingUnloaded())
9730 return CORPROF_E_DATAINCOMPLETE;
9733 //This method would work fine on reflection.emit, but there would be no way to know
9734 //if some other thread was changing the size of the symbols before this method returned.
9735 //Adding events or locks to detect/prevent changes would make the scenario workable
9736 if (pModule->IsReflection())
9738 return COR_PRF_MODULE_DYNAMIC;
9741 CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9742 if (pStream == NULL)
9747 STATSTG SizeData = { 0 };
9748 hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9753 if (SizeData.cbSize.u.HighPart > 0)
9755 return COR_E_OVERFLOW;
9757 *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
9762 HRESULT ProfToEEInterfaceImpl::ReadInMemorySymbols(
9764 DWORD symbolsReadOffset,
9766 DWORD countSymbolBytes,
9767 DWORD* pCountSymbolBytesRead)
9777 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9778 kP2EEAllowableAfterAttach,
9781 "**PROF: ReadInMemorySymbols.\n"));
9784 if (pSymbolBytes == NULL)
9786 return E_INVALIDARG;
9788 if (pCountSymbolBytesRead == NULL)
9790 return E_INVALIDARG;
9792 *pCountSymbolBytesRead = 0;
9794 Module* pModule = reinterpret_cast< Module* >(moduleId);
9795 if (pModule == NULL)
9797 return E_INVALIDARG;
9799 if (pModule->IsBeingUnloaded())
9801 return CORPROF_E_DATAINCOMPLETE;
9804 //This method would work fine on reflection.emit, but there would be no way to know
9805 //if some other thread was changing the size of the symbols before this method returned.
9806 //Adding events or locks to detect/prevent changes would make the scenario workable
9807 if (pModule->IsReflection())
9809 return COR_PRF_MODULE_DYNAMIC;
9812 CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9813 if (pStream == NULL)
9815 return E_INVALIDARG;
9818 STATSTG SizeData = { 0 };
9819 hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9824 if (SizeData.cbSize.u.HighPart > 0)
9826 return COR_E_OVERFLOW;
9828 DWORD streamSize = SizeData.cbSize.u.LowPart;
9829 if (symbolsReadOffset >= streamSize)
9831 return E_INVALIDARG;
9834 *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
9835 memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
9840 HRESULT ProfToEEInterfaceImpl::ApplyMetaData(
9851 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach | kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: ApplyMetaData.\n"));
9853 if (moduleId == NULL)
9855 return E_INVALIDARG;
9861 Module *pModule = (Module *)moduleId;
9862 _ASSERTE(pModule != NULL);
9863 if (pModule->IsBeingUnloaded())
9865 hr = CORPROF_E_DATAINCOMPLETE;
9869 pModule->ApplyMetaData();
9872 EX_CATCH_HRESULT(hr);
9876 //---------------------------------------------------------------------------------------
9878 // Simple wrapper around EEToProfInterfaceImpl::ManagedToUnmanagedTransition. This
9879 // can be called by C++ code and directly by generated stubs.
9882 // pMD - MethodDesc for the managed function involved in the transition
9883 // reason - Passed on to profiler to indicate why the transition is occurring
9886 void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD,
9887 COR_PRF_TRANSITION_REASON reason)
9897 // This function is called within the runtime, not directly from managed code.
9898 // Also, the only case MD is NULL is the calli pinvoke case, and we still
9899 // want to notify the profiler in that case.
9901 // Do not notify the profiler about QCalls
9902 if (pMD == NULL || !pMD->IsQCall())
9904 BEGIN_PIN_PROFILER(CORProfilerPresent());
9905 g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD),
9911 //---------------------------------------------------------------------------------------
9913 // Simple wrapper around EEToProfInterfaceImpl::UnmanagedToManagedTransition. This
9914 // can be called by C++ code and directly by generated stubs.
9917 // pMD - MethodDesc for the managed function involved in the transition
9918 // reason - Passed on to profiler to indicate why the transition is occurring
9921 void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD,
9922 COR_PRF_TRANSITION_REASON reason)
9932 // This function is called within the runtime, not directly from managed code.
9933 // Also, the only case MD is NULL is the calli pinvoke case, and we still
9934 // want to notify the profiler in that case.
9936 // Do not notify the profiler about QCalls
9937 if (pMD == NULL || !pMD->IsQCall())
9939 BEGIN_PIN_PROFILER(CORProfilerPresent());
9940 g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD),
9948 #endif // PROFILING_SUPPORTED
9951 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemoting)
9955 #ifdef PROFILING_SUPPORTED
9956 FC_RETURN_BOOL(CORProfilerTrackRemoting());
9957 #else // !PROFILING_SUPPORTED
9958 FC_RETURN_BOOL(FALSE);
9959 #endif // !PROFILING_SUPPORTED
9963 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingCookie)
9967 #ifdef PROFILING_SUPPORTED
9968 FC_RETURN_BOOL(CORProfilerTrackRemotingCookie());
9969 #else // !PROFILING_SUPPORTED
9970 FC_RETURN_BOOL(FALSE);
9971 #endif // !PROFILING_SUPPORTED
9975 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingAsync)
9979 #ifdef PROFILING_SUPPORTED
9980 FC_RETURN_BOOL(CORProfilerTrackRemotingAsync());
9981 #else // !PROFILING_SUPPORTED
9982 FC_RETURN_BOOL(FALSE);
9983 #endif // !PROFILING_SUPPORTED
9987 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingClientSendingMessage, GUID *pId, CLR_BOOL fIsAsync)
9991 #ifdef PROFILING_SUPPORTED
9992 // Need to erect a GC frame so that GCs can occur without a problem
9993 // within the profiler code.
9995 // Note that we don't need to worry about pId moving around since
9996 // it is a value class declared on the stack and so GC doesn't
9999 _ASSERTE (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pId)); // should be on the stack, not in the heap
10000 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10003 BEGIN_PIN_PROFILER(CORProfilerPresent());
10005 if (CORProfilerTrackRemotingCookie())
10007 g_profControlBlock.pProfInterface->GetGUID(pId);
10008 _ASSERTE(pId->Data1);
10010 g_profControlBlock.pProfInterface->RemotingClientSendingMessage(pId, fIsAsync);
10014 g_profControlBlock.pProfInterface->RemotingClientSendingMessage(NULL, fIsAsync);
10016 END_PIN_PROFILER();
10018 HELPER_METHOD_FRAME_END_POLL();
10019 #endif // PROFILING_SUPPORTED
10024 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingClientReceivingReply, GUID id, CLR_BOOL fIsAsync)
10028 #ifdef PROFILING_SUPPORTED
10029 // Need to erect a GC frame so that GCs can occur without a problem
10030 // within the profiler code.
10032 // Note that we don't need to worry about pId moving around since
10033 // it is a value class declared on the stack and so GC doesn't
10036 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10040 BEGIN_PIN_PROFILER(CORProfilerPresent());
10042 if (CORProfilerTrackRemotingCookie())
10044 g_profControlBlock.pProfInterface->RemotingClientReceivingReply(&id, fIsAsync);
10048 g_profControlBlock.pProfInterface->RemotingClientReceivingReply(NULL, fIsAsync);
10050 END_PIN_PROFILER();
10053 HELPER_METHOD_FRAME_END_POLL();
10054 #endif // PROFILING_SUPPORTED
10059 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingServerReceivingMessage, GUID id, CLR_BOOL fIsAsync)
10063 #ifdef PROFILING_SUPPORTED
10064 // Need to erect a GC frame so that GCs can occur without a problem
10065 // within the profiler code.
10067 // Note that we don't need to worry about pId moving around since
10068 // it is a value class declared on the stack and so GC doesn't
10071 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10074 BEGIN_PIN_PROFILER(CORProfilerPresent());
10076 if (CORProfilerTrackRemotingCookie())
10078 g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(&id, fIsAsync);
10082 g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(NULL, fIsAsync);
10084 END_PIN_PROFILER();
10087 HELPER_METHOD_FRAME_END_POLL();
10088 #endif // PROFILING_SUPPORTED
10092 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingServerSendingReply, GUID *pId, CLR_BOOL fIsAsync)
10096 #ifdef PROFILING_SUPPORTED
10097 // Need to erect a GC frame so that GCs can occur without a problem
10098 // within the profiler code.
10100 // Note that we don't need to worry about pId moving around since
10101 // it is a value class declared on the stack and so GC doesn't
10104 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10107 BEGIN_PIN_PROFILER(CORProfilerPresent());
10109 if (CORProfilerTrackRemotingCookie())
10111 g_profControlBlock.pProfInterface->GetGUID(pId);
10112 _ASSERTE(pId->Data1);
10114 g_profControlBlock.pProfInterface->RemotingServerSendingReply(pId, fIsAsync);
10118 g_profControlBlock.pProfInterface->RemotingServerSendingReply(NULL, fIsAsync);
10120 END_PIN_PROFILER();
10123 HELPER_METHOD_FRAME_END_POLL();
10124 #endif // PROFILING_SUPPORTED
10129 //*******************************************************************************************
10130 // These do a lot of work for us, setting up Frames, gathering arg info and resolving generics.
10131 //*******************************************************************************************
10133 HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecificHandle)
10137 #ifdef PROFILING_SUPPORTED
10139 #ifdef PROF_TEST_ONLY_FORCE_ELT
10140 // If this test-only flag is set, it's possible we might not have a profiler
10141 // attached, or might not have any of the hooks set. See
10142 // code:ProfControlBlock#TestOnlyELT
10143 if (g_profControlBlock.fTestOnlyForceEnterLeave)
10145 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10147 (g_profControlBlock.pProfInterface->GetEnterHook() == NULL) &&
10148 (g_profControlBlock.pProfInterface->GetEnter2Hook() == NULL) &&
10149 (g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL) &&
10150 (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL)
10157 #endif // PROF_TEST_ONLY_FORCE_ELT
10159 // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10160 _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL);
10161 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10162 _ASSERTE(platformSpecificHandle != NULL);
10165 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10167 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10168 // frame, like we're about to do.
10169 SetCallbackStateFlagsHolder csf(
10170 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10172 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10173 eltInfo.platformSpecificHandle = platformSpecificHandle;
10176 // CLR v4 Slow-Path ELT
10178 if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL)
10180 FunctionIDOrClientID functionIDOrClientID;
10181 functionIDOrClientID.clientID = clientData;
10182 g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()(
10183 functionIDOrClientID,
10184 (COR_PRF_ELT_INFO)&eltInfo);
10188 if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL)
10190 // We have run out of heap memory, so the content of the mapping table becomes stale.
10191 // All Whidbey ETL hooks must be turned off.
10192 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10197 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10198 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10199 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10200 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10201 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10202 FunctionID functionId = clientData;
10203 _ASSERTE(functionId != NULL);
10204 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10207 // Whidbey Fast-Path ELT
10209 if (CORProfilerELT2FastPathEnterEnabled())
10211 g_profControlBlock.pProfInterface->GetEnter2Hook()(
10220 // Whidbey Slow-Path ELT
10222 ProfileSetFunctionIDInPlatformSpecificHandle(platformSpecificHandle, functionId);
10224 COR_PRF_FRAME_INFO frameInfo = NULL;
10225 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo = NULL;
10226 ULONG ulArgInfoSize = 0;
10228 if (CORProfilerFunctionArgsEnabled())
10230 // The loader won't trigger a GC or throw for already loaded argument types.
10231 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
10234 // Find the method this is referring to, so we can get the signature
10236 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
10237 MetaSig metaSig(pMethodDesc);
10239 NewHolder<ProfileArgIterator> pProfileArgIterator;
10242 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
10245 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, platformSpecificHandle);
10247 if (pProfileArgIterator == NULL)
10253 ULONG32 count = pProfileArgIterator->GetNumArgs();
10255 if (metaSig.HasThis())
10260 ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE);
10261 pArgumentInfo = (COR_PRF_FUNCTION_ARGUMENT_INFO *)_alloca(ulArgInfoSize);
10264 HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo);
10266 _ASSERTE(hr == S_OK);
10267 g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
10273 // We will not be here unless the jit'd or ngen'd function we're about to enter
10274 // was backpatched with this wrapper around the profiler's hook, and that
10275 // wouldn't have happened unless the profiler supplied us with a hook
10276 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10277 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10278 // its mind about where the hooks are.)
10279 _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL);
10281 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10282 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10283 // to enable the jitter to add enter/leave callouts independently of whether
10284 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10285 // the callouts quickly return and do nothing.)
10291 g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData);
10297 HELPER_METHOD_FRAME_END(); // Un-link the frame
10299 #endif // PROFILING_SUPPORTED
10303 HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecificHandle)
10307 FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
10309 #ifdef PROFILING_SUPPORTED
10311 #ifdef PROF_TEST_ONLY_FORCE_ELT
10312 // If this test-only flag is set, it's possible we might not have a profiler
10313 // attached, or might not have any of the hooks set. See
10314 // code:ProfControlBlock#TestOnlyELT
10315 if (g_profControlBlock.fTestOnlyForceEnterLeave)
10317 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10319 (g_profControlBlock.pProfInterface->GetLeaveHook() == NULL) &&
10320 (g_profControlBlock.pProfInterface->GetLeave2Hook() == NULL) &&
10321 (g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL) &&
10322 (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL)
10329 #endif // PROF_TEST_ONLY_FORCE_ELT
10331 // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10332 _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL);
10333 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10334 _ASSERTE(platformSpecificHandle != NULL);
10337 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10339 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10340 // frame, like we're about to do.
10341 SetCallbackStateFlagsHolder csf(
10342 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10344 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10345 eltInfo.platformSpecificHandle = platformSpecificHandle;
10348 // CLR v4 Slow-Path ELT
10350 if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL)
10352 FunctionIDOrClientID functionIDOrClientID;
10353 functionIDOrClientID.clientID = clientData;
10354 g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()(
10355 functionIDOrClientID,
10356 (COR_PRF_ELT_INFO)&eltInfo);
10360 if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL)
10362 // We have run out of heap memory, so the content of the mapping table becomes stale.
10363 // All Whidbey ETL hooks must be turned off.
10364 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10369 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10370 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10371 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10372 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10373 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10374 FunctionID functionId = clientData;
10375 _ASSERTE(functionId != NULL);
10376 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10379 // Whidbey Fast-Path ELT
10381 if (CORProfilerELT2FastPathLeaveEnabled())
10383 g_profControlBlock.pProfInterface->GetLeave2Hook()(
10392 // Whidbey Slow-Path ELT
10394 COR_PRF_FRAME_INFO frameInfo = NULL;
10395 COR_PRF_FUNCTION_ARGUMENT_RANGE argumentRange;
10397 HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange);
10398 _ASSERTE(hr == S_OK);
10400 g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
10404 // We will not be here unless the jit'd or ngen'd function we're about to leave
10405 // was backpatched with this wrapper around the profiler's hook, and that
10406 // wouldn't have happened unless the profiler supplied us with a hook
10407 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10408 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10409 // its mind about where the hooks are.)
10410 _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL);
10412 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10413 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10414 // to enable the jitter to add enter/leave callouts independently of whether
10415 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10416 // the callouts quickly return and do nothing.)
10422 g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData);
10429 HELPER_METHOD_FRAME_END(); // Un-link the frame
10431 #endif // PROFILING_SUPPORTED
10435 HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpecificHandle)
10439 FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
10441 #ifdef PROFILING_SUPPORTED
10443 #ifdef PROF_TEST_ONLY_FORCE_ELT
10444 // If this test-only flag is set, it's possible we might not have a profiler
10445 // attached, or might not have any of the hooks set. See
10446 // code:ProfControlBlock#TestOnlyELT
10447 if (g_profControlBlock.fTestOnlyForceEnterLeave)
10449 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10451 (g_profControlBlock.pProfInterface->GetTailcallHook() == NULL) &&
10452 (g_profControlBlock.pProfInterface->GetTailcall2Hook() == NULL) &&
10453 (g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL) &&
10454 (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL)
10461 #endif // PROF_TEST_ONLY_FORCE_ELT
10463 // ELT3 fast-path hooks should be NULL when ELT intermediary is used.
10464 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL);
10465 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10466 _ASSERTE(platformSpecificHandle != NULL);
10469 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10471 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10472 // frame, like we're about to do.
10473 SetCallbackStateFlagsHolder csf(
10474 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10476 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10477 eltInfo.platformSpecificHandle = platformSpecificHandle;
10480 // CLR v4 Slow-Path ELT
10482 if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL)
10484 FunctionIDOrClientID functionIDOrClientID;
10485 functionIDOrClientID.clientID = clientData;
10486 g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()(
10487 functionIDOrClientID,
10488 (COR_PRF_ELT_INFO)&eltInfo);
10492 if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL)
10494 // We have run out of heap memory, so the content of the mapping table becomes stale.
10495 // All Whidbey ETL hooks must be turned off.
10496 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10501 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10502 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10503 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10504 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10505 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10506 FunctionID functionId = clientData;
10507 _ASSERTE(functionId != NULL);
10508 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10511 // Whidbey Fast-Path ELT
10513 if (CORProfilerELT2FastPathTailcallEnabled())
10515 g_profControlBlock.pProfInterface->GetTailcall2Hook()(
10523 // Whidbey Slow-Path ELT
10525 COR_PRF_FRAME_INFO frameInfo = NULL;
10527 HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo);
10528 _ASSERTE(hr == S_OK);
10530 g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
10534 // We will not be here unless the jit'd or ngen'd function we're about to tailcall
10535 // was backpatched with this wrapper around the profiler's hook, and that
10536 // wouldn't have happened unless the profiler supplied us with a hook
10537 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10538 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10539 // its mind about where the hooks are.)
10540 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL);
10542 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10543 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10544 // to enable the jitter to add enter/leave callouts independently of whether
10545 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10546 // the callouts quickly return and do nothing.)
10551 g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData);
10557 HELPER_METHOD_FRAME_END(); // Un-link the frame
10559 #endif // PROFILING_SUPPORTED