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 //---------------------------------------------------------------------------------------
1086 // Callback of type walk_fn used by the GC when walking the heap, to help profapi and ETW
1087 // track objects. This guy orchestrates the use of the above callbacks which dig
1088 // into object references contained each object encountered by this callback.
1089 // This method is defined when either GC_PROFILING is defined or FEATURE_EVENT_TRACING
1090 // is defined and can operate fully when only one of the two is defined.
1093 // pBO - Object reference encountered on the heap
1094 // pvContext - Pointer to ProfilerWalkHeapContext, containing ETW context built up
1095 // during this GC, and which remembers if profapi-profiler is supposed to be called.
1098 // BOOL indicating whether the heap walk should continue.
1102 extern bool s_forcedGCInProgress;
1104 bool HeapWalkHelper(Object * pBO, void * pvContext)
1114 OBJECTREF * arrObjRef = NULL;
1115 size_t cNumRefs = 0;
1116 bool bOnStack = false;
1117 MethodTable * pMT = pBO->GetMethodTable();
1119 ProfilerWalkHeapContext * pProfilerWalkHeapContext = (ProfilerWalkHeapContext *) pvContext;
1121 if (pMT->ContainsPointersOrCollectible())
1123 // First round through calculates the number of object refs for this class
1124 GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &CountContainedObjectRef, (void *)&cNumRefs);
1128 // Create an array to contain all of the refs for this object
1129 bOnStack = cNumRefs <= 32 ? true : false;
1133 // It's small enough, so just allocate on the stack
1134 arrObjRef = (OBJECTREF *)_alloca(cNumRefs * sizeof(OBJECTREF));
1138 // Otherwise, allocate from the heap
1139 arrObjRef = new (nothrow) OBJECTREF[cNumRefs];
1147 // Second round saves off all of the ref values
1148 OBJECTREF * pCurObjRef = arrObjRef;
1149 GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &SaveContainedObjectRef, (void *)&pCurObjRef);
1153 HRESULT hr = E_FAIL;
1155 #if defined(GC_PROFILING)
1156 if (pProfilerWalkHeapContext->fProfilerPinned)
1158 // It is not safe and could be overflowed to downcast size_t to ULONG on WIN64.
1159 // However, we have to do this dangerous downcast here to comply with the existing Profiling COM interface.
1160 // We are currently evaluating ways to fix this potential overflow issue.
1161 hr = g_profControlBlock.pProfInterface->ObjectReference(
1163 SafeGetClassIDFromObject(pBO),
1165 (ObjectID *) arrObjRef);
1169 #ifdef FEATURE_EVENT_TRACE
1170 if (s_forcedGCInProgress &&
1171 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
1172 TRACE_LEVEL_INFORMATION,
1173 CLR_GCHEAPDUMP_KEYWORD))
1175 ETW::GCLog::ObjectReference(
1176 pProfilerWalkHeapContext,
1178 (ULONGLONG) SafeGetClassIDFromObject(pBO),
1180 (Object **) arrObjRef);
1183 #endif // FEATURE_EVENT_TRACE
1185 // If the data was not allocated on the stack, need to clean it up.
1186 if ((arrObjRef != NULL) && !bOnStack)
1188 delete [] arrObjRef;
1191 // Return TRUE iff we want to the heap walk to continue. The only way we'd abort the
1192 // heap walk is if we're issuing profapi callbacks, and the profapi profiler
1193 // intentionally returned a failed HR (as its request that we stop the walk). There's
1194 // a potential conflict here. If a profapi profiler and an ETW profiler are both
1195 // monitoring the heap dump, and the profapi profiler requests to abort the walk (but
1196 // the ETW profiler may not want to abort the walk), then what do we do? The profapi
1197 // profiler gets precedence. We don't want to accidentally send more callbacks to a
1198 // profapi profiler that explicitly requested an abort. The ETW profiler will just
1199 // have to deal. In theory, I could make the code more complex by remembering that a
1200 // profapi profiler requested to abort the dump but an ETW profiler is still
1201 // attached, and then intentionally inhibit the remainder of the profapi callbacks
1202 // for this GC. But that's unnecessary complexity. In practice, it should be
1203 // extremely rare that a profapi profiler is monitoring heap dumps AND an ETW
1204 // profiler is also monitoring heap dumps.
1205 return (pProfilerWalkHeapContext->fProfilerPinned) ? SUCCEEDED(hr) : TRUE;
1208 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACING)
1210 #ifdef PROFILING_SUPPORTED
1211 //---------------------------------------------------------------------------------------
1213 // Callback of type walk_fn used by the GC when walking the heap, to help profapi
1214 // track objects. This is really just a wrapper around
1215 // EEToProfInterfaceImpl::AllocByClass, which does the real work
1218 // pBO - Object reference encountered on the heap
1219 // pv - Structure used by EEToProfInterfaceImpl::AllocByClass to do its work.
1222 // BOOL indicating whether the heap walk should continue.
1225 // Currently always returns TRUE
1228 bool AllocByClassHelper(Object * pBO, void * pv)
1237 _ASSERTE(pv != NULL);
1240 BEGIN_PIN_PROFILER(CORProfilerPresent());
1241 // Pass along the call
1242 g_profControlBlock.pProfInterface->AllocByClass(
1244 SafeGetClassIDFromObject(pBO),
1252 #endif // PROFILING_SUPPORTED
1253 #if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1255 //---------------------------------------------------------------------------------------
1257 // Callback of type promote_func called by GC while scanning roots (in GCProfileWalkHeap,
1258 // called after the collection). Wrapper around EEToProfInterfaceImpl::RootReference2,
1259 // which does the real work.
1262 // pObj - Object reference encountered
1263 /// ppRoot - Address that references ppObject (can be interior pointer)
1264 // pSC - ProfilingScanContext * containing the root kind and GCReferencesData used
1265 // by RootReference2
1266 // dwFlags - Properties of the root as GC_CALL* constants (this function converts
1267 // to COR_PRF_GC_ROOT_FLAGS.
1270 void ScanRootsHelper(Object* pObj, Object ** ppRoot, ScanContext *pSC, uint32_t dwFlags)
1280 // RootReference2 can return E_OUTOFMEMORY, and we're swallowing that.
1281 // Furthermore, we can't really handle it because we're callable during GC promotion.
1282 // On the other hand, this only means profiling information will be incomplete,
1283 // so it's ok to swallow E_OUTOFMEMORY.
1287 ProfilingScanContext *pPSC = (ProfilingScanContext *)pSC;
1289 DWORD dwEtwRootFlags = 0;
1290 if (dwFlags & GC_CALL_INTERIOR)
1291 dwEtwRootFlags |= kEtwGCRootFlagsInterior;
1292 if (dwFlags & GC_CALL_PINNED)
1293 dwEtwRootFlags |= kEtwGCRootFlagsPinning;
1295 #if defined(GC_PROFILING)
1296 void *rootID = NULL;
1297 switch (pPSC->dwEtwRootKind)
1299 case kEtwGCRootKindStack:
1303 case kEtwGCRootKindHandle:
1304 _ASSERT(!"Shouldn't see handle here");
1306 case kEtwGCRootKindFinalizer:
1311 // Notify profiling API of the root
1312 if (pPSC->fProfilerPinned)
1314 // Let the profiling code know about this root reference
1315 g_profControlBlock.pProfInterface->
1316 RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId));
1320 #ifdef FEATURE_EVENT_TRACE
1321 // Notify ETW of the root
1322 if (s_forcedGCInProgress &&
1323 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
1324 TRACE_LEVEL_INFORMATION,
1325 CLR_GCHEAPDUMP_KEYWORD))
1327 ETW::GCLog::RootReference(
1328 NULL, // handle is NULL, cuz this is a non-HANDLE root
1329 pObj, // object being rooted
1330 NULL, // pSecondaryNodeForDependentHandle is NULL, cuz this isn't a dependent handle
1331 FALSE, // is dependent handle
1333 dwFlags, // dwGCFlags
1336 #endif // FEATURE_EVENT_TRACE
1339 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1340 #ifdef PROFILING_SUPPORTED
1342 //---------------------------------------------------------------------------------------
1344 // Private ProfToEEInterfaceImpl maintenance functions
1348 //---------------------------------------------------------------------------------------
1350 // Initialize ProfToEEInterfaceImpl (including ModuleILHeap statics)
1353 // HRESULT indicating success
1356 HRESULT ProfToEEInterfaceImpl::Init()
1367 LOG((LF_CORPROF, LL_INFO1000, "**PROF: Init.\n"));
1370 if (ProfilingAPIUtility::ShouldInjectProfAPIFault(kProfAPIFault_StartupInternal))
1372 return E_OUTOFMEMORY;
1380 //---------------------------------------------------------------------------------------
1382 // Destroy ProfToEEInterfaceImpl (including ModuleILHeap statics)
1385 ProfToEEInterfaceImpl::~ProfToEEInterfaceImpl()
1395 LOG((LF_CORPROF, LL_INFO1000, "**PROF: Terminate.\n"));
1398 //---------------------------------------------------------------------------------------
1400 // Obsolete info functions
1403 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionInterface(IUnknown **)
1405 LIMITED_METHOD_CONTRACT;
1409 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionIThisThread(IUnknown **)
1411 LIMITED_METHOD_CONTRACT;
1415 HRESULT ProfToEEInterfaceImpl::BeginInprocDebugging(BOOL, DWORD *)
1417 LIMITED_METHOD_CONTRACT;
1421 HRESULT ProfToEEInterfaceImpl::EndInprocDebugging(DWORD)
1423 LIMITED_METHOD_CONTRACT;
1427 HRESULT ProfToEEInterfaceImpl::SetFunctionReJIT(FunctionID)
1429 LIMITED_METHOD_CONTRACT;
1436 //---------------------------------------------------------------------------------------
1438 // *******************************
1439 // Public Profiler->EE entrypoints
1440 // *******************************
1442 // ProfToEEInterfaceImpl implementation of public ICorProfilerInfo* methods
1444 // NOTE: All ICorProfilerInfo* method implementations must follow the rules stated
1445 // at the top of this file!
1448 // See corprof.idl / MSDN for detailed comments about each of these public
1449 // functions, their parameters, return values, etc.
1451 HRESULT ProfToEEInterfaceImpl::SetEventMask(DWORD dwEventMask)
1465 EE_THREAD_NOT_REQUIRED;
1472 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1475 "**PROF: SetEventMask 0x%08x.\n",
1478 _ASSERTE(CORProfilerPresentOrInitializing());
1480 return g_profControlBlock.pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */);
1483 HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHigh)
1497 EE_THREAD_NOT_REQUIRED;
1504 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1507 "**PROF: SetEventMask2 0x%08x, 0x%08x.\n",
1508 dwEventsLow, dwEventsHigh));
1510 _ASSERTE(CORProfilerPresentOrInitializing());
1512 return g_profControlBlock.pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh);
1516 HRESULT ProfToEEInterfaceImpl::GetHandleFromThread(ThreadID threadId, HANDLE *phThread)
1530 EE_THREAD_NOT_REQUIRED;
1538 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1541 "**PROF: GetHandleFromThread 0x%p.\n",
1544 if (!IsManagedThread(threadId))
1546 return E_INVALIDARG;
1551 HANDLE hThread = ((Thread *)threadId)->GetThreadHandle();
1553 if (hThread == INVALID_HANDLE_VALUE)
1557 *phThread = hThread;
1562 HRESULT ProfToEEInterfaceImpl::GetObjectSize(ObjectID objectId, ULONG *pcSize)
1572 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
1576 EE_THREAD_NOT_REQUIRED;
1584 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1587 "**PROF: GetObjectSize 0x%p.\n",
1590 if (objectId == NULL)
1592 return E_INVALIDARG;
1595 HRESULT hr = AllowObjectInspection();
1601 // Get the object pointer
1602 Object *pObj = reinterpret_cast<Object *>(objectId);
1607 SIZE_T size = pObj->GetSize();
1609 if(size < MIN_OBJECT_SIZE)
1611 size = PtrAlign(size);
1614 if (size > ULONG_MAX)
1616 *pcSize = ULONG_MAX;
1617 return COR_E_OVERFLOW;
1619 *pcSize = (ULONG)size;
1626 HRESULT ProfToEEInterfaceImpl::GetObjectSize2(ObjectID objectId, SIZE_T *pcSize)
1636 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
1640 EE_THREAD_NOT_REQUIRED;
1648 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1651 "**PROF: GetObjectSize2 0x%p.\n",
1654 if (objectId == NULL)
1656 return E_INVALIDARG;
1659 HRESULT hr = AllowObjectInspection();
1665 // Get the object pointer
1666 Object *pObj = reinterpret_cast<Object *>(objectId);
1671 SIZE_T size = pObj->GetSize();
1673 if(size < MIN_OBJECT_SIZE)
1675 size = PtrAlign(size);
1686 HRESULT ProfToEEInterfaceImpl::IsArrayClass(
1687 /* [in] */ ClassID classId,
1688 /* [out] */ CorElementType *pBaseElemType,
1689 /* [out] */ ClassID *pBaseClassId,
1690 /* [out] */ ULONG *pcRank)
1702 EE_THREAD_NOT_REQUIRED;
1710 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1713 "**PROF: IsArrayClass 0x%p.\n",
1718 if (classId == NULL)
1720 return E_INVALIDARG;
1723 TypeHandle th = TypeHandle::FromPtr((void *)classId);
1725 ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(th);
1727 // If this is indeed an array class, get some info about it
1732 _ASSERTE(!"Unexpected return from ArrayKindFromTypeHandle()");
1737 case ARRAY_KIND_TYPEDESC:
1739 // This is actually an array, so cast it up
1740 ArrayTypeDesc *pArr = th.AsArray();
1742 // Fill in the type if they want it
1743 if (pBaseElemType != NULL)
1745 *pBaseElemType = pArr->GetArrayElementTypeHandle().GetVerifierCorElementType();
1748 // If this is an array of classes and they wish to have the base type
1749 // If there is no associated class with this type, then there's no problem
1750 // because GetClass returns NULL which is the default we want to return in
1752 // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
1753 if (pBaseClassId != NULL)
1755 *pBaseClassId = TypeHandleToClassID(pArr->GetTypeParam());
1758 // If they want the number of dimensions of the array
1761 *pcRank = (ULONG) pArr->GetRank();
1764 // S_OK indicates that this was indeed an array
1768 case ARRAY_KIND_METHODTABLE:
1770 MethodTable *pArrMT = th.GetMethodTable();
1772 // Fill in the type if they want it
1773 if (pBaseElemType != NULL)
1775 *pBaseElemType = pArrMT->GetArrayElementType();
1778 // If this is an array of classes and they wish to have the base type.
1779 if (pBaseClassId != NULL)
1781 *pBaseClassId = TypeHandleToClassID(pArrMT->GetApproxArrayElementTypeHandle());
1784 // If they want the number of dimensions of the array
1787 *pcRank = (ULONG) pArrMT->GetRank();
1790 // S_OK indicates that this was indeed an array
1794 case ARRAY_KIND_NOTARRAY:
1796 if (pBaseClassId != NULL)
1798 *pBaseClassId = NULL;
1801 // This is not an array, S_FALSE indicates so.
1810 HRESULT ProfToEEInterfaceImpl::GetThreadInfo(ThreadID threadId, DWORD *pdwWin32ThreadId)
1824 EE_THREAD_NOT_REQUIRED;
1832 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1835 "**PROF: GetThreadInfo 0x%p.\n",
1838 if (!IsManagedThread(threadId))
1840 return E_INVALIDARG;
1843 if (pdwWin32ThreadId)
1845 *pdwWin32ThreadId = ((Thread *)threadId)->GetOSThreadId();
1851 HRESULT ProfToEEInterfaceImpl::GetCurrentThreadID(ThreadID *pThreadId)
1865 EE_THREAD_NOT_REQUIRED;
1873 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1876 "**PROF: GetCurrentThreadID.\n"));
1880 // No longer assert that GetThread doesn't return NULL, since callbacks
1881 // can now occur on non-managed threads (such as the GC helper threads)
1882 Thread * pThread = GetThreadNULLOk();
1884 // If pThread is null, then the thread has never run managed code and
1885 // so has no ThreadID
1886 if (!IsManagedThread(pThread))
1887 hr = CORPROF_E_NOT_MANAGED_THREAD;
1889 // Only provide value if they want it
1891 *pThreadId = (ThreadID) pThread;
1896 //---------------------------------------------------------------------------------------
1898 // Internal helper function to wrap a call into the JIT manager to get information about
1899 // a managed function based on IP
1902 // ip - IP address inside managed function of interest
1903 // ppCodeInfo - [out] information about the managed function based on IP
1906 // HRESULT indicating success or failure.
1910 HRESULT GetFunctionInfoInternal(LPCBYTE ip, EECodeInfo * pCodeInfo)
1917 EE_THREAD_NOT_REQUIRED;
1922 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
1923 // host (SQL). Corners will be cut to ensure this is the case
1924 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
1928 // Before calling into the code manager, ensure the GC heap has been
1929 // initialized--else the code manager will assert trying to get info from the heap.
1930 if (!IsGarbageCollectorFullyInitialized())
1932 return CORPROF_E_NOT_YET_AVAILABLE;
1935 if (ShouldAvoidHostCalls())
1937 ExecutionManager::ReaderLockHolder rlh(NoHostCalls);
1938 if (!rlh.Acquired())
1940 // Couldn't get the info. Try again later
1941 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
1944 pCodeInfo->Init((PCODE)ip, ExecutionManager::ScanNoReaderLock);
1948 pCodeInfo->Init((PCODE)ip);
1951 if (!pCodeInfo->IsValid())
1960 HRESULT GetFunctionFromIPInternal(LPCBYTE ip, EECodeInfo * pCodeInfo, BOOL failOnNoMetadata)
1967 EE_THREAD_NOT_REQUIRED;
1972 _ASSERTE (pCodeInfo != NULL);
1974 HRESULT hr = GetFunctionInfoInternal(ip, pCodeInfo);
1980 if (failOnNoMetadata)
1982 // never return a method that the user of the profiler API cannot use
1983 if (pCodeInfo->GetMethodDesc()->IsNoMetadata())
1993 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP(LPCBYTE ip, FunctionID * pFunctionId)
2007 EE_THREAD_NOT_REQUIRED;
2009 // Querying the code manager requires a reader lock. However, see
2010 // code:#DisableLockOnAsyncCalls
2011 DISABLED(CAN_TAKE_LOCK);
2013 // Asynchronous functions can be called at arbitrary times when runtime
2014 // is holding locks that cannot be reentered without causing deadlock.
2015 // This contract detects any attempts to reenter locks held at the time
2016 // this function was called.
2020 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2021 // host (SQL). Corners will be cut to ensure this is the case
2022 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2026 // See code:#DisableLockOnAsyncCalls
2027 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2029 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2032 "**PROF: GetFunctionFromIP 0x%p.\n",
2035 // This call is allowed asynchronously, but the JIT functions take a reader lock.
2036 // So we need to ensure the current thread hasn't been hijacked by a profiler while
2037 // it was holding the writer lock. Checking the ForbidSuspendThread region is a
2038 // sufficient test for this
2039 FAIL_IF_IN_FORBID_SUSPEND_REGION();
2043 EECodeInfo codeInfo;
2045 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2053 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2060 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP2(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
2067 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2068 // which can switch us to preemptive mode and trigger GCs
2075 EE_THREAD_NOT_REQUIRED;
2077 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2083 // See code:#DisableLockOnAsyncCalls
2084 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2086 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2087 kP2EEAllowableAfterAttach | kP2EETriggers,
2090 "**PROF: GetFunctionFromIP2 0x%p.\n",
2095 EECodeInfo codeInfo;
2097 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2105 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2108 if (pReJitId != NULL)
2110 MethodDesc * pMD = codeInfo.GetMethodDesc();
2111 *pReJitId = ReJitManager::GetReJitId(pMD, codeInfo.GetStartAddress());
2117 //*****************************************************************************
2118 // Given a function id, retrieve the metadata token and a reader api that
2119 // can be used against the token.
2120 //*****************************************************************************
2121 HRESULT ProfToEEInterfaceImpl::GetTokenAndMetaDataFromFunction(
2122 FunctionID functionId,
2139 EE_THREAD_NOT_REQUIRED;
2141 // PEFile::GetRWImporter and GetReadablePublicMetaDataInterface take locks
2147 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2150 "**PROF: GetTokenAndMetaDataFromFunction 0x%p.\n",
2153 if (functionId == NULL)
2155 return E_INVALIDARG;
2160 MethodDesc *pMD = FunctionIdToMethodDesc(functionId);
2162 // it's not safe to examine a methoddesc that has not been restored so do not do so
2163 if (!pMD->IsRestored())
2164 return CORPROF_E_DATAINCOMPLETE;
2168 *pToken = pMD->GetMemberDef();
2171 // don't bother with any of this module fetching if the metadata access isn't requested
2174 Module * pMod = pMD->GetModule();
2175 hr = pMod->GetReadablePublicMetaDataInterface(ofRead, riid, (LPVOID *) ppOut);
2181 //---------------------------------------------------------------------------------------
2182 // What follows are the GetCodeInfo* APIs and their helpers. The two helpers factor out
2183 // some of the common code to validate parameters and then determine the code info from
2184 // the start of the code. Each individual GetCodeInfo* API differs in how it uses these
2185 // helpers, particuarly in how it determines the start of the code (GetCodeInfo3 needs
2186 // to use the rejit manager to determine the code start, whereas the others do not).
2187 // Factoring out like this allows us to have statically determined contracts that differ
2188 // based on whether we need to use the rejit manager, which requires locking and
2190 //---------------------------------------------------------------------------------------
2193 HRESULT ValidateParametersForGetCodeInfo(
2194 MethodDesc * pMethodDesc,
2196 COR_PRF_CODE_INFO codeInfos[])
2198 LIMITED_METHOD_CONTRACT;
2200 if (pMethodDesc == NULL)
2202 return E_INVALIDARG;
2205 if ((cCodeInfos != 0) && (codeInfos == NULL))
2207 return E_INVALIDARG;
2210 // it's not safe to examine a methoddesc that has not been restored so do not do so
2211 if (!pMethodDesc->IsRestored())
2212 return CORPROF_E_DATAINCOMPLETE;
2214 if (pMethodDesc->HasClassOrMethodInstantiation() && pMethodDesc->IsTypicalMethodDefinition())
2216 // In this case, we used to replace pMethodDesc with its canonical instantiation
2217 // (FindOrCreateTypicalSharedInstantiation). However, a profiler should never be able
2218 // to get to this point anyway, since any MethodDesc a profiler gets from us
2219 // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
2220 // We assert here just in case a test proves me wrong, but generally we will
2221 // disallow this code path.
2222 _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetCodeInfo2");
2223 return E_INVALIDARG;
2229 HRESULT GetCodeInfoFromCodeStart(
2232 ULONG32 * pcCodeInfos,
2233 COR_PRF_CODE_INFO codeInfos[])
2241 // We need to take the ExecutionManager reader lock to find the
2242 // appropriate jit manager.
2246 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2247 // host (SQL). Corners will be cut to ensure this is the case
2248 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2252 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2254 ///////////////////////////////////
2255 // Get the code region info for this function. This is a multi step process.
2257 // MethodDesc ==> Code Address ==> JitMananger ==>
2258 // MethodToken ==> MethodRegionInfo
2260 // (Our caller handled the first step: MethodDesc ==> Code Address.)
2264 // On WIN64 we have a choice of where to go to find out the function address range size:
2265 // GC info (which is what we're doing below on all architectures) or the OS unwind
2266 // info, stored in the RUNTIME_FUNCTION structure. The latter produces
2267 // a SMALLER size than the former, because the latter excludes some data from
2268 // the set we report to the OS for unwind info. For example, switch tables can be
2269 // separated out from the regular code and not be reported as OS unwind info, and thus
2270 // those addresses will not appear in the range reported by the RUNTIME_FUNCTION gotten via:
2272 // IJitManager* pJitMan = ExecutionManager::FindJitMan((PBYTE)codeInfos[0].startAddress);
2273 // PRUNTIME_FUNCTION pfe = pJitMan->GetUnwindInfo((PBYTE)codeInfos[0].startAddress);
2274 // *pcCodeInfos = (ULONG) (pfe->EndAddress - pfe->BeginAddress);
2276 // (Note that GCInfo & OS unwind info report the same start address--it's the size that's
2279 // The advantage of using the GC info is that it's available on all architectures,
2280 // and it gives you a more complete picture of the addresses belonging to the function.
2282 // A disadvantage of using GC info is we'll report those extra addresses (like switch
2283 // tables) that a profiler might turn back around and use in a call to
2284 // GetFunctionFromIP. A profiler may expect we'd be able to map back any address
2285 // in the function's GetCodeInfo ranges back to that function's FunctionID (methoddesc). But
2286 // querying these extra addresses will cause GetFunctionFromIP to fail, as they're not
2287 // actually valid instruction addresses that the IP register can be set to.
2289 // The advantage wins out, so we're going with GC info everywhere.
2297 return CORPROF_E_FUNCTION_NOT_COMPILED;
2300 EECodeInfo codeInfo;
2301 hr = GetFunctionInfoInternal(
2304 if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
2306 _ASSERTE(ShouldAvoidHostCalls());
2311 return CORPROF_E_FUNCTION_NOT_COMPILED;
2314 IJitManager::MethodRegionInfo methodRegionInfo;
2315 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
2318 // Fill out the codeInfo structures with valuse from the
2321 // Note that we're assuming that a method will never be split into
2322 // more than two regions ... this is unlikely to change any time in
2325 if (NULL != codeInfos)
2330 // We have to return the two regions in the order that they would appear
2331 // if straight-line compiled
2333 if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2335 codeInfos[0].startAddress =
2336 (UINT_PTR)methodRegionInfo.hotStartAddress;
2337 codeInfos[0].size = methodRegionInfo.hotSize;
2341 _ASSERTE(methodRegionInfo.coldStartAddress != NULL);
2342 codeInfos[0].startAddress =
2343 (UINT_PTR)methodRegionInfo.coldStartAddress;
2344 codeInfos[0].size = methodRegionInfo.coldSize;
2347 if (NULL != methodRegionInfo.coldStartAddress)
2351 if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2353 codeInfos[1].startAddress =
2354 (UINT_PTR)methodRegionInfo.coldStartAddress;
2355 codeInfos[1].size = methodRegionInfo.coldSize;
2359 codeInfos[1].startAddress =
2360 (UINT_PTR)methodRegionInfo.hotStartAddress;
2361 codeInfos[1].size = methodRegionInfo.hotSize;
2368 if (NULL != pcCodeInfos)
2370 *pcCodeInfos = (NULL != methodRegionInfo.coldStartAddress) ? 2 : 1;
2377 //*****************************************************************************
2378 // Gets the location and size of a jitted function
2379 //*****************************************************************************
2381 HRESULT ProfToEEInterfaceImpl::GetCodeInfo(FunctionID functionId, LPCBYTE * pStart, ULONG * pcSize)
2395 EE_THREAD_NOT_REQUIRED;
2397 // (See locking contract comment in GetCodeInfoHelper.)
2398 DISABLED(CAN_TAKE_LOCK);
2400 // (See locking contract comment in GetCodeInfoHelper.)
2404 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2405 // host (SQL). Corners will be cut to ensure this is the case
2406 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2410 // See code:#DisableLockOnAsyncCalls
2411 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2413 // This is called asynchronously, but GetCodeInfoHelper() will
2414 // ensure we're not called at a dangerous time
2415 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2418 "**PROF: GetCodeInfo 0x%p.\n",
2421 // GetCodeInfo may be called asynchronously, and the JIT functions take a reader
2422 // lock. So we need to ensure the current thread hasn't been hijacked by a profiler while
2423 // it was holding the writer lock. Checking the ForbidSuspendThread region is a sufficient test for this
2424 FAIL_IF_IN_FORBID_SUSPEND_REGION();
2426 if (functionId == 0)
2428 return E_INVALIDARG;
2431 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2433 COR_PRF_CODE_INFO codeInfos[2];
2436 HRESULT hr = GetCodeInfoFromCodeStart(
2437 pMethodDesc->GetNativeCode(),
2438 _countof(codeInfos),
2442 if ((FAILED(hr)) || (0 == cCodeInfos))
2449 *pStart = reinterpret_cast< LPCBYTE >(codeInfos[0].startAddress);
2454 if (!FitsIn<ULONG>(codeInfos[0].size))
2456 return E_UNEXPECTED;
2458 *pcSize = static_cast<ULONG>(codeInfos[0].size);
2464 HRESULT ProfToEEInterfaceImpl::GetCodeInfo2(FunctionID functionId,
2466 ULONG32 * pcCodeInfos,
2467 COR_PRF_CODE_INFO codeInfos[])
2481 EE_THREAD_NOT_REQUIRED;
2483 // (See locking contract comment in GetCodeInfoHelper.)
2484 DISABLED(CAN_TAKE_LOCK);
2486 // (See locking contract comment in GetCodeInfoHelper.)
2490 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2491 // host (SQL). Corners will be cut to ensure this is the case
2492 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2494 PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2495 PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2499 // See code:#DisableLockOnAsyncCalls
2500 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2502 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2505 "**PROF: GetCodeInfo2 0x%p.\n",
2512 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2514 hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2517 hr = GetCodeInfoFromCodeStart(
2518 pMethodDesc->GetNativeCode(),
2524 EX_CATCH_HRESULT(hr);
2530 HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId,
2533 ULONG32* pcCodeInfos,
2534 COR_PRF_CODE_INFO codeInfos[])
2543 // We need to access the rejitmanager, which means taking locks, which means we
2551 EE_THREAD_NOT_REQUIRED;
2553 // We need to access the rejitmanager, which means taking locks
2557 PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2558 PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2562 // See code:#DisableLockOnAsyncCalls
2563 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2565 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2566 kP2EEAllowableAfterAttach | kP2EETriggers,
2569 "**PROF: GetCodeInfo3 0x%p 0x%p.\n",
2570 functionId, reJitId));
2576 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2578 hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2581 PCODE pCodeStart = NULL;
2582 CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
2584 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
2586 ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMethodDesc, reJitId);
2588 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMethodDesc);
2589 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
2591 // Now that tiered compilation can create more than one jitted code version for the same rejit id
2592 // we are arbitrarily choosing the first one to return. To address a specific version of native code
2593 // use GetCodeInfo4.
2594 pCodeStart = iter->GetNativeCode();
2599 hr = GetCodeInfoFromCodeStart(pCodeStart,
2605 EX_CATCH_HRESULT(hr);
2611 HRESULT ProfToEEInterfaceImpl::GetEventMask(DWORD * pdwEvents)
2625 EE_THREAD_NOT_REQUIRED;
2634 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2637 "**PROF: GetEventMask.\n"));
2639 if (pdwEvents == NULL)
2641 return E_INVALIDARG;
2644 *pdwEvents = g_profControlBlock.dwEventMask;
2648 HRESULT ProfToEEInterfaceImpl::GetEventMask2(DWORD *pdwEventsLow, DWORD *pdwEventsHigh)
2662 EE_THREAD_NOT_REQUIRED;
2671 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2674 "**PROF: GetEventMask2.\n"));
2676 if ((pdwEventsLow == NULL) || (pdwEventsHigh == NULL))
2678 return E_INVALIDARG;
2681 *pdwEventsLow = g_profControlBlock.dwEventMask;
2682 *pdwEventsHigh = g_profControlBlock.dwEventMaskHigh;
2687 void ProfToEEInterfaceImpl::MethodTableCallback(void* context, void* objectUNSAFE)
2697 // each callback identifies the address of a method table within the frozen object segment
2698 // that pointer is an object ID by definition -- object references point to the method table
2699 CDynArray< ObjectID >* objects = reinterpret_cast< CDynArray< ObjectID >* >(context);
2701 *objects->Append() = reinterpret_cast< ObjectID >(objectUNSAFE);
2705 void ProfToEEInterfaceImpl::ObjectRefCallback(void* context, void* objectUNSAFE)
2707 // we don't care about embedded object references, ignore them
2711 HRESULT ProfToEEInterfaceImpl::EnumModuleFrozenObjects(ModuleID moduleID,
2712 ICorProfilerObjectEnum** ppEnum)
2726 EE_THREAD_NOT_REQUIRED;
2734 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2737 "**PROF: EnumModuleFrozenObjects 0x%p.\n",
2742 return E_INVALIDARG;
2745 Module* pModule = reinterpret_cast< Module* >(moduleID);
2746 if (pModule == NULL || pModule->IsBeingUnloaded())
2748 return CORPROF_E_DATAINCOMPLETE;
2755 // If we don't support frozen objects at all, then just return empty
2757 *ppEnum = new ProfilerObjectEnum();
2759 EX_CATCH_HRESULT(hr);
2767 * GetArrayObjectInfo
2769 * This function returns informatin about array objects. In particular, the dimensions
2770 * and where the data buffer is stored.
2773 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfo(ObjectID objectId,
2774 ULONG32 cDimensionSizes,
2775 ULONG32 pDimensionSizes[],
2776 int pDimensionLowerBounds[],
2787 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
2796 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2799 "**PROF: GetArrayObjectInfo 0x%p.\n",
2802 if (objectId == NULL)
2804 return E_INVALIDARG;
2807 if ((pDimensionSizes == NULL) ||
2808 (pDimensionLowerBounds == NULL) ||
2811 return E_INVALIDARG;
2814 HRESULT hr = AllowObjectInspection();
2820 Object * pObj = reinterpret_cast<Object *>(objectId);
2822 // GC callbacks may come from a non-EE thread, which is considered permanently preemptive.
2823 // We are about calling some object inspection functions, which require to be in co-op mode.
2824 // Given that none managed objects can be changed by managed code until GC resumes the
2825 // runtime, it is safe to violate the mode contract and to inspect managed objects from a
2826 // non-EE thread when GetArrayObjectInfo is called within GC callbacks.
2827 if (NativeThreadInGC())
2829 CONTRACT_VIOLATION(ModeViolation);
2830 return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2833 return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2836 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfoHelper(Object * pObj,
2837 ULONG32 cDimensionSizes,
2838 __out_ecount(cDimensionSizes) ULONG32 pDimensionSizes[],
2839 __out_ecount(cDimensionSizes) int pDimensionLowerBounds[],
2850 // Because of the object pointer parameter, we must be either in CO-OP mode,
2851 // or on a non-EE thread in the process of doing a GC .
2852 if (!NativeThreadInGC()) { MODE_COOPERATIVE; }
2860 // Must have an array.
2861 MethodTable * pMT = pObj->GetMethodTable();
2862 if (!pMT->IsArray())
2864 return E_INVALIDARG;
2867 ArrayBase * pArray = static_cast<ArrayBase*> (pObj);
2869 unsigned rank = pArray->GetRank();
2871 if (cDimensionSizes < rank)
2873 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2876 // Copy range for each dimension (rank)
2877 int * pBounds = pArray->GetBoundsPtr();
2878 int * pLowerBounds = pArray->GetLowerBoundsPtr();
2881 for(i = 0; i < rank; i++)
2883 pDimensionSizes[i] = pBounds[i];
2884 pDimensionLowerBounds[i] = pLowerBounds[i];
2888 *ppData = pArray->GetDataPtr();
2896 * Returns information about how a particular value type is laid out.
2899 HRESULT ProfToEEInterfaceImpl::GetBoxClassLayout(ClassID classId,
2900 ULONG32 *pBufferOffset)
2914 EE_THREAD_NOT_REQUIRED;
2922 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2925 "**PROF: GetBoxClassLayout 0x%p.\n",
2928 if (pBufferOffset == NULL)
2930 return E_INVALIDARG;
2933 if (classId == NULL)
2935 return E_INVALIDARG;
2938 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
2941 // This is the incorrect API for arrays. Use GetArrayInfo and GetArrayLayout.
2943 if (!typeHandle.IsValueType())
2945 return E_INVALIDARG;
2948 *pBufferOffset = Object::GetOffsetOfFirstField();
2954 * GetThreadAppDomain
2956 * Returns the app domain currently associated with the given thread.
2959 HRESULT ProfToEEInterfaceImpl::GetThreadAppDomain(ThreadID threadId,
2960 AppDomainID *pAppDomainId)
2975 EE_THREAD_NOT_REQUIRED;
2983 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2986 "**PROF: GetThreadAppDomain 0x%p.\n",
2989 if (pAppDomainId == NULL)
2991 return E_INVALIDARG;
2996 if (threadId == NULL)
2998 pThread = GetThreadNULLOk();
3002 pThread = (Thread *)threadId;
3006 // If pThread is null, then the thread has never run managed code and
3007 // so has no ThreadID.
3009 if (!IsManagedThread(pThread))
3011 return CORPROF_E_NOT_MANAGED_THREAD;
3014 *pAppDomainId = (AppDomainID)pThread->GetDomain();
3021 * GetRVAStaticAddress
3023 * This function returns the absolute address of the given field in the given
3024 * class. The field must be an RVA Static token.
3027 * classId - the containing class.
3028 * fieldToken - the field we are querying.
3029 * pAddress - location for storing the resulting address location.
3033 * E_INVALIDARG if not an RVA static,
3034 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3037 HRESULT ProfToEEInterfaceImpl::GetRVAStaticAddress(ClassID classId,
3038 mdFieldDef fieldToken,
3052 // FieldDesc::GetStaticAddress takes a lock
3058 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3061 "**PROF: GetRVAStaticAddress 0x%p, 0x%08x.\n",
3066 // Check for NULL parameters
3068 if ((classId == NULL) || (ppAddress == NULL))
3070 return E_INVALIDARG;
3073 if (GetThread() == NULL)
3075 return CORPROF_E_NOT_MANAGED_THREAD;
3078 if (GetAppDomain() == NULL)
3083 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3086 // If this class is not fully restored, that is all the information we can get at this time.
3088 if (!typeHandle.IsRestored())
3090 return CORPROF_E_DATAINCOMPLETE;
3094 // Get the field descriptor object
3096 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3098 if (pFieldDesc == NULL)
3100 return E_INVALIDARG;
3104 // Verify this field is of the right type
3106 if(!pFieldDesc->IsStatic() ||
3107 !pFieldDesc->IsRVA() ||
3108 pFieldDesc->IsThreadStatic())
3110 return E_INVALIDARG;
3113 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3114 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3115 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3118 // Check that the data is available
3120 if (!IsClassOfMethodTableInited(pMethodTable))
3122 return CORPROF_E_DATAINCOMPLETE;
3126 // Store the result and return
3128 PTR_VOID pAddress = pFieldDesc->GetStaticAddress(NULL);
3129 if (pAddress == NULL)
3131 return CORPROF_E_DATAINCOMPLETE;
3134 *ppAddress = pAddress;
3141 * GetAppDomainStaticAddress
3143 * This function returns the absolute address of the given field in the given
3144 * class in the given app domain. The field must be an App Domain Static token.
3147 * classId - the containing class.
3148 * fieldToken - the field we are querying.
3149 * appDomainId - the app domain container.
3150 * pAddress - location for storing the resulting address location.
3154 * E_INVALIDARG if not an app domain static,
3155 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3158 HRESULT ProfToEEInterfaceImpl::GetAppDomainStaticAddress(ClassID classId,
3159 mdFieldDef fieldToken,
3160 AppDomainID appDomainId,
3175 EE_THREAD_NOT_REQUIRED;
3177 // FieldDesc::GetStaticAddress & FieldDesc::GetBase take locks
3183 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3186 "**PROF: GetAppDomainStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3192 // Check for NULL parameters
3194 if ((classId == NULL) || (appDomainId == NULL) || (ppAddress == NULL))
3196 return E_INVALIDARG;
3199 // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3200 // statics. See if the profiler is trying to be naughty.
3201 if (!((BaseDomain*) appDomainId)->IsAppDomain())
3203 return E_INVALIDARG;
3206 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3209 // If this class is not fully restored, that is all the information we can get at this time.
3211 if (!typeHandle.IsRestored())
3213 return CORPROF_E_DATAINCOMPLETE;
3217 // Get the field descriptor object
3219 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3221 if (pFieldDesc == NULL)
3224 // Give specific error code for literals.
3227 if (FAILED(typeHandle.GetModule()->GetMDImport()->GetFieldDefProps(fieldToken, &dwFieldAttrs)))
3229 return E_INVALIDARG;
3232 if (IsFdLiteral(dwFieldAttrs))
3234 return CORPROF_E_LITERALS_HAVE_NO_ADDRESS;
3237 return E_INVALIDARG;
3241 // Verify this field is of the right type
3243 if(!pFieldDesc->IsStatic() ||
3244 pFieldDesc->IsRVA() ||
3245 pFieldDesc->IsThreadStatic())
3247 return E_INVALIDARG;
3250 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3251 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3252 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3253 AppDomain * pAppDomain = (AppDomain *)appDomainId;
3256 // Check that the data is available
3258 if (!IsClassOfMethodTableInited(pMethodTable))
3260 return CORPROF_E_DATAINCOMPLETE;
3266 void *base = (void*)pFieldDesc->GetBase();
3270 return CORPROF_E_DATAINCOMPLETE;
3274 // Store the result and return
3276 PTR_VOID pAddress = pFieldDesc->GetStaticAddress(base);
3277 if (pAddress == NULL)
3279 return E_INVALIDARG;
3282 *ppAddress = pAddress;
3288 * GetThreadStaticAddress
3290 * This function returns the absolute address of the given field in the given
3291 * class on the given thread. The field must be an Thread Static token. threadId
3292 * must be the current thread ID or NULL, which means using curernt thread ID.
3295 * classId - the containing class.
3296 * fieldToken - the field we are querying.
3297 * threadId - the thread container, which has to be the current managed thread or
3298 * NULL, which means to use the current managed thread.
3299 * pAddress - location for storing the resulting address location.
3303 * E_INVALIDARG if not a thread static,
3304 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3307 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress(ClassID classId,
3308 mdFieldDef fieldToken,
3329 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3332 "**PROF: GetThreadStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3338 // Verify the value of threadId, which must be the current thread ID or NULL, which means using curernt thread ID.
3340 if ((threadId != NULL) && (threadId != ((ThreadID)GetThread())))
3342 return E_INVALIDARG;
3345 threadId = reinterpret_cast<ThreadID>(GetThread());
3346 AppDomainID appDomainId = reinterpret_cast<AppDomainID>(GetAppDomain());
3349 // Check for NULL parameters
3351 if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3353 return E_INVALIDARG;
3356 return GetThreadStaticAddress2(classId,
3364 * GetThreadStaticAddress2
3366 * This function returns the absolute address of the given field in the given
3367 * class on the given thread. The field must be an Thread Static token.
3370 * classId - the containing class.
3371 * fieldToken - the field we are querying.
3372 * appDomainId - the AppDomain container.
3373 * threadId - the thread container.
3374 * pAddress - location for storing the resulting address location.
3378 * E_INVALIDARG if not a thread static,
3379 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3382 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress2(ClassID classId,
3383 mdFieldDef fieldToken,
3384 AppDomainID appDomainId,
3405 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3408 "**PROF: GetThreadStaticAddress2 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3415 if (threadId == NULL)
3417 if (GetThread() == NULL)
3419 return CORPROF_E_NOT_MANAGED_THREAD;
3422 threadId = reinterpret_cast<ThreadID>(GetThread());
3426 // Check for NULL parameters
3428 if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3430 return E_INVALIDARG;
3433 // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3434 // statics. See if the profiler is trying to be naughty.
3435 if (!((BaseDomain*) appDomainId)->IsAppDomain())
3437 return E_INVALIDARG;
3440 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3443 // If this class is not fully restored, that is all the information we can get at this time.
3445 if (!typeHandle.IsRestored())
3447 return CORPROF_E_DATAINCOMPLETE;
3451 // Get the field descriptor object
3453 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3455 if (pFieldDesc == NULL)
3457 return E_INVALIDARG;
3461 // Verify this field is of the right type
3463 if(!pFieldDesc->IsStatic() ||
3464 !pFieldDesc->IsThreadStatic() ||
3465 pFieldDesc->IsRVA())
3467 return E_INVALIDARG;
3470 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3471 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3472 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3475 // Check that the data is available
3477 if (!IsClassOfMethodTableInited(pMethodTable))
3479 return CORPROF_E_DATAINCOMPLETE;
3483 // Store the result and return
3485 PTR_VOID pAddress = (void *)(((Thread *)threadId)->GetStaticFieldAddrNoCreate(pFieldDesc));
3486 if (pAddress == NULL)
3488 return E_INVALIDARG;
3491 *ppAddress = pAddress;
3497 * GetContextStaticAddress
3499 * This function returns the absolute address of the given field in the given
3500 * class in the given context. The field must be an Context Static token.
3503 * classId - the containing class.
3504 * fieldToken - the field we are querying.
3505 * contextId - the context container.
3506 * pAddress - location for storing the resulting address location.
3512 HRESULT ProfToEEInterfaceImpl::GetContextStaticAddress(ClassID classId,
3513 mdFieldDef fieldToken,
3514 ContextID contextId,
3534 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3537 "**PROF: GetContextStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3546 * GetAppDomainsContainingModule
3548 * This function returns the AppDomains in which the given module has been loaded
3551 * moduleId - the module with static variables.
3552 * cAppDomainIds - the input size of appDomainIds array.
3553 * pcAppDomainIds - the output size of appDomainIds array.
3554 * appDomainIds - the array to be filled up with AppDomainIDs containing initialized
3555 * static variables from the moduleId's moudle.
3559 * E_INVALIDARG for invalid parameters,
3560 * CORPROF_E_DATAINCOMPLETE if moduleId's module is not yet initialized.
3563 HRESULT ProfToEEInterfaceImpl::GetAppDomainsContainingModule(ModuleID moduleId,
3564 ULONG32 cAppDomainIds,
3565 ULONG32 * pcAppDomainIds,
3566 AppDomainID appDomainIds[])
3573 // This method iterates over AppDomains, which adds, then releases, a reference on
3574 // each AppDomain iterated. This causes locking, and can cause triggering if the
3575 // AppDomain gets destroyed as a result of the release. (See code:AppDomainIterator::Next
3576 // and its call to code:AppDomain::Release.)
3582 // (See comment above GC_TRIGGERS.)
3588 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
3589 kP2EEAllowableAfterAttach | kP2EETriggers,
3592 "**PROF: GetAppDomainsContainingModule 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3600 // Check for NULL parameters
3602 if ((moduleId == NULL) || ((appDomainIds == NULL) && (cAppDomainIds != 0)) || (pcAppDomainIds == NULL))
3604 return E_INVALIDARG;
3607 Module* pModule = reinterpret_cast< Module* >(moduleId);
3608 if (pModule->IsBeingUnloaded())
3610 return CORPROF_E_DATAINCOMPLETE;
3613 // IterateAppDomainContainingModule uses AppDomainIterator, which cannot be called while the current thread
3614 // is holding the ThreadStore lock.
3615 if (ThreadStore::HoldingThreadStore())
3617 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
3620 IterateAppDomainContainingModule iterateAppDomainContainingModule(pModule, cAppDomainIds, pcAppDomainIds, appDomainIds);
3622 return iterateAppDomainContainingModule.PopulateArray();
3628 * GetStaticFieldInfo
3630 * This function returns a bit mask of the type of statics the
3634 * classId - the containing class.
3635 * fieldToken - the field we are querying.
3636 * pFieldInfo - location for storing the resulting bit mask.
3640 * E_INVALIDARG if pFieldInfo is NULL
3643 HRESULT ProfToEEInterfaceImpl::GetStaticFieldInfo(ClassID classId,
3644 mdFieldDef fieldToken,
3645 COR_PRF_STATIC_TYPE *pFieldInfo)
3659 EE_THREAD_NOT_REQUIRED;
3667 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3670 "**PROF: GetStaticFieldInfo 0x%p, 0x%08x.\n",
3675 // Check for NULL parameters
3677 if ((classId == NULL) || (pFieldInfo == NULL))
3679 return E_INVALIDARG;
3682 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3685 // If this class is not fully restored, that is all the information we can get at this time.
3687 if (!typeHandle.IsRestored())
3689 return CORPROF_E_DATAINCOMPLETE;
3693 // Get the field descriptor object
3695 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3697 if (pFieldDesc == NULL)
3699 return E_INVALIDARG;
3702 *pFieldInfo = COR_PRF_FIELD_NOT_A_STATIC;
3704 if (pFieldDesc->IsRVA())
3706 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_RVA_STATIC);
3709 if (pFieldDesc->IsThreadStatic())
3711 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_THREAD_STATIC);
3714 if ((*pFieldInfo == COR_PRF_FIELD_NOT_A_STATIC) && pFieldDesc->IsStatic())
3716 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_APP_DOMAIN_STATIC);
3727 * This function generalizes GetClassIDInfo for all types, both generic and non-generic. It returns
3728 * the module, type token, and an array of instantiation classIDs that were used to instantiate the
3732 * classId - The classId (TypeHandle) to query information about.
3733 * pParentClassId - The ClassID (TypeHandle) of the parent class.
3734 * pModuleId - An optional parameter for returning the module of the class.
3735 * pTypeDefToken - An optional parameter for returning the metadata token of the class.
3736 * cNumTypeArgs - The count of the size of the array typeArgs
3737 * pcNumTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
3738 * the number that would be needed.
3739 * typeArgs - An array to store generic type parameters for the class.
3742 * S_OK if successful.
3744 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo2(ClassID classId,
3745 ModuleID *pModuleId,
3746 mdTypeDef *pTypeDefToken,
3747 ClassID *pParentClassId,
3748 ULONG32 cNumTypeArgs,
3749 ULONG32 *pcNumTypeArgs,
3765 EE_THREAD_NOT_REQUIRED;
3771 PRECONDITION(CheckPointer(pParentClassId, NULL_OK));
3772 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
3773 PRECONDITION(CheckPointer(pTypeDefToken, NULL_OK));
3774 PRECONDITION(CheckPointer(pcNumTypeArgs, NULL_OK));
3775 PRECONDITION(CheckPointer(typeArgs, NULL_OK));
3779 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3782 "**PROF: GetClassIDInfo2 0x%p.\n",
3786 // Verify parameters.
3788 if (classId == NULL)
3790 return E_INVALIDARG;
3793 if ((cNumTypeArgs != 0) && (typeArgs == NULL))
3795 return E_INVALIDARG;
3798 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3801 // If this class is not fully restored, that is all the information we can get at this time.
3803 if (!typeHandle.IsRestored())
3805 return CORPROF_E_DATAINCOMPLETE;
3809 // Handle globals which don't have the instances.
3811 if (classId == PROFILER_GLOBAL_CLASS)
3813 if (pParentClassId != NULL)
3815 *pParentClassId = NULL;
3818 if (pModuleId != NULL)
3820 *pModuleId = PROFILER_GLOBAL_MODULE;
3823 if (pTypeDefToken != NULL)
3825 *pTypeDefToken = mdTokenNil;
3832 // Do not do arrays via this API
3834 ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(typeHandle);
3835 if (arrayKind == ARRAY_KIND_TYPEDESC || arrayKind == ARRAY_KIND_METHODTABLE)
3837 return CORPROF_E_CLASSID_IS_ARRAY;
3840 _ASSERTE (arrayKind == ARRAY_KIND_NOTARRAY);
3842 if (typeHandle.IsTypeDesc())
3844 // Not an array, but still a typedesc? We don't know how to
3846 return CORPROF_E_CLASSID_IS_COMPOSITE;
3850 // Fill in the basic information
3852 if (pParentClassId != NULL)
3854 TypeHandle parentTypeHandle = typeHandle.GetParent();
3855 if (!parentTypeHandle.IsNull())
3857 *pParentClassId = TypeHandleToClassID(parentTypeHandle);
3861 *pParentClassId = NULL;
3865 if (pModuleId != NULL)
3867 *pModuleId = (ModuleID) typeHandle.GetModule();
3868 _ASSERTE(*pModuleId != NULL);
3871 if (pTypeDefToken != NULL)
3873 *pTypeDefToken = typeHandle.GetCl();
3874 _ASSERTE(*pTypeDefToken != NULL);
3878 // See if they are just looking to get the buffer size.
3880 if (cNumTypeArgs == 0)
3882 if (pcNumTypeArgs != NULL)
3884 *pcNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3890 // Adjust the count for the size of the given array.
3892 if (cNumTypeArgs > typeHandle.GetMethodTable()->GetNumGenericArgs())
3894 cNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3897 if (pcNumTypeArgs != NULL)
3899 *pcNumTypeArgs = cNumTypeArgs;
3903 // Copy over the instantiating types.
3906 Instantiation inst = typeHandle.GetMethodTable()->GetInstantiation();
3908 for (count = 0; count < cNumTypeArgs; count ++)
3910 typeArgs[count] = TypeHandleToClassID(inst[count]);
3916 HRESULT ProfToEEInterfaceImpl::GetModuleInfo(ModuleID moduleId,
3917 LPCBYTE * ppBaseLoadAddress,
3920 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
3921 AssemblyID * pAssemblyId)
3931 // See comment in code:ProfToEEInterfaceImpl::GetModuleInfo2
3938 EE_THREAD_NOT_REQUIRED;
3941 PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
3942 PRECONDITION(CheckPointer(ppBaseLoadAddress, NULL_OK));
3943 PRECONDITION(CheckPointer(pcchName, NULL_OK));
3944 PRECONDITION(CheckPointer(wszName, NULL_OK));
3945 PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
3949 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3952 "**PROF: GetModuleInfo 0x%p.\n",
3955 // Paramter validation is taken care of in GetModuleInfo2.
3957 return GetModuleInfo2(
3964 NULL); // Don't need module type
3967 //---------------------------------------------------------------------------------------
3969 // Helper used by GetModuleInfo2 to determine the bitmask of COR_PRF_MODULE_FLAGS for
3970 // the specified module.
3973 // pModule - Module to get the flags for
3976 // Bitmask of COR_PRF_MODULE_FLAGS corresponding to pModule
3979 DWORD ProfToEEInterfaceImpl::GetModuleFlags(Module * pModule)
3985 CAN_TAKE_LOCK; // IsWindowsRuntimeModule accesses metadata directly, which takes locks
3990 PEFile * pPEFile = pModule->GetFile();
3991 if (pPEFile == NULL)
3993 // Hopefully this should never happen; but just in case, don't try to determine the
3994 // flags without a PEFile.
4000 // First, set the flags that are dependent on which PEImage / layout we look at
4001 // inside the Module (disk/ngen/flat)
4003 if (pModule->HasNativeImage())
4006 dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4008 // Intentionally not checking for flat, since NGEN PEImages never have flat
4013 #ifdef FEATURE_READYTORUN
4014 // pModule->HasNativeImage() returns false for ReadyToRun images
4015 if (pModule->IsReadyToRun())
4018 dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4021 // Not NGEN or ReadyToRun.
4022 if (pPEFile->HasOpenedILimage())
4024 PEImage * pILImage = pPEFile->GetOpenedILimage();
4025 if (pILImage->IsFile())
4027 dwRet |= COR_PRF_MODULE_DISK;
4029 if (pPEFile->GetLoadedIL()->IsFlat())
4031 dwRet |= COR_PRF_MODULE_FLAT_LAYOUT;
4036 if (pModule->IsReflection())
4038 dwRet |= COR_PRF_MODULE_DYNAMIC;
4041 if (pModule->IsCollectible())
4043 dwRet |= COR_PRF_MODULE_COLLECTIBLE;
4046 if (pModule->IsResource())
4048 dwRet |= COR_PRF_MODULE_RESOURCE;
4051 if (pModule->IsWindowsRuntimeModule())
4053 dwRet |= COR_PRF_MODULE_WINDOWS_RUNTIME;
4059 HRESULT ProfToEEInterfaceImpl::GetModuleInfo2(ModuleID moduleId,
4060 LPCBYTE * ppBaseLoadAddress,
4063 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
4064 AssemblyID * pAssemblyId,
4065 DWORD * pdwModuleFlags)
4075 // The pModule->GetScopeName() call below can result in locks getting taken to
4076 // access the metadata implementation. However, these locks do not do a mode
4084 EE_THREAD_NOT_REQUIRED;
4087 PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
4088 PRECONDITION(CheckPointer(ppBaseLoadAddress, NULL_OK));
4089 PRECONDITION(CheckPointer(pcchName, NULL_OK));
4090 PRECONDITION(CheckPointer(wszName, NULL_OK));
4091 PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
4095 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4098 "**PROF: GetModuleInfo2 0x%p.\n",
4101 if (moduleId == NULL)
4103 return E_INVALIDARG;
4106 Module * pModule = (Module *) moduleId;
4107 if (pModule->IsBeingUnloaded())
4109 return CORPROF_E_DATAINCOMPLETE;
4117 PEFile * pFile = pModule->GetFile();
4119 // Pick some safe defaults to begin with.
4120 if (ppBaseLoadAddress != NULL)
4121 *ppBaseLoadAddress = 0;
4122 if (wszName != NULL)
4124 if (pcchName != NULL)
4126 if (pAssemblyId != NULL)
4127 *pAssemblyId = PROFILER_PARENT_UNKNOWN;
4129 // Module flags can be determined first without fear of error
4130 if (pdwModuleFlags != NULL)
4131 *pdwModuleFlags = GetModuleFlags(pModule);
4133 // Get the module file name
4134 LPCWSTR wszFileName = pFile->GetPath();
4135 _ASSERTE(wszFileName != NULL);
4136 PREFIX_ASSUME(wszFileName != NULL);
4138 // If there is no filename, which is the case for RefEmit modules and for SQL
4139 // modules, then rather than returning an empty string for the name, just use the
4140 // module name from metadata (a.k.a. Module.ScopeName). This is required to
4141 // support SQL F1 sampling profiling.
4142 StackSString strScopeName;
4143 LPCUTF8 szScopeName = NULL;
4144 if ((*wszFileName == W('\0')) && SUCCEEDED(pModule->GetScopeName(&szScopeName)))
4146 strScopeName.SetUTF8(szScopeName);
4147 strScopeName.Normalize();
4148 wszFileName = strScopeName.GetUnicode();
4151 ULONG trueLen = (ULONG)(wcslen(wszFileName) + 1);
4153 // Return name of module as required.
4154 if (wszName && cchName > 0)
4156 if (cchName < trueLen)
4158 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4162 wcsncpy_s(wszName, cchName, wszFileName, trueLen);
4166 // If they request the actual length of the name
4168 *pcchName = trueLen;
4170 if (ppBaseLoadAddress != NULL && !pFile->IsDynamic())
4172 if (pModule->IsProfilerNotified())
4174 // Set the base load address -- this could be null in certain error conditions
4175 *ppBaseLoadAddress = pModule->GetProfilerBase();
4179 *ppBaseLoadAddress = NULL;
4182 if (*ppBaseLoadAddress == NULL)
4184 hr = CORPROF_E_DATAINCOMPLETE;
4188 // Return the parent assembly for this module if desired.
4189 if (pAssemblyId != NULL)
4191 // Lie and say the assembly isn't avaialable until we are loaded (even though it is.)
4192 // This is for backward compatibilty - we may want to change it
4193 if (pModule->IsProfilerNotified())
4195 Assembly *pAssembly = pModule->GetAssembly();
4196 _ASSERTE(pAssembly);
4198 *pAssemblyId = (AssemblyID) pAssembly;
4202 hr = CORPROF_E_DATAINCOMPLETE;
4206 EX_CATCH_HRESULT(hr);
4213 * Get a metadata interface instance which maps to the given module.
4214 * One may ask for the metadata to be opened in read+write mode, but
4215 * this will result in slower metadata execution of the program, because
4216 * changes made to the metadata cannot be optimized as they were from
4219 HRESULT ProfToEEInterfaceImpl::GetModuleMetaData(ModuleID moduleId,
4235 // Currently, this function is technically EE_THREAD_REQUIRED because
4236 // some functions in synch.cpp assert that there is a Thread object,
4237 // but we might be able to lift that restriction and make this be
4238 // EE_THREAD_NOT_REQUIRED.
4240 // PEFile::GetRWImporter & PEFile::GetEmitter &
4241 // GetReadablePublicMetaDataInterface take locks
4247 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
4250 "**PROF: GetModuleMetaData 0x%p, 0x%08x.\n",
4254 if (moduleId == NULL)
4256 return E_INVALIDARG;
4259 // Check for unsupported bits, and return E_INVALIDARG if present
4260 if ((dwOpenFlags & ~(ofNoTransform | ofRead | ofWrite)) != 0)
4262 return E_INVALIDARG;
4268 pModule = (Module *) moduleId;
4269 _ASSERTE(pModule != NULL);
4270 if (pModule->IsBeingUnloaded())
4272 return CORPROF_E_DATAINCOMPLETE;
4275 // Make sure we can get the importer first
4276 if (pModule->IsResource())
4283 // Decide which type of open mode we are in to see which you require.
4284 if ((dwOpenFlags & ofWrite) == 0)
4286 // Readable interface
4287 return pModule->GetReadablePublicMetaDataInterface(dwOpenFlags, riid, (LPVOID *) ppOut);
4290 // Writeable interface
4291 IUnknown *pObj = NULL;
4294 pObj = pModule->GetValidatedEmitter();
4296 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
4298 // Ask for the interface the caller wanted, only if they provide a out param
4299 if (SUCCEEDED(hr) && ppOut)
4300 hr = pObj->QueryInterface(riid, (void **) ppOut);
4307 * Retrieve a pointer to the body of a method starting at it's header.
4308 * A method is scoped by the module it lives in. Because this function
4309 * is designed to give a tool access to IL before it has been loaded
4310 * by the Runtime, it uses the metadata token of the method to find
4311 * the instance desired. Note that this function has no effect on
4312 * already compiled code.
4314 HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID moduleId,
4315 mdMethodDef methodId,
4316 LPCBYTE *ppMethodHeader,
4317 ULONG *pcbMethodSize)
4330 // PEFile::CheckLoaded & Module::GetDynamicIL both take a lock
4337 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4338 kP2EEAllowableAfterAttach,
4341 "**PROF: GetILFunctionBody 0x%p, 0x%08x.\n",
4345 Module * pModule; // Working pointer for real class.
4346 ULONG RVA; // Return RVA of the method body.
4347 DWORD dwImplFlags; // Flags for the item.
4349 if ((moduleId == NULL) ||
4350 (methodId == mdMethodDefNil) ||
4352 (TypeFromToken(methodId) != mdtMethodDef))
4354 return E_INVALIDARG;
4357 pModule = (Module *) moduleId;
4358 _ASSERTE(pModule != NULL && methodId != mdMethodDefNil);
4359 if (pModule->IsBeingUnloaded())
4361 return CORPROF_E_DATAINCOMPLETE;
4364 // Find the method body based on metadata.
4365 IMDInternalImport *pImport = pModule->GetMDImport();
4368 PEFile *pFile = pModule->GetFile();
4370 if (!pFile->CheckLoaded())
4371 return (CORPROF_E_DATAINCOMPLETE);
4373 LPCBYTE pbMethod = NULL;
4375 // Don't return rewritten IL, use the new API to get that.
4376 pbMethod = (LPCBYTE) pModule->GetDynamicIL(methodId, FALSE);
4378 // Method not overriden - get the original copy of the IL by going to metadata
4379 if (pbMethod == NULL)
4382 IfFailRet(pImport->GetMethodImplProps(methodId, &RVA, &dwImplFlags));
4384 // Check to see if the method has associated IL
4385 if ((RVA == 0 && !pFile->IsDynamic()) || !(IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags) || IsMiInternalCall(dwImplFlags)))
4387 return (CORPROF_E_FUNCTION_NOT_IL);
4392 // Get the location of the IL
4393 pbMethod = (LPCBYTE) (pModule->GetIL(RVA));
4395 EX_CATCH_HRESULT(hr);
4403 // Fill out param if provided
4405 *ppMethodHeader = pbMethod;
4407 // Calculate the size of the method itself.
4410 if (!FitsIn<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod)))
4412 return E_UNEXPECTED;
4414 *pcbMethodSize = static_cast<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod));
4419 //---------------------------------------------------------------------------------------
4420 // Retrieves an IMethodMalloc pointer around a ModuleILHeap instance that will own
4421 // allocating heap space for this module (for IL rewriting).
4424 // moduleId - ModuleID this allocator shall allocate for
4425 // ppMalloc - [out] IMethodMalloc pointer the profiler will use for allocation requests
4426 // against this module
4429 // HRESULT indicating success / failure
4432 // IL method bodies used to have the requirement that they must be referenced as
4433 // RVA's to the loaded module, which means they come after the module within
4434 // METHOD_MAX_RVA. In order to make it easier for a tool to swap out the body of
4435 // a method, this allocator will ensure memory allocated after that point.
4437 // Now that requirement is completely gone, so there's nothing terribly special
4438 // about this allocator, we just keep it around for legacy purposes.
4440 HRESULT ProfToEEInterfaceImpl::GetILFunctionBodyAllocator(ModuleID moduleId,
4441 IMethodMalloc ** ppMalloc)
4448 // ModuleILHeap::FindOrCreateHeap may take a Crst if it
4449 // needs to create a new allocator and add it to the list. Taking a crst
4450 // switches to preemptive, which is effectively a GC trigger
4457 EE_THREAD_NOT_REQUIRED;
4459 // (see GC_TRIGGERS comment)
4465 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4466 kP2EEAllowableAfterAttach | kP2EETriggers,
4469 "**PROF: GetILFunctionBodyAllocator 0x%p.\n",
4472 if ((moduleId == NULL) || (ppMalloc == NULL))
4474 return E_INVALIDARG;
4477 Module * pModule = (Module *) moduleId;
4479 if (pModule->IsBeingUnloaded() ||
4480 !pModule->GetFile()->CheckLoaded())
4482 return (CORPROF_E_DATAINCOMPLETE);
4485 *ppMalloc = &ModuleILHeap::s_Heap;
4490 * Replaces the method body for a function in a module. This will replace
4491 * the RVA of the method in the metadata to point to this new method body,
4492 * and adjust any internal data structures as required. This function can
4493 * only be called on those methods which have never been compiled by a JITTER.
4494 * Please use the GetILFunctionBodyAllocator to allocate space for the new method to
4495 * ensure the buffer is compatible.
4497 HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId,
4498 mdMethodDef methodId,
4499 LPCBYTE pbNewILMethodHeader)
4503 // PEFile::GetEmitter, Module::SetDynamicIL all throw
4506 // Locks are taken (see CAN_TAKE_LOCK below), which may cause mode switch to
4507 // preemptive, which is triggers.
4513 // Module::SetDynamicIL & PEFile::CheckLoaded & PEFile::GetEmitter take locks
4519 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4520 kP2EEAllowableAfterAttach | kP2EETriggers,
4523 "**PROF: SetILFunctionBody 0x%p, 0x%08x.\n",
4527 if ((moduleId == NULL) ||
4528 (methodId == mdMethodDefNil) ||
4529 (TypeFromToken(methodId) != mdtMethodDef) ||
4530 (pbNewILMethodHeader == NULL))
4532 return E_INVALIDARG;
4535 Module *pModule; // Working pointer for real class.
4538 // Cannot set the body for anything other than a method def
4539 if (TypeFromToken(methodId) != mdtMethodDef)
4540 return (E_INVALIDARG);
4542 // Cast module to appropriate type
4543 pModule = (Module *) moduleId;
4544 _ASSERTE (pModule != NULL); // Enforced in CorProfInfo::SetILFunctionBody
4545 if (pModule->IsBeingUnloaded())
4547 return CORPROF_E_DATAINCOMPLETE;
4550 // Remember the profiler is doing this, as that means we must never detach it!
4551 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
4553 // This action is not temporary!
4554 // If the profiler want to be able to revert, they need to use
4555 // the new ReJIT APIs.
4556 pModule->SetDynamicIL(methodId, (TADDR)pbNewILMethodHeader, FALSE);
4562 * Sets the codemap for the replaced IL function body
4564 HRESULT ProfToEEInterfaceImpl::SetILInstrumentedCodeMap(FunctionID functionId,
4566 ULONG cILMapEntries,
4567 COR_IL_MAP rgILMapEntries[])
4571 // Debugger::SetILInstrumentedCodeMap throws
4574 // Debugger::SetILInstrumentedCodeMap triggers
4581 EE_THREAD_NOT_REQUIRED;
4583 // Debugger::SetILInstrumentedCodeMap takes a lock when it calls Debugger::GetOrCreateMethodInfo
4589 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4590 kP2EEAllowableAfterAttach | kP2EETriggers,
4593 "**PROF: SetILInstrumentedCodeMap 0x%p, %d.\n",
4597 if (functionId == NULL)
4599 return E_INVALIDARG;
4602 if (cILMapEntries >= (MAXULONG / sizeof(COR_IL_MAP)))
4604 // Too big! The allocation below would overflow when calculating the size.
4605 return E_INVALIDARG;
4609 #ifdef DEBUGGING_SUPPORTED
4611 MethodDesc *pMethodDesc = FunctionIdToMethodDesc(functionId);
4613 // it's not safe to examine a methoddesc that has not been restored so do not do so
4614 if (!pMethodDesc ->IsRestored())
4615 return CORPROF_E_DATAINCOMPLETE;
4617 if (g_pDebugInterface == NULL)
4619 return CORPROF_E_DEBUGGING_DISABLED;
4622 COR_IL_MAP * rgNewILMapEntries = new (nothrow) COR_IL_MAP[cILMapEntries];
4624 if (rgNewILMapEntries == NULL)
4625 return E_OUTOFMEMORY;
4627 memcpy_s(rgNewILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries, rgILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries);
4629 return g_pDebugInterface->SetILInstrumentedCodeMap(pMethodDesc,
4634 #else //DEBUGGING_SUPPORTED
4636 #endif //DEBUGGING_SUPPORTED
4639 HRESULT ProfToEEInterfaceImpl::ForceGC()
4643 // GC calls "new" which throws
4646 // Uh duh, look at the name of the function, dude
4653 EE_THREAD_NOT_REQUIRED;
4655 // Initiating a GC causes a runtime suspension which requires the
4656 // mother of all locks: the thread store lock.
4662 ASSERT_NO_EE_LOCKS_HELD();
4664 // We need to use IsGarbageCollectorFullyInitialized() instead of IsGCHeapInitialized() because
4665 // there are other GC initialization being done after IsGCHeapInitialized() becomes TRUE,
4666 // and before IsGarbageCollectorFullyInitialized() becomes TRUE.
4667 if (!IsGarbageCollectorFullyInitialized())
4669 return CORPROF_E_NOT_YET_AVAILABLE;
4672 // Disallow the cases where a profiler calls this off a hijacked CLR thread
4673 // or inside a profiler callback. (Allow cases where this is a native thread, or a
4674 // thread which previously successfully called ForceGC.)
4675 Thread * pThread = GetThreadNULLOk();
4676 if ((pThread != NULL) &&
4677 (!AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED)) &&
4678 (pThread->GetFrame() != FRAME_TOP
4679 || AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_INCALLBACK)))
4683 "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE "
4684 "due to illegal hijacked profiler call or call from inside another callback\n"));
4685 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
4688 // NOTE: We cannot use the standard macro PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX
4689 // here because the macro ensures that either the current thread is not an
4690 // EE thread, or, if it is, that the CALLBACK flag is set. In classic apps
4691 // a profiler-owned native thread will not get an EE thread associated with
4692 // it, however, in AppX apps, during the first call into the GC on a
4693 // profiler-owned thread, the EE will associate an EE-thread with the profiler
4694 // thread. As a consequence the second call to ForceGC on the same thread
4695 // would fail, since this is now an EE thread and this API is not called from
4698 // First part of the PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX macro:
4699 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4700 kP2EEAllowableAfterAttach | kP2EETriggers,
4703 "**PROF: ForceGC.\n"));
4705 #ifdef FEATURE_EVENT_TRACE
4706 // This helper, used by ETW and profAPI ensures a managed thread gets created for
4707 // this thread before forcing the GC (to work around Jupiter issues where it's
4708 // expected this thread is already managed before starting the GC).
4709 HRESULT hr = ETW::GCLog::ForceGCForDiagnostics();
4710 #else // !FEATURE_EVENT_TRACE
4711 HRESULT hr = E_FAIL;
4712 #endif // FEATURE_EVENT_TRACE
4714 // If a Thread object was just created for this thread, remember the fact that it
4715 // was a ForceGC() thread, so we can be more lenient when doing
4716 // COR_PRF_CALLBACKSTATE_INCALLBACK later on from other APIs
4717 pThread = GetThreadNULLOk();
4718 if (pThread != NULL)
4720 pThread->SetProfilerCallbackStateFlags(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED);
4728 * Returns the ContextID for the current thread.
4730 HRESULT ProfToEEInterfaceImpl::GetThreadContext(ThreadID threadId,
4731 ContextID *pContextId)
4745 EE_THREAD_NOT_REQUIRED;
4753 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4756 "**PROF: GetThreadContext 0x%p.\n",
4759 if (!IsManagedThread(threadId))
4761 return E_INVALIDARG;
4764 // Cast to right type
4765 Thread *pThread = reinterpret_cast<Thread *>(threadId);
4767 // Get the context for the Thread* provided
4768 AppDomain *pContext = pThread->GetDomain(); // Context is same as AppDomain in CoreCLR
4771 // If there's no current context, return incomplete info
4773 return (CORPROF_E_DATAINCOMPLETE);
4775 // Set the result and return
4777 *pContextId = reinterpret_cast<ContextID>(pContext);
4782 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo(ClassID classId,
4783 ModuleID *pModuleId,
4784 mdTypeDef *pTypeDefToken)
4798 EE_THREAD_NOT_REQUIRED;
4806 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4809 "**PROF: GetClassIDInfo 0x%p.\n",
4812 if (classId == NULL)
4814 return E_INVALIDARG;
4817 if (pModuleId != NULL)
4822 if (pTypeDefToken != NULL)
4824 *pTypeDefToken = NULL;
4827 // Handle globals which don't have the instances.
4828 if (classId == PROFILER_GLOBAL_CLASS)
4830 if (pModuleId != NULL)
4832 *pModuleId = PROFILER_GLOBAL_MODULE;
4835 if (pTypeDefToken != NULL)
4837 *pTypeDefToken = mdTokenNil;
4840 else if (classId == NULL)
4842 return E_INVALIDARG;
4844 // Get specific data.
4847 TypeHandle th = TypeHandle::FromPtr((void *)classId);
4849 if (!th.IsTypeDesc())
4854 // If this class is not fully restored, that is all the information we can get at this time.
4856 if (!th.IsRestored())
4858 return CORPROF_E_DATAINCOMPLETE;
4861 if (pModuleId != NULL)
4863 *pModuleId = (ModuleID) th.GetModule();
4864 _ASSERTE(*pModuleId != NULL);
4867 if (pTypeDefToken != NULL)
4869 *pTypeDefToken = th.GetCl();
4870 _ASSERTE(*pTypeDefToken != NULL);
4880 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo(FunctionID functionId,
4882 ModuleID *pModuleId,
4897 EE_THREAD_NOT_REQUIRED;
4905 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4908 "**PROF: GetFunctionInfo 0x%p.\n",
4911 if (functionId == NULL)
4913 return E_INVALIDARG;
4916 MethodDesc *pMDesc = (MethodDesc *) functionId;
4917 if (!pMDesc->IsRestored())
4919 return CORPROF_E_DATAINCOMPLETE;
4922 MethodTable *pMT = pMDesc->GetMethodTable();
4923 if (!pMT->IsRestored())
4925 return CORPROF_E_DATAINCOMPLETE;
4928 ClassID classId = PROFILER_GLOBAL_CLASS;
4932 classId = NonGenericTypeHandleToClassID(TypeHandle(pMT));
4935 if (pClassId != NULL)
4937 *pClassId = classId;
4940 if (pModuleId != NULL)
4942 *pModuleId = (ModuleID) pMDesc->GetModule();
4947 *pToken = pMDesc->GetMemberDef();
4954 * GetILToNativeMapping returns a map from IL offsets to native
4955 * offsets for this code. An array of COR_DEBUG_IL_TO_NATIVE_MAP
4956 * structs will be returned, and some of the ilOffsets in this array
4957 * may be the values specified in CorDebugIlToNativeMappingTypes.
4959 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping(FunctionID functionId,
4961 ULONG32 * pcMap, // [out]
4962 COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
4966 // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
4969 // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
4970 // called from here. Since the profiler has a valid functionId, the methoddesc for
4971 // this code will already have been created. We should be able to enforce this by
4972 // passing allowCreate=FALSE to FindOrCreateTypicalSharedInstantiation.
4973 DISABLED(GC_NOTRIGGER);
4978 // The call to g_pDebugInterface->GetILToNativeMapping() below may call
4979 // Debugger::AcquireDebuggerLock
4985 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
4988 "**PROF: GetILToNativeMapping 0x%p.\n",
4991 return GetILToNativeMapping2(functionId, 0, cMap, pcMap, map);
4994 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId,
4997 ULONG32 * pcMap, // [out]
4998 COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
5002 // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
5005 // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
5006 // called from here. Since the profiler has a valid functionId, the methoddesc for
5007 // this code will already have been created. We should be able to enforce this by
5008 // passing allowCreate=FALSE to FindOrCreateTypicalSharedInstantiation.
5009 DISABLED(GC_NOTRIGGER);
5014 // The call to g_pDebugInterface->GetILToNativeMapping() below may call
5015 // Debugger::AcquireDebuggerLock
5021 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5024 "**PROF: GetILToNativeMapping2 0x%p 0x%p.\n",
5025 functionId, reJitId));
5027 if (functionId == NULL)
5029 return E_INVALIDARG;
5033 ((pcMap == NULL) || (map == NULL)))
5035 return E_INVALIDARG;
5042 // Cast to proper type
5043 MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
5045 if (pMD->HasClassOrMethodInstantiation() && pMD->IsTypicalMethodDefinition())
5047 // In this case, we used to replace pMD with its canonical instantiation
5048 // (FindOrCreateTypicalSharedInstantiation). However, a profiler should never be able
5049 // to get to this point anyway, since any MethodDesc a profiler gets from us
5050 // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
5051 // We assert here just in case a test proves me wrong, but generally we will
5052 // disallow this code path.
5053 _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetILToNativeMapping2");
5058 PCODE pCodeStart = NULL;
5059 CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
5060 ILCodeVersion ilCodeVersion = NULL;
5062 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
5064 pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
5066 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
5067 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
5069 // Now that tiered compilation can create more than one jitted code version for the same rejit id
5070 // we are arbitrarily choosing the first one to return. To address a specific version of native code
5071 // use GetILToNativeMapping3.
5072 pCodeStart = iter->GetNativeCode();
5077 hr = GetILToNativeMapping3(pCodeStart, cMap, pcMap, map);
5080 EX_CATCH_HRESULT(hr);
5087 //*****************************************************************************
5088 // Given an ObjectID, go get the EE ClassID for it.
5089 //*****************************************************************************
5090 HRESULT ProfToEEInterfaceImpl::GetClassFromObject(ObjectID objectId,
5101 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
5104 // Object::GetTypeHandle takes a lock
5110 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5113 "**PROF: GetClassFromObject 0x%p.\n",
5116 if (objectId == NULL)
5118 return E_INVALIDARG;
5121 HRESULT hr = AllowObjectInspection();
5127 // Cast the ObjectID as a Object
5128 Object *pObj = reinterpret_cast<Object *>(objectId);
5130 // Set the out param and indicate success
5131 // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
5134 *pClassId = SafeGetClassIDFromObject(pObj);
5140 //*****************************************************************************
5141 // Given a module and a token for a class, go get the EE data structure for it.
5142 //*****************************************************************************
5143 HRESULT ProfToEEInterfaceImpl::GetClassFromToken(ModuleID moduleId,
5152 // ClassLoader::LoadTypeDefOrRefThrowing triggers
5158 // ClassLoader::LoadTypeDefOrRefThrowing takes a lock
5164 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5165 kP2EEAllowableAfterAttach | kP2EETriggers,
5168 "**PROF: GetClassFromToken 0x%p, 0x%08x.\n",
5172 if ((moduleId == NULL) || (typeDef == mdTypeDefNil) || (typeDef == NULL))
5174 return E_INVALIDARG;
5177 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5179 return CORPROF_E_RUNTIME_UNINITIALIZED;
5183 Module *pModule = (Module *) moduleId;
5185 // No module, or it's disassociated from metadata
5186 if ((pModule == NULL) || (pModule->IsBeingUnloaded()))
5188 return CORPROF_E_DATAINCOMPLETE;
5191 // First, check the RID map. This is important since it
5192 // works during teardown (and the below doesn't)
5194 th = pModule->LookupTypeDef(typeDef);
5200 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, typeDef,
5201 ClassLoader::ThrowIfNotFound,
5202 ClassLoader::PermitUninstDefOrRef);
5204 EX_CATCH_HRESULT(hr);
5212 if (!th.GetMethodTable())
5214 return CORPROF_E_DATAINCOMPLETE;
5218 // Check if it is generic
5220 ClassID classId = NonGenericTypeHandleToClassID(th);
5222 if (classId == NULL)
5224 return CORPROF_E_TYPE_IS_PARAMETERIZED;
5227 // Return value if necessary
5230 *pClassId = classId;
5237 HRESULT ProfToEEInterfaceImpl::GetClassFromTokenAndTypeArgs(ModuleID moduleID,
5248 // LoadGenericInstantiationThrowing may load
5254 // ClassLoader::LoadGenericInstantiationThrowing takes a lock
5260 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5261 kP2EEAllowableAfterAttach | kP2EETriggers,
5264 "**PROF: GetClassFromTokenAndTypeArgs 0x%p, 0x%08x.\n",
5268 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5270 return CORPROF_E_RUNTIME_UNINITIALIZED;
5273 Module* pModule = reinterpret_cast< Module* >(moduleID);
5275 if (pModule == NULL || pModule->IsBeingUnloaded())
5277 return CORPROF_E_DATAINCOMPLETE;
5280 // This array needs to be accessible at least until the call to
5281 // ClassLoader::LoadGenericInstantiationThrowing
5282 TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5283 NewArrayHolder< TypeHandle > holder(genericParameters);
5285 if (NULL == genericParameters)
5287 return E_OUTOFMEMORY;
5290 for (ULONG32 i = 0; i < cTypeArgs; ++i)
5292 genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5296 // nickbe 11/24/2003 10:12:56
5298 // In RTM/Everett we decided to load the class if it hadn't been loaded yet
5299 // (see ProfToEEInterfaceImpl::GetClassFromToken). For compatibility we're
5300 // going to make the same decision here. It's potentially confusing to tell
5301 // someone a type doesn't exist at one point in time, but does exist later,
5302 // and there is no good way for us to determing that a class may eventually
5303 // be loaded without going ahead and loading it
5310 // Not sure if this is a valid override or not - making this a VIOLATION
5311 // until we're sure.
5312 CONTRACT_VIOLATION(LoadsTypeViolation);
5314 if (GetThreadNULLOk() == NULL)
5316 // Type system will try to validate as part of its contract if the current
5317 // AppDomain returned by GetAppDomain can load types in specified module's
5318 // assembly. On a non-EE thread it results in an AV in a check build
5319 // since the type system tries to dereference NULL returned by GetAppDomain.
5320 // More importantly, loading a type on a non-EE thread is not allowed.
5322 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE() states that callers will not
5323 // try to load a type, so that type system will not try to test type
5324 // loadability in the current AppDomain. However,
5325 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE does not prevent callers from
5326 // loading a type. It is profiler's responsibility not to attempt to load
5327 // a type in unsupported ways (e.g. from a non-EE thread). It doesn't
5328 // impact retail builds, in which contracts are not available.
5329 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5331 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE also defines FAULT_FORBID, which
5332 // causes Scanruntime to flag a fault violation in AssemblySpec::InitializeSpec,
5333 // which is defined as FAULTS. It only happens in a type-loading path, which
5334 // is not supported on a non-EE thread. Suppressing a contract violation in an
5335 // unsupported execution path is more preferable than causing AV when calling
5336 // GetClassFromTokenAndTypeArgs on a non-EE thread in a check build. See Dev10
5337 // 682526 for more details.
5340 th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5342 Instantiation(genericParameters, cTypeArgs),
5343 ClassLoader::LoadTypes);
5347 th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5349 Instantiation(genericParameters, cTypeArgs),
5350 ClassLoader::LoadTypes);
5353 EX_CATCH_HRESULT(hr);
5362 // Hmm, the type isn't loaded yet.
5363 return CORPROF_E_DATAINCOMPLETE;
5366 *pClassID = TypeHandleToClassID(th);
5371 //*****************************************************************************
5372 // Given the token for a method, return the fucntion id.
5373 //*****************************************************************************
5374 HRESULT ProfToEEInterfaceImpl::GetFunctionFromToken(ModuleID moduleId,
5376 FunctionID *pFunctionId)
5390 EE_THREAD_NOT_REQUIRED;
5398 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5401 "**PROF: GetFunctionFromToken 0x%p, 0x%08x.\n",
5405 if ((moduleId == NULL) || (typeDef == mdTokenNil))
5407 return E_INVALIDARG;
5410 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5412 return CORPROF_E_RUNTIME_UNINITIALIZED;
5419 Module *pModule = (Module *) moduleId;
5421 // No module, or disassociated from metadata
5422 if (pModule == NULL || pModule->IsBeingUnloaded())
5424 return CORPROF_E_DATAINCOMPLETE;
5427 // Default return value of NULL
5428 MethodDesc *pDesc = NULL;
5430 // Different lookup depending on whether it's a Def or Ref
5431 if (TypeFromToken(typeDef) == mdtMethodDef)
5433 pDesc = pModule->LookupMethodDef(typeDef);
5435 else if (TypeFromToken(typeDef) == mdtMemberRef)
5437 pDesc = pModule->LookupMemberRefAsMethod(typeDef);
5441 return E_INVALIDARG;
5446 return E_INVALIDARG;
5450 // Check that this is a non-generic method
5452 if (pDesc->HasClassOrMethodInstantiation())
5454 return CORPROF_E_FUNCTION_IS_PARAMETERIZED;
5457 if (pFunctionId && SUCCEEDED(hr))
5459 *pFunctionId = MethodDescToFunctionID(pDesc);
5465 HRESULT ProfToEEInterfaceImpl::GetFunctionFromTokenAndTypeArgs(ModuleID moduleID,
5466 mdMethodDef funcDef,
5470 FunctionID* pFunctionID)
5477 // It can trigger type loads
5483 // MethodDesc::FindOrCreateAssociatedMethodDesc enters a Crst
5489 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5490 kP2EEAllowableAfterAttach | kP2EETriggers,
5493 "**PROF: GetFunctionFromTokenAndTypeArgs 0x%p, 0x%08x, 0x%p.\n",
5498 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
5499 Module* pModule = reinterpret_cast< Module* >(moduleID);
5501 if ((pModule == NULL) || typeHandle.IsNull())
5503 return E_INVALIDARG;
5506 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5508 return CORPROF_E_RUNTIME_UNINITIALIZED;
5511 if (pModule->IsBeingUnloaded())
5513 return CORPROF_E_DATAINCOMPLETE;
5516 MethodDesc* pMethodDesc = NULL;
5518 if (mdtMethodDef == TypeFromToken(funcDef))
5520 pMethodDesc = pModule->LookupMethodDef(funcDef);
5522 else if (mdtMemberRef == TypeFromToken(funcDef))
5524 pMethodDesc = pModule->LookupMemberRefAsMethod(funcDef);
5528 return E_INVALIDARG;
5531 MethodTable* pMethodTable = typeHandle.GetMethodTable();
5533 if (pMethodTable == NULL || !pMethodTable->IsRestored() ||
5534 pMethodDesc == NULL || !pMethodDesc->IsRestored())
5536 return CORPROF_E_DATAINCOMPLETE;
5539 // This array needs to be accessible at least until the call to
5540 // MethodDesc::FindOrCreateAssociatedMethodDesc
5541 TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5542 NewArrayHolder< TypeHandle > holder(genericParameters);
5544 if (NULL == genericParameters)
5546 return E_OUTOFMEMORY;
5549 for (ULONG32 i = 0; i < cTypeArgs; ++i)
5551 genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5554 MethodDesc* result = NULL;
5559 result = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethodDesc,
5562 Instantiation(genericParameters, cTypeArgs),
5565 EX_CATCH_HRESULT(hr);
5569 *pFunctionID = MethodDescToFunctionID(result);
5575 //*****************************************************************************
5576 // Retrieve information about a given application domain, which is like a
5578 //*****************************************************************************
5579 HRESULT ProfToEEInterfaceImpl::GetAppDomainInfo(AppDomainID appDomainId,
5582 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5583 ProcessID *pProcessId)
5590 // AppDomain::GetFriendlyNameForDebugger triggers
5596 // AppDomain::GetFriendlyNameForDebugger takes a lock
5602 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5603 kP2EEAllowableAfterAttach | kP2EETriggers,
5606 "**PROF: GetAppDomainInfo 0x%p.\n",
5609 if (appDomainId == NULL)
5611 return E_INVALIDARG;
5614 BaseDomain *pDomain; // Internal data structure.
5618 // Right now, this ID is not a true AppDomain, since we use the old
5619 // AppDomain/SystemDomain model in the profiling API. This means that
5620 // the profiler exposes the SharedDomain and the SystemDomain to the
5621 // outside world. It's not clear whether this is actually the right thing
5622 // to do or not. - seantrow
5627 pDomain = (BaseDomain *) appDomainId;
5629 // Make sure they've passed in a valid appDomainId
5630 if (pDomain == NULL)
5631 return (E_INVALIDARG);
5633 // Pick sensible defaults.
5641 LPCWSTR szFriendlyName;
5642 if (pDomain == SystemDomain::System())
5643 szFriendlyName = g_pwBaseLibrary;
5645 szFriendlyName = ((AppDomain*)pDomain)->GetFriendlyNameForDebugger();
5647 if (szFriendlyName != NULL)
5649 // Get the module file name
5650 ULONG trueLen = (ULONG)(wcslen(szFriendlyName) + 1);
5652 // Return name of module as required.
5653 if (szName && cchName > 0)
5655 ULONG copyLen = trueLen;
5657 if (copyLen >= cchName)
5659 copyLen = cchName - 1;
5662 wcsncpy_s(szName, cchName, szFriendlyName, copyLen);
5665 // If they request the actual length of the name
5667 *pcchName = trueLen;
5670 // If we don't have a friendly name but the call was requesting it, then return incomplete data HR
5673 if ((szName != NULL && cchName > 0) || pcchName)
5674 hr = CORPROF_E_DATAINCOMPLETE;
5678 *pProcessId = (ProcessID) GetCurrentProcessId();
5684 //*****************************************************************************
5685 // Retrieve information about an assembly, which is a collection of dll's.
5686 //*****************************************************************************
5687 HRESULT ProfToEEInterfaceImpl::GetAssemblyInfo(AssemblyID assemblyId,
5690 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5691 AppDomainID *pAppDomainId,
5692 ModuleID *pModuleId)
5696 // SString::SString throws
5706 EE_THREAD_NOT_REQUIRED;
5708 // PEAssembly::GetSimpleName() enters a lock via use of the metadata interface
5714 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5717 "**PROF: GetAssemblyInfo 0x%p.\n",
5720 if (assemblyId == NULL)
5722 return E_INVALIDARG;
5727 Assembly *pAssembly; // Internal data structure for assembly.
5729 pAssembly = (Assembly *) assemblyId;
5730 _ASSERTE(pAssembly != NULL);
5732 if (pcchName || szName)
5734 // Get the friendly name of the assembly
5735 SString name(SString::Utf8, pAssembly->GetSimpleName());
5737 const COUNT_T nameLength = name.GetCount() + 1;
5739 if ((NULL != szName) && (cchName > 0))
5741 wcsncpy_s(szName, cchName, name.GetUnicode(), min(nameLength, cchName - 1));
5744 if (NULL != pcchName)
5746 *pcchName = nameLength;
5750 // Get the parent application domain.
5753 *pAppDomainId = (AppDomainID) pAssembly->GetDomain();
5754 _ASSERTE(*pAppDomainId != NULL);
5757 // Find the module the manifest lives in.
5760 *pModuleId = (ModuleID) pAssembly->GetManifestModule();
5762 // This is the case where the profiler has called GetAssemblyInfo
5763 // on an assembly that has been completely created yet.
5765 hr = CORPROF_E_DATAINCOMPLETE;
5771 // Setting ELT hooks is only allowed from within Initialize(). However, test-only
5772 // profilers may need to set those hooks from an attaching profiling. See
5773 // code:ProfControlBlock#TestOnlyELT
5774 #ifdef PROF_TEST_ONLY_FORCE_ELT
5775 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT(logParams) \
5778 if (g_profControlBlock.fTestOnlyForceEnterLeave) \
5780 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, logParams); \
5784 PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams); \
5787 #else // PROF_TEST_ONLY_FORCE_ELT
5788 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT \
5789 PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY
5790 #endif // PROF_TEST_ONLY_FORCE_ELT
5793 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
5794 FunctionLeave * pFuncLeave,
5795 FunctionTailcall * pFuncTailcall)
5809 EE_THREAD_NOT_REQUIRED;
5816 // The profiler must call SetEnterLeaveFunctionHooks during initialization, since
5817 // the enter/leave events are immutable and must also be set during initialization.
5818 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5820 "**PROF: SetEnterLeaveFunctionHooks 0x%p, 0x%p, 0x%p.\n",
5825 return g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall);
5829 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
5830 FunctionLeave2 * pFuncLeave,
5831 FunctionTailcall2 * pFuncTailcall)
5845 EE_THREAD_NOT_REQUIRED;
5852 // The profiler must call SetEnterLeaveFunctionHooks2 during initialization, since
5853 // the enter/leave events are immutable and must also be set during initialization.
5854 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5856 "**PROF: SetEnterLeaveFunctionHooks2 0x%p, 0x%p, 0x%p.\n",
5862 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall);
5866 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
5867 FunctionLeave3 * pFuncLeave3,
5868 FunctionTailcall3 * pFuncTailcall3)
5882 EE_THREAD_NOT_REQUIRED;
5889 // The profiler must call SetEnterLeaveFunctionHooks3 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: SetEnterLeaveFunctionHooks3 0x%p, 0x%p, 0x%p.\n",
5899 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3,
5906 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
5907 FunctionLeave3WithInfo * pFuncLeave3WithInfo,
5908 FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
5922 EE_THREAD_NOT_REQUIRED;
5929 // The profiler must call SetEnterLeaveFunctionHooks3WithInfo during initialization, since
5930 // the enter/leave events are immutable and must also be set during initialization.
5931 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5933 "**PROF: SetEnterLeaveFunctionHooks3WithInfo 0x%p, 0x%p, 0x%p.\n",
5934 pFuncEnter3WithInfo,
5935 pFuncLeave3WithInfo,
5936 pFuncTailcall3WithInfo));
5939 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo,
5940 pFuncLeave3WithInfo,
5941 pFuncTailcall3WithInfo);
5945 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper(FunctionIDMapper *pFunc)
5959 EE_THREAD_NOT_REQUIRED;
5967 PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF,
5969 "**PROF: SetFunctionIDMapper 0x%p.\n",
5972 g_profControlBlock.pProfInterface->SetFunctionIDMapper(pFunc);
5977 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper2(FunctionIDMapper2 *pFunc, void * clientData)
5991 EE_THREAD_NOT_REQUIRED;
5999 PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF,
6001 "**PROF: SetFunctionIDMapper2. pFunc: 0x%p. clientData: 0x%p.\n",
6005 g_profControlBlock.pProfInterface->SetFunctionIDMapper2(pFunc, clientData);
6013 * This function takes the frameInfo returned from a profiler callback and splays it
6014 * out into as much information as possible.
6017 * funcId - The function that is being requested.
6018 * frameInfo - Frame specific information from a callback (for resolving generics).
6019 * pClassId - An optional parameter for returning the class id of the function.
6020 * pModuleId - An optional parameter for returning the module of the function.
6021 * pToken - An optional parameter for returning the metadata token of the function.
6022 * cTypeArgs - The count of the size of the array typeArgs
6023 * pcTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
6024 * the number that would be needed.
6025 * typeArgs - An array to store generic type parameters for the function.
6028 * S_OK if successful.
6030 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo2(FunctionID funcId,
6031 COR_PRF_FRAME_INFO frameInfo,
6033 ModuleID *pModuleId,
6036 ULONG32 *pcTypeArgs,
6051 EE_THREAD_NOT_REQUIRED;
6053 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6054 // reads metadata which causes us to take a reader lock. However, see
6055 // code:#DisableLockOnAsyncCalls
6056 DISABLED(CAN_TAKE_LOCK);
6058 // Asynchronous functions can be called at arbitrary times when runtime
6059 // is holding locks that cannot be reentered without causing deadlock.
6060 // This contract detects any attempts to reenter locks held at the time
6061 // this function was called.
6065 PRECONDITION(CheckPointer(pClassId, NULL_OK));
6066 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6067 PRECONDITION(CheckPointer(pToken, NULL_OK));
6068 PRECONDITION(CheckPointer(pcTypeArgs, NULL_OK));
6069 PRECONDITION(CheckPointer(typeArgs, NULL_OK));
6073 // See code:#DisableLockOnAsyncCalls
6074 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6076 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6079 "**PROF: GetFunctionInfo2 0x%p.\n",
6083 // Verify parameters.
6085 COR_PRF_FRAME_INFO_INTERNAL *pFrameInfo = (COR_PRF_FRAME_INFO_INTERNAL *)frameInfo;
6087 if ((funcId == NULL) ||
6088 ((pFrameInfo != NULL) && (pFrameInfo->funcID != funcId)))
6090 return E_INVALIDARG;
6093 MethodDesc *pMethDesc = FunctionIdToMethodDesc(funcId);
6095 if (pMethDesc == NULL)
6097 return E_INVALIDARG;
6100 if ((cTypeArgs != 0) && (typeArgs == NULL))
6102 return E_INVALIDARG;
6105 // it's not safe to examine a methoddesc that has not been restored so do not do so
6106 if (!pMethDesc ->IsRestored())
6107 return CORPROF_E_DATAINCOMPLETE;
6110 // Find the exact instantiation of this function.
6112 TypeHandle specificClass;
6113 MethodDesc* pActualMethod;
6115 ClassID classId = NULL;
6117 if (pMethDesc->IsSharedByGenericInstantiations())
6120 OBJECTREF pThis = NULL;
6122 if (pFrameInfo != NULL)
6124 // If FunctionID represents a generic methoddesc on a struct, then pFrameInfo->thisArg
6125 // isn't an Object*. It's a pointer directly into the struct's members (i.e., it's not pointing at the
6126 // method table). That means pFrameInfo->thisArg cannot be casted to an OBJECTREF for
6127 // use by Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation. However,
6128 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation won't even need a this pointer
6129 // for the methoddesc it's processing if the methoddesc is on a value type. So we
6130 // can safely pass NULL for the methoddesc's this in such a case.
6131 if (pMethDesc->GetMethodTable()->IsValueType())
6133 _ASSERTE(!pMethDesc->AcquiresInstMethodTableFromThis());
6134 _ASSERTE(pThis == NULL);
6138 pThis = ObjectToOBJECTREF((PTR_Object)(pFrameInfo->thisArg));
6142 exactMatch = Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
6145 PTR_VOID((pFrameInfo != NULL) ? pFrameInfo->extraArg : NULL),
6151 classId = TypeHandleToClassID(specificClass);
6153 else if (!specificClass.HasInstantiation() || !specificClass.IsSharedByGenericInstantiations())
6156 // In this case we could not get the type args for the method, but if the class
6157 // is not a generic class or is instantiated with value types, this value is correct.
6159 classId = TypeHandleToClassID(specificClass);
6164 // We could not get any class information.
6171 TypeHandle typeHandle(pMethDesc->GetMethodTable());
6172 classId = TypeHandleToClassID(typeHandle);
6173 pActualMethod = pMethDesc;
6178 // Fill in the ClassId, if desired
6180 if (pClassId != NULL)
6182 *pClassId = classId;
6186 // Fill in the ModuleId, if desired.
6188 if (pModuleId != NULL)
6190 *pModuleId = (ModuleID)pMethDesc->GetModule();
6194 // Fill in the token, if desired.
6198 *pToken = (mdToken)pMethDesc->GetMemberDef();
6201 if ((cTypeArgs == 0) && (pcTypeArgs != NULL))
6204 // They are searching for the size of the array needed, we can return that now and
6205 // short-circuit all the work below.
6207 if (pcTypeArgs != NULL)
6209 *pcTypeArgs = pActualMethod->GetNumGenericMethodArgs();
6215 // If no place to store resulting count, quit now.
6217 if (pcTypeArgs == NULL)
6223 // Fill in the type args
6225 DWORD cArgsToFill = pActualMethod->GetNumGenericMethodArgs();
6227 if (cArgsToFill > cTypeArgs)
6229 cArgsToFill = cTypeArgs;
6232 *pcTypeArgs = cArgsToFill;
6234 if (cArgsToFill == 0)
6239 Instantiation inst = pActualMethod->GetMethodInstantiation();
6241 for (DWORD i = 0; i < cArgsToFill; i++)
6243 typeArgs[i] = TypeHandleToClassID(inst[i]);
6252 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6253 * or LCG method and returns true in the pHasNoMetadata if it is indeed a metadata-less
6257 * functionId - The function that is being requested.
6258 * isDynamic - An optional parameter for returning if the function has metadata or not.
6261 * S_OK if successful.
6263 HRESULT ProfToEEInterfaceImpl::IsFunctionDynamic(FunctionID functionId, BOOL *isDynamic)
6270 EE_THREAD_NOT_REQUIRED;
6272 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6273 // reads metadata which causes us to take a reader lock. However, see
6274 // code:#DisableLockOnAsyncCalls
6275 DISABLED(CAN_TAKE_LOCK);
6277 // Asynchronous functions can be called at arbitrary times when runtime
6278 // is holding locks that cannot be reentered without causing deadlock.
6279 // This contract detects any attempts to reenter locks held at the time
6280 // this function was called.
6284 PRECONDITION(CheckPointer(isDynamic, NULL_OK));
6288 // See code:#DisableLockOnAsyncCalls
6289 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6291 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6294 "**PROF: IsFunctionDynamic 0x%p.\n",
6298 // Verify parameters.
6301 if (functionId == NULL)
6303 return E_INVALIDARG;
6306 MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6308 if (pMethDesc == NULL)
6310 return E_INVALIDARG;
6313 // it's not safe to examine a methoddesc that has not been restored so do not do so
6314 if (!pMethDesc->IsRestored())
6315 return CORPROF_E_DATAINCOMPLETE;
6318 // Fill in the pHasNoMetadata, if desired.
6320 if (isDynamic != NULL)
6322 *isDynamic = pMethDesc->IsNoMetadata();
6329 * GetFunctionFromIP3
6331 * This function takes an IP and determines if it is a managed function returning its
6332 * FunctionID. This method is different from GetFunctionFromIP in that will return
6333 * FunctionIDs even if they have no associated metadata.
6336 * ip - The instruction pointer.
6337 * pFunctionId - An optional parameter for returning the FunctionID.
6338 * pReJitId - The ReJIT id.
6341 * S_OK if successful.
6343 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP3(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
6349 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6350 // which can switch us to preemptive mode and trigger GCs
6353 EE_THREAD_NOT_REQUIRED;
6355 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6361 // See code:#DisableLockOnAsyncCalls
6362 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6364 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6365 kP2EEAllowableAfterAttach | kP2EETriggers,
6368 "**PROF: GetFunctionFromIP3 0x%p.\n",
6373 EECodeInfo codeInfo;
6375 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ FALSE);
6383 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
6386 if (pReJitId != NULL)
6388 MethodDesc * pMD = codeInfo.GetMethodDesc();
6389 *pReJitId = ReJitManager::GetReJitId(pMD, codeInfo.GetStartAddress());
6396 * GetDynamicFunctionInfo
6398 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6399 * or LCG method and gives information about it without failing like GetFunctionInfo.
6402 * functionId - The function that is being requested.
6403 * pModuleId - An optional parameter for returning the module of the function.
6404 * ppvSig - An optional parameter for returning the signature of the function.
6405 * pbSig - An optional parameter for returning the size of the signature of the function.
6406 * cchName - A parameter for indicating the size of buffer for the wszName parameter.
6407 * pcchName - An optional parameter for returning the true size of the wszName parameter.
6408 * wszName - A parameter to the caller allocated buffer of size cchName
6411 * S_OK if successful.
6413 HRESULT ProfToEEInterfaceImpl::GetDynamicFunctionInfo(FunctionID functionId,
6414 ModuleID *pModuleId,
6415 PCCOR_SIGNATURE* ppvSig,
6419 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[])
6426 EE_THREAD_NOT_REQUIRED;
6428 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6429 // reads metadata which causes us to take a reader lock. However, see
6430 // code:#DisableLockOnAsyncCalls
6431 DISABLED(CAN_TAKE_LOCK);
6433 // Asynchronous functions can be called at arbitrary times when runtime
6434 // is holding locks that cannot be reentered without causing deadlock.
6435 // This contract detects any attempts to reenter locks held at the time
6436 // this function was called.
6440 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6441 PRECONDITION(CheckPointer(ppvSig, NULL_OK));
6442 PRECONDITION(CheckPointer(pbSig, NULL_OK));
6443 PRECONDITION(CheckPointer(pcchName, NULL_OK));
6447 // See code:#DisableLockOnAsyncCalls
6448 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6450 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6453 "**PROF: GetDynamicFunctionInfo 0x%p.\n",
6457 // Verify parameters.
6460 if (functionId == NULL)
6462 return E_INVALIDARG;
6465 MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6467 if (pMethDesc == NULL)
6469 return E_INVALIDARG;
6472 // it's not safe to examine a methoddesc that has not been restored so do not do so
6473 if (!pMethDesc->IsRestored())
6474 return CORPROF_E_DATAINCOMPLETE;
6477 if (!pMethDesc->IsNoMetadata())
6478 return E_INVALIDARG;
6481 // Fill in the ModuleId, if desired.
6483 if (pModuleId != NULL)
6485 *pModuleId = (ModuleID)pMethDesc->GetModule();
6489 // Fill in the ppvSig and pbSig, if desired
6491 if (ppvSig != NULL && pbSig != NULL)
6493 pMethDesc->GetSig(ppvSig, pbSig);
6500 if (wszName != NULL)
6502 if (pcchName != NULL)
6506 ss.SetUTF8(pMethDesc->GetName());
6508 LPCWSTR methodName = ss.GetUnicode();
6510 ULONG trueLen = (ULONG)(wcslen(methodName) + 1);
6512 // Return name of method as required.
6513 if (wszName && cchName > 0)
6515 if (cchName < trueLen)
6517 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6521 wcsncpy_s(wszName, cchName, methodName, trueLen);
6525 // If they request the actual length of the name
6527 *pcchName = trueLen;
6529 EX_CATCH_HRESULT(hr);
6535 * GetNativeCodeStartAddresses
6537 * Gets all of the native code addresses associated with a particular function. iered compilation
6538 * potentially creates different native code versions for a method, and this function allows profilers
6539 * to view all native versions of a method.
6542 * functionID - The function that is being requested.
6543 * reJitId - The ReJIT id.
6544 * cCodeStartAddresses - A parameter for indicating the size of buffer for the codeStartAddresses parameter.
6545 * pcCodeStartAddresses - An optional parameter for returning the true size of the codeStartAddresses parameter.
6546 * codeStartAddresses - The array to be filled up with native code addresses.
6549 * S_OK if successful
6552 HRESULT ProfToEEInterfaceImpl::GetNativeCodeStartAddresses(FunctionID functionID,
6554 ULONG32 cCodeStartAddresses,
6555 ULONG32 *pcCodeStartAddresses,
6556 UINT_PTR codeStartAddresses[])
6563 EE_THREAD_NOT_REQUIRED;
6567 PRECONDITION(CheckPointer(pcCodeStartAddresses, NULL_OK));
6568 PRECONDITION(CheckPointer(codeStartAddresses, NULL_OK));
6572 if (functionID == NULL)
6574 return E_INVALIDARG;
6577 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6580 "**PROF: GetNativeCodeStartAddresses 0x%p 0x%p.\n",
6581 functionID, reJitId));
6587 if (pcCodeStartAddresses != NULL)
6589 *pcCodeStartAddresses = 0;
6592 MethodDesc * methodDesc = FunctionIdToMethodDesc(functionID);
6593 PTR_MethodDesc pMD = PTR_MethodDesc(methodDesc);
6594 ULONG32 trueLen = 0;
6595 StackSArray<UINT_PTR> addresses;
6597 CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
6599 ILCodeVersion ilCodeVersion = NULL;
6601 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
6603 ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
6605 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
6606 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
6608 addresses.Append((*iter).GetNativeCode());
6614 if (pcCodeStartAddresses != NULL)
6616 *pcCodeStartAddresses = trueLen;
6619 if (codeStartAddresses != NULL)
6621 if (cCodeStartAddresses < trueLen)
6623 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6627 for(ULONG32 i = 0; i < trueLen; ++i)
6629 codeStartAddresses[i] = addresses[i];
6634 EX_CATCH_HRESULT(hr);
6640 * GetILToNativeMapping3
6642 * This overload behaves the same as GetILToNativeMapping2, except it allows the profiler
6643 * to address specific native code versions instead of defaulting to the first one.
6646 * pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
6647 * cMap - size of the map array
6648 * pcMap - how many items are returned in the map array
6649 * map - an array to store the il to native mappings in
6652 * S_OK if successful
6655 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping3(UINT_PTR pNativeCodeStartAddress,
6658 COR_DEBUG_IL_TO_NATIVE_MAP map[])
6663 DISABLED(GC_NOTRIGGER);
6668 PRECONDITION(CheckPointer(pcMap, NULL_OK));
6669 PRECONDITION(CheckPointer(map, NULL_OK));
6673 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
6676 "**PROF: GetILToNativeMapping3 0x%p.\n",
6677 pNativeCodeStartAddress));
6679 if (pNativeCodeStartAddress == NULL)
6681 return E_INVALIDARG;
6685 ((pcMap == NULL) || (map == NULL)))
6687 return E_INVALIDARG;
6690 #ifdef DEBUGGING_SUPPORTED
6691 if (g_pDebugInterface == NULL)
6693 return CORPROF_E_DEBUGGING_DISABLED;
6696 return (g_pDebugInterface->GetILToNativeMapping(pNativeCodeStartAddress, cMap, pcMap, map));
6705 * Gets the location and size of a jitted function. Tiered compilation potentially creates different native code
6706 * versions for a method, and this overload allows profilers to specify which native version it would like the
6710 * pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
6711 * cCodeInfos - size of the codeInfos array
6712 * pcCodeInfos - how many items are returned in the codeInfos array
6713 * codeInfos - an array to store the code infos in
6716 * S_OK if successful
6719 HRESULT ProfToEEInterfaceImpl::GetCodeInfo4(UINT_PTR pNativeCodeStartAddress,
6721 ULONG32* pcCodeInfos,
6722 COR_PRF_CODE_INFO codeInfos[])
6729 EE_THREAD_NOT_REQUIRED;
6733 PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
6734 PRECONDITION(CheckPointer(codeInfos, NULL_OK));
6738 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6739 kP2EEAllowableAfterAttach | kP2EETriggers,
6742 "**PROF: GetCodeInfo4 0x%p.\n",
6743 pNativeCodeStartAddress));
6745 if ((cCodeInfos != 0) && (codeInfos == NULL))
6747 return E_INVALIDARG;
6750 return GetCodeInfoFromCodeStart(pNativeCodeStartAddress,
6756 HRESULT ProfToEEInterfaceImpl::RequestReJITWithInliners(
6759 ModuleID moduleIds[],
6760 mdMethodDef methodIds[])
6768 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
6769 PRECONDITION(CheckPointer(methodIds, NULL_OK));
6773 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6774 kP2EETriggers | kP2EEAllowableAfterAttach,
6777 "**PROF: RequestReJITWithInliners.\n"));
6779 if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
6781 return CORPROF_E_CALLBACK4_REQUIRED;
6784 if (!CORProfilerEnableRejit())
6786 return CORPROF_E_REJIT_NOT_ENABLED;
6789 if (!ReJitManager::IsReJITInlineTrackingEnabled())
6791 return CORPROF_E_REJIT_INLINING_DISABLED;
6794 // Request at least 1 method to reJIT!
6795 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
6797 return E_INVALIDARG;
6800 // We only support disabling inlining currently
6801 if ((dwRejitFlags & COR_PRF_REJIT_BLOCK_INLINING) != COR_PRF_REJIT_BLOCK_INLINING)
6803 return E_INVALIDARG;
6806 // Remember the profiler is doing this, as that means we must never detach it!
6807 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
6810 return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds, static_cast<COR_PRF_REJIT_FLAGS>(dwRejitFlags));
6814 * EnumerateObjectReferences
6816 * Enumerates the object references (if any) from the ObjectID.
6819 * objectId - object id of interest
6820 * callback - callback to call for each object reference
6821 * clientData - client data for the profiler to pass and receive for each reference
6824 * S_OK if successful, S_FALSE if no references
6827 HRESULT ProfToEEInterfaceImpl::EnumerateObjectReferences(ObjectID objectId, ObjectReferenceCallback callback, void* clientData)
6834 EE_THREAD_NOT_REQUIRED;
6839 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6840 kP2EEAllowableAfterAttach,
6843 "**PROF: EnumerateObjectReferences 0x%p.\n",
6846 if (callback == nullptr)
6848 return E_INVALIDARG;
6851 Object* pBO = (Object*)objectId;
6852 MethodTable *pMT = pBO->GetMethodTable();
6854 if (pMT->ContainsPointersOrCollectible())
6856 GCHeapUtilities::GetGCHeap()->DiagWalkObject2(pBO, (walk_fn2)callback, clientData);
6868 * Determines whether the object is in a read-only segment
6871 * objectId - object id of interest
6874 * S_OK if successful
6877 HRESULT ProfToEEInterfaceImpl::IsFrozenObject(ObjectID objectId, BOOL *pbFrozen)
6884 EE_THREAD_NOT_REQUIRED;
6889 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6890 kP2EEAllowableAfterAttach,
6893 "**PROF: IsFrozenObject 0x%p.\n",
6896 *pbFrozen = GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)objectId) ? TRUE : FALSE;
6902 * GetLOHObjectSizeThreshold
6904 * Gets the value of the configured LOH Threshold.
6907 * pThreshold - value of the threshold in bytes
6910 * S_OK if successful
6913 HRESULT ProfToEEInterfaceImpl::GetLOHObjectSizeThreshold(DWORD *pThreshold)
6920 EE_THREAD_NOT_REQUIRED;
6925 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6926 kP2EEAllowableAfterAttach,
6929 "**PROF: GetLOHObjectSizeThreshold\n"));
6931 if (pThreshold == nullptr)
6933 return E_INVALIDARG;
6936 *pThreshold = g_pConfig->GetGCLOHThreshold();
6941 HRESULT ProfToEEInterfaceImpl::SuspendRuntime()
6949 EE_THREAD_NOT_REQUIRED;
6953 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6954 kP2EEAllowableAfterAttach | kP2EETriggers,
6957 "**PROF: SuspendRuntime\n"));
6961 return CORPROF_E_RUNTIME_UNINITIALIZED;
6964 if (ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0))
6966 return CORPROF_E_SUSPENSION_IN_PROGRESS;
6969 g_profControlBlock.fProfilerRequestedRuntimeSuspend = TRUE;
6970 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_REASON::SUSPEND_FOR_PROFILER);
6974 HRESULT ProfToEEInterfaceImpl::ResumeRuntime()
6985 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6986 kP2EEAllowableAfterAttach | kP2EETriggers,
6989 "**PROF: ResumeRuntime\n"));
6993 return CORPROF_E_RUNTIME_UNINITIALIZED;
6996 if (!g_profControlBlock.fProfilerRequestedRuntimeSuspend)
6998 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
7001 ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */);
7002 g_profControlBlock.fProfilerRequestedRuntimeSuspend = FALSE;
7009 * This function describes to a profiler the internal layout of a string.
7012 * pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7013 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7014 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7017 * S_OK if successful.
7019 HRESULT ProfToEEInterfaceImpl::GetStringLayout(ULONG *pBufferLengthOffset,
7020 ULONG *pStringLengthOffset,
7021 ULONG *pBufferOffset)
7035 EE_THREAD_NOT_REQUIRED;
7041 PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7042 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7043 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
7047 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7050 "**PROF: GetStringLayout.\n"));
7052 return this->GetStringLayoutHelper(pBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7058 * This function describes to a profiler the internal layout of a string.
7061 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7062 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7065 * S_OK if successful.
7067 HRESULT ProfToEEInterfaceImpl::GetStringLayout2(ULONG *pStringLengthOffset,
7068 ULONG *pBufferOffset)
7082 EE_THREAD_NOT_REQUIRED;
7088 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7089 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
7093 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7096 "**PROF: GetStringLayout2.\n"));
7098 ULONG dummyBufferLengthOffset;
7099 return this->GetStringLayoutHelper(&dummyBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7103 * GetStringLayoutHelper
7105 * This function describes to a profiler the internal layout of a string.
7108 * pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7109 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7110 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7113 * S_OK if successful.
7115 HRESULT ProfToEEInterfaceImpl::GetStringLayoutHelper(ULONG *pBufferLengthOffset,
7116 ULONG *pStringLengthOffset,
7117 ULONG *pBufferOffset)
7131 EE_THREAD_NOT_REQUIRED;
7137 PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7138 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7139 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
7143 // The String class no longer has a bufferLength field in it.
7144 // We are returning the offset of the stringLength because that is the closest we can get
7145 // This is most certainly a breaking change and a new method
7146 // ICorProfilerInfo3::GetStringLayout2 has been added on the interface ICorProfilerInfo3
7147 if (pBufferLengthOffset != NULL)
7149 *pBufferLengthOffset = StringObject::GetStringLengthOffset();
7152 if (pStringLengthOffset != NULL)
7154 *pStringLengthOffset = StringObject::GetStringLengthOffset();
7157 if (pBufferOffset != NULL)
7159 *pBufferOffset = StringObject::GetBufferOffset();
7168 * This function describes to a profiler the internal layout of a class.
7171 * classID - The class that is being queried. It is really a TypeHandle.
7172 * rFieldOffset - An array to store information about each field in the class.
7173 * cFieldOffset - Count of the number of elements in rFieldOffset.
7174 * pcFieldOffset - Upon return contains the number of elements filled in, or if
7175 * cFieldOffset is zero, the number of elements needed.
7176 * pulClassSize - Optional parameter for containing the size in bytes of the underlying
7177 * internal class structure.
7180 * S_OK if successful.
7182 HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID,
7183 COR_FIELD_OFFSET rFieldOffset[],
7185 ULONG *pcFieldOffset,
7186 ULONG *pulClassSize)
7200 EE_THREAD_NOT_REQUIRED;
7206 PRECONDITION(CheckPointer(rFieldOffset, NULL_OK));
7207 PRECONDITION(CheckPointer(pcFieldOffset));
7208 PRECONDITION(CheckPointer(pulClassSize, NULL_OK));
7212 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7215 "**PROF: GetClassLayout 0x%p.\n",
7219 // Verify parameters
7221 if ((pcFieldOffset == NULL) || (classID == NULL))
7223 return E_INVALIDARG;
7226 if ((cFieldOffset != 0) && (rFieldOffset == NULL))
7228 return E_INVALIDARG;
7231 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classID);
7234 // This is the incorrect API for arrays or strings. Use GetArrayObjectInfo, and GetStringLayout
7236 if (typeHandle.IsTypeDesc() || typeHandle.AsMethodTable()->IsArray())
7238 return E_INVALIDARG;
7242 // We used to have a bug where this API incorrectly succeeded for strings during startup. Profilers
7243 // took dependency on this bug. Let the API to succeed for strings during startup for backward compatibility.
7245 if (typeHandle.AsMethodTable()->IsString() && g_profControlBlock.fBaseSystemClassesLoaded)
7247 return E_INVALIDARG;
7251 // If this class is not fully restored, that is all the information we can get at this time.
7253 if (!typeHandle.IsRestored())
7255 return CORPROF_E_DATAINCOMPLETE;
7258 // Types can be pre-restored, but they still aren't expected to handle queries before
7259 // eager fixups have run. This is a targetted band-aid for a bug intellitrace was
7260 // running into - attempting to get the class layout for all types at module load time.
7261 // If we don't detect this the runtime will AV during the field iteration below. Feel
7262 // free to eliminate this check when a more complete solution is available.
7263 if (MethodTable::IsParentMethodTableTagged(typeHandle.AsMethodTable()))
7265 return CORPROF_E_DATAINCOMPLETE;
7268 // !IsValueType = IsArray || IsReferenceType Since IsArry has been ruled out above, it must
7269 // be a reference type if !IsValueType.
7270 BOOL fReferenceType = !typeHandle.IsValueType();
7273 // Fill in class size now
7275 // Move after the check for typeHandle.GetMethodTable()->IsRestored()
7276 // because an unrestored MethodTable may have a bad EE class pointer
7277 // which will be used by MethodTable::GetNumInstanceFieldBytes
7279 if (pulClassSize != NULL)
7283 // aligned size including the object header for reference types
7284 *pulClassSize = typeHandle.GetMethodTable()->GetBaseSize();
7288 // unboxed and unaligned size for value types
7289 *pulClassSize = typeHandle.GetMethodTable()->GetNumInstanceFieldBytes();
7293 ApproxFieldDescIterator fieldDescIterator(typeHandle.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
7295 ULONG cFields = fieldDescIterator.Count();
7298 // If they are looking to just get the count, return that.
7300 if ((cFieldOffset == 0) || (rFieldOffset == NULL))
7302 *pcFieldOffset = cFields;
7307 // Dont put too many in the array.
7309 if (cFields > cFieldOffset)
7311 cFields = cFieldOffset;
7314 *pcFieldOffset = cFields;
7317 // Now fill in the array
7322 for (i = 0; i < cFields; i++)
7324 pField = fieldDescIterator.Next();
7325 rFieldOffset[i].ridOfField = (ULONG)pField->GetMemberDef();
7326 rFieldOffset[i].ulOffset = (ULONG)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
7333 typedef struct _PROFILER_STACK_WALK_DATA
7335 StackSnapshotCallback *callback;
7337 ULONG32 contextFlags;
7340 #ifdef WIN64EXCEPTIONS
7341 StackFrame sfParent;
7343 } PROFILER_STACK_WALK_DATA;
7347 * ProfilerStackWalkCallback
7349 * This routine is used as the callback from the general stack walker for
7350 * doing snapshot stack walks
7353 StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_DATA *pData)
7357 NOTHROW; // throw is RIGHT out... the throw at minimum allocates the thrown object which we *must* not do
7358 GC_NOTRIGGER; // the stack is not necessarily crawlable at this state !!!) we must not induce a GC
7362 MethodDesc *pFunc = pCf->GetFunction();
7364 COR_PRF_FRAME_INFO_INTERNAL frameInfo;
7365 ULONG32 contextSize = 0;
7366 BYTE *context = NULL;
7368 UINT_PTR currentIP = 0;
7369 REGDISPLAY *pRegDisplay = pCf->GetRegisterSet();
7370 #if defined(_TARGET_X86_)
7371 CONTEXT builtContext;
7375 // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want
7376 // to return to the profiler as the context seed if it wants to walk the unmanaged
7377 // stack frame, so we report the functionId as NULL to indicate this.
7379 if (pCf->IsNativeMarker())
7385 // Skip all Lightweight reflection/emit functions
7387 if ((pFunc != NULL) && pFunc->IsNoMetadata())
7389 return SWA_CONTINUE;
7393 // If this is not a transition of any sort and not a managed
7394 // method, ignore it.
7396 if (!pCf->IsNativeMarker() && !pCf->IsFrameless())
7398 return SWA_CONTINUE;
7401 currentIP = (UINT_PTR)pRegDisplay->ControlPC;
7403 frameInfo.size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
7404 frameInfo.version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
7408 frameInfo.funcID = MethodDescToFunctionID(pFunc);
7409 frameInfo.extraArg = NULL;
7413 frameInfo.funcID = NULL;
7414 frameInfo.extraArg = NULL;
7417 frameInfo.IP = currentIP;
7418 frameInfo.thisArg = NULL;
7420 if (pData->infoFlags & COR_PRF_SNAPSHOT_REGISTER_CONTEXT)
7422 #if defined(_TARGET_X86_)
7424 // X86 stack walking does not keep the context up-to-date during the
7425 // walk. Instead it keeps the REGDISPLAY up-to-date. Thus, we need to
7426 // build a CONTEXT from the REGDISPLAY.
7429 memset(&builtContext, 0, sizeof(builtContext));
7430 builtContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
7431 CopyRegDisplay(pRegDisplay, NULL, &builtContext);
7432 context = (BYTE *)(&builtContext);
7434 context = (BYTE *)pRegDisplay->pCurrentContext;
7436 contextSize = sizeof(CONTEXT);
7439 // NOTE: We are intentionally not setting any callback state flags here (i.e., not using
7440 // SetCallbackStateFlagsHolder), as we want the DSS callback to "inherit" the
7441 // same callback state that DSS has: if DSS was called asynchronously, then consider
7442 // the DSS callback to be called asynchronously.
7443 if (pData->callback(frameInfo.funcID,
7445 (COR_PRF_FRAME_INFO)&frameInfo,
7448 pData->clientData) == S_OK)
7450 return SWA_CONTINUE;
7458 //---------------------------------------------------------------------------------------
7459 // Normally, calling GetFunction() on the frame is sufficient to ensure
7460 // HelperMethodFrames are intialized. However, sometimes we need to be able to specify
7461 // that we should not enter the host while initializing, so we need to initialize such
7462 // frames more directly. This small helper function directly forces the initialization,
7463 // and ensures we don't enter the host as a result if we're executing in an asynchronous
7464 // call (i.e., hijacked thread)
7467 // pFrame - Frame to initialize.
7470 // TRUE iff pFrame was successfully initialized (or was already initialized). If
7471 // pFrame is not a HelperMethodFrame (or derived type), this returns TRUE
7472 // immediately. FALSE indicates we tried to initialize w/out entering the host, and
7473 // had to abort as a result when a reader lock was needed but unavailable.
7476 static BOOL EnsureFrameInitialized(Frame * pFrame)
7483 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7484 // host (SQL). Corners will be cut to ensure this is the case
7485 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7491 if (pFrame->GetFrameType() != Frame::TYPE_HELPER_METHOD_FRAME)
7493 // This frame is not a HelperMethodFrame or a frame derived from
7494 // HelperMethodFrame, so HMF-specific lazy initialization is not an issue.
7498 HelperMethodFrame * pHMF = (HelperMethodFrame *) pFrame;
7500 if (pHMF->InsureInit(
7501 false, // initialInit
7502 NULL, // unwindState
7503 (ShouldAvoidHostCalls() ?
7508 // InsureInit() succeeded and found the return address
7512 // No return address was found. It must be because we asked InsureInit() to bail if
7513 // it would have entered the host
7514 _ASSERTE(ShouldAvoidHostCalls());
7518 //---------------------------------------------------------------------------------------
7520 // Implements the COR_PRF_SNAPSHOT_X86_OPTIMIZED algorithm called by DoStackSnapshot.
7521 // Does a simple EBP walk, rather than invoking all of StackWalkFramesEx.
7524 // pThreadToSnapshot - Thread whose stack should be walked
7525 // pctxSeed - Register context with which to seed the walk
7526 // callback - Function to call at each frame found during the walk
7527 // clientData - Parameter to pass through to callback
7530 // HRESULT indicating success or failure.
7533 HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
7534 Thread * pThreadToSnapshot,
7536 StackSnapshotCallback * callback,
7544 EE_THREAD_NOT_REQUIRED;
7546 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7547 // host (SQL). Corners will be cut to ensure this is the case
7548 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7554 // We haven't set the stackwalker thread type flag yet (see next line), so it shouldn't be set. Only
7555 // exception to this is if the current call is made by a hijacking profiler which
7556 // redirected this thread while it was previously in the middle of another stack walk
7557 _ASSERTE(IsCalledAsynchronously() || !IsStackWalkerThread());
7559 // Remember that we're walking the stack. This holder will reinstate the original
7560 // value of the stackwalker flag (from the thread type mask) in its destructor.
7561 ClrFlsValueSwitch _threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThreadToSnapshot);
7563 // This flag remembers if we reported a managed frame since the last unmanaged block
7564 // we reported. It's used to avoid reporting two unmanaged blocks in a row.
7565 BOOL fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7567 Frame * pFrameCur = pThreadToSnapshot->GetFrame();
7570 ZeroMemory(&ctxCur, sizeof(ctxCur));
7572 // Use seed if we got one. Otherwise, EE explicit Frame chain will seed the walk.
7573 if (pctxSeed != NULL)
7575 ctxCur.Ebp = pctxSeed->Ebp;
7576 ctxCur.Eip = pctxSeed->Eip;
7577 ctxCur.Esp = pctxSeed->Esp;
7582 // At each iteration of the loop:
7583 // * Analyze current frame (get managed data if it's a managed frame)
7584 // * Report current frame via callback()
7585 // * Walk down to next frame
7587 // **** Managed or unmanaged frame? ****
7589 EECodeInfo codeInfo;
7590 MethodDesc * pMethodDescCur = NULL;
7592 if (ctxCur.Eip != 0)
7594 hr = GetFunctionInfoInternal(
7595 (LPCBYTE) ctxCur.Eip,
7597 if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
7599 _ASSERTE(ShouldAvoidHostCalls());
7604 pMethodDescCur = codeInfo.GetMethodDesc();
7608 // **** Report frame to profiler ****
7611 // Make sure the frame gave us an IP
7612 (ctxCur.Eip != 0) &&
7614 // Make sure any managed frame isn't for an IL stub or LCG
7615 ((pMethodDescCur == NULL) || !pMethodDescCur->IsNoMetadata()) &&
7617 // Only report unmanaged frames if the last frame we reported was managed
7618 // (avoid reporting two unmanaged blocks in a row)
7619 ((pMethodDescCur != NULL) || fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock))
7621 // Around the call to the profiler, temporarily clear the
7622 // ThreadType_StackWalker type flag, as we have no control over what the
7623 // profiler may do inside its callback (it could theoretically attempt to
7624 // load other types, though I don't personally know of profilers that
7625 // currently do this).
7627 CLEAR_THREAD_TYPE_STACKWALKER();
7629 (FunctionID) pMethodDescCur,
7631 NULL, // COR_PRF_FRAME_INFO
7632 sizeof(ctxCur), // contextSize,
7633 (LPBYTE) &ctxCur, // context,
7635 SET_THREAD_TYPE_STACKWALKER(pThreadToSnapshot);
7641 if (pMethodDescCur == NULL)
7643 // Just reported an unmanaged block, so reset the flag
7644 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7648 // Just reported a managed block, so remember it
7649 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = TRUE;
7653 // **** Walk down to next frame ****
7655 // Is current frame managed or unmanaged?
7656 if (pMethodDescCur == NULL)
7658 // Unmanaged frame. Use explicit EE Frame chain to help
7661 ZeroMemory(&frameRD, sizeof(frameRD));
7663 while (pFrameCur != FRAME_TOP)
7665 // Frame is only useful if it will contain register context info
7666 if (!pFrameCur->NeedsUpdateRegDisplay())
7672 // This should be the first call we make to the Frame, as it will
7673 // ensure we force lazy initialize of HelperMethodFrames
7674 if (!EnsureFrameInitialized(pFrameCur))
7676 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7679 // This frame is only useful if it gives us an actual return address,
7680 // and is situated on the stack at or below our current ESP (stack
7682 if ((pFrameCur->GetReturnAddress() != NULL) &&
7683 (dac_cast<TADDR>(pFrameCur) >= dac_cast<TADDR>(ctxCur.Esp)))
7685 pFrameCur->UpdateRegDisplay(&frameRD);
7690 pFrameCur = pFrameCur->PtrNextFrame();
7693 if (pFrameCur == FRAME_TOP)
7695 // No more frames. Stackwalk is over
7699 // Update ctxCur based on frame
7700 ctxCur.Eip = pFrameCur->GetReturnAddress();
7701 ctxCur.Ebp = GetRegdisplayFP(&frameRD);
7702 ctxCur.Esp = GetRegdisplaySP(&frameRD);
7708 // GC info will assist us in determining whether this is a non-EBP frame and
7709 // info about pushed arguments.
7710 GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
7711 PTR_VOID gcInfo = gcInfoToken.Info;
7713 unsigned uiMethodSizeDummy;
7714 PTR_CBYTE table = PTR_CBYTE(gcInfo);
7715 table += decodeUnsigned(table, &uiMethodSizeDummy);
7716 table = decodeHeader(table, gcInfoToken.Version, &header);
7718 // Ok, GCInfo, can we do a simple EBP walk or what?
7720 if ((codeInfo.GetRelOffset() < header.prologSize) ||
7721 (!header.ebpFrame && !header.doubleAlign))
7723 // We're either in the prolog or we're not in an EBP frame, in which case
7724 // we'll just defer to the code manager to unwind for us. This condition
7725 // is relatively rare, but can occur if:
7727 // * The profiler did a DSS from its Enter hook, in which case we're
7728 // still inside the prolog, OR
7729 // * The seed context or explicit EE Frame chain seeded us with a
7730 // non-EBP frame function. In this case, using a naive EBP
7731 // unwinding algorithm would actually skip over the next EBP
7732 // frame, and would get SP all wrong as we try skipping over
7733 // the pushed parameters. So let's just ask the code manager for
7736 // Note that there are yet more conditions (much more rare) where the EBP
7737 // walk could get lost (e.g., we're inside an epilog). But we only care
7738 // about the most likely cases, and it's ok if the unlikely cases result
7739 // in truncated stacks, as unlikely cases will be statistically
7740 // irrelevant to CPU performance sampling profilers
7741 CodeManState codeManState;
7742 codeManState.dwIsSet = 0;
7744 ZeroMemory(&rd, sizeof(rd));
7746 rd.SetEbpLocation(&ctxCur.Ebp);
7748 rd.ControlPC = ctxCur.Eip;
7750 codeInfo.GetCodeManager()->UnwindStackFrame(
7753 SpeculativeStackwalk,
7757 ctxCur.Ebp = *rd.GetEbpLocation();
7759 ctxCur.Eip = rd.ControlPC;
7763 // We're in an actual EBP frame, so we can simplistically walk down to
7764 // the next frame using EBP.
7766 // Return address is stored just below saved EBP (stack grows up)
7767 ctxCur.Eip = *(DWORD *) (ctxCur.Ebp + sizeof(DWORD));
7770 // Stack location where current function pushed its EBP
7773 // Skip past that EBP
7776 // Skip past return address pushed by caller
7779 // Skip past arguments to current function that were pushed by caller.
7780 // (Caller will pop varargs, so don't count those.)
7781 (header.varargs ? 0 : (header.argCount * sizeof(DWORD)));
7783 // EBP for frame below us (stack grows up) has been saved onto our own
7784 // frame. Dereference it now.
7785 ctxCur.Ebp = *(DWORD *) ctxCur.Ebp;
7790 #endif // _TARGET_X86_
7792 //*****************************************************************************
7793 // The profiler stackwalk Wrapper
7794 //*****************************************************************************
7795 HRESULT ProfToEEInterfaceImpl::ProfilerStackWalkFramesWrapper(Thread * pThreadToSnapshot, PROFILER_STACK_WALK_DATA * pData, unsigned flags)
7797 STATIC_CONTRACT_WRAPPER;
7799 StackWalkAction swaRet = pThreadToSnapshot->StackWalkFrames(
7800 (PSTACKWALKFRAMESCALLBACK)ProfilerStackWalkCallback,
7808 _ASSERTE(!"Unexpected StackWalkAction returned from Thread::StackWalkFrames");
7815 return CORPROF_E_STACKSNAPSHOT_ABORTED;
7822 //---------------------------------------------------------------------------------------
7824 // DoStackSnapshot helper to call FindJitMan to determine if the specified
7825 // context is in managed code.
7828 // pCtx - Context to look at
7829 // hostCallPreference - Describes how to acquire the reader lock--either AllowHostCalls
7830 // or NoHostCalls (see code:HostCallPreference).
7833 // S_OK: The context is in managed code
7834 // S_FALSE: The context is not in managed code.
7835 // Error: Unable to determine (typically because hostCallPreference was NoHostCalls
7836 // and the reader lock was unattainable without yielding)
7839 HRESULT IsContextInManagedCode(const CONTEXT * pCtx, HostCallPreference hostCallPreference)
7841 WRAPPER_NO_CONTRACT;
7842 BOOL fFailedReaderLock = FALSE;
7844 // if there's no Jit Manager for the IP, it's not managed code.
7845 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(pCtx), hostCallPreference, &fFailedReaderLock);
7846 if (fFailedReaderLock)
7848 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7851 return fIsManagedCode ? S_OK : S_FALSE;
7854 //*****************************************************************************
7855 // Perform a stack walk, calling back to callback at each managed frame.
7856 //*****************************************************************************
7857 HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread,
7858 StackSnapshotCallback *callback,
7862 ULONG32 contextSize)
7866 // Yay! (Note: NOTHROW is vital. The throw at minimum allocates
7867 // the thrown object which we *must* not do.)
7870 // Yay! (Note: this is called asynchronously to view the stack at arbitrary times,
7871 // so the stack is not necessarily crawlable for GC at this state!)
7878 EE_THREAD_NOT_REQUIRED;
7880 // #DisableLockOnAsyncCalls
7881 // This call is allowed asynchronously, however it does take locks. Therefore,
7882 // we will hit contract asserts if we happen to be in a CANNOT_TAKE_LOCK zone when
7883 // a hijacking profiler hijacks this thread to run DoStackSnapshot. CANNOT_RETAKE_LOCK
7884 // is a more granular locking contract that says "I promise that if I take locks, I
7885 // won't reenter any locks that were taken before this function was called".
7886 DISABLED(CAN_TAKE_LOCK);
7888 // Asynchronous functions can be called at arbitrary times when runtime
7889 // is holding locks that cannot be reentered without causing deadlock.
7890 // This contract detects any attempts to reenter locks held at the time
7891 // this function was called.
7897 // This CONTRACT_VIOLATION is still needed because DISABLED(CAN_TAKE_LOCK) does not
7898 // turn off contract violations.
7899 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
7901 LPCONTEXT pctxSeed = reinterpret_cast<LPCONTEXT> (pbContext);
7903 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7906 "**PROF: DoStackSnapshot 0x%p, 0x%p, 0x%08x, 0x%p, 0x%p, 0x%08x.\n",
7914 HRESULT hr = E_UNEXPECTED;
7915 // (hr assignment is to appease the compiler; we won't actually return without explicitly setting hr again)
7917 Thread *pThreadToSnapshot = NULL;
7918 Thread * pCurrentThread = GetThreadNULLOk();
7919 BOOL fResumeThread = FALSE;
7920 INDEBUG(ULONG ulForbidTypeLoad = 0;)
7921 BOOL fResetSnapshotThreadExternalCount = FALSE;
7922 int cRefsSnapshotThread = 0;
7924 // Remember whether we've already determined the current context of the target thread
7925 // is in managed (S_OK), not in managed (S_FALSE), or unknown (error).
7926 HRESULT hrCurrentContextIsManaged = E_FAIL;
7929 memset(&ctxCurrent, 0, sizeof(ctxCurrent));
7933 PROFILER_STACK_WALK_DATA data;
7937 // no managed code has run and things are likely in a very bad have loaded state
7938 // this is a bad time to try to walk the stack
7940 // Returning directly as there is nothing to cleanup yet
7941 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7944 if (!CORProfilerStackSnapshotEnabled())
7946 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7947 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
7952 pThreadToSnapshot = pCurrentThread;
7956 pThreadToSnapshot = (Thread *)thread;
7960 if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT | COR_PRF_SNAPSHOT_X86_OPTIMIZED)) != 0)
7962 if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT)) != 0)
7965 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7966 return E_INVALIDARG;
7969 if (!IsManagedThread(pThreadToSnapshot) || !IsGarbageCollectorFullyInitialized())
7972 // No managed frames, return now.
7974 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7978 // We must make sure no other thread tries to hijack the thread we're about to walk
7979 // Hijacking means Thread::HijackThread, i.e. bashing return addresses which would break the stack walk
7980 Thread::HijackLockHolder hijackLockHolder(pThreadToSnapshot);
7981 if (!hijackLockHolder.Acquired())
7983 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7984 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7987 if (pThreadToSnapshot != pCurrentThread // Walking separate thread
7988 && pCurrentThread != NULL // Walker (current) thread is a managed / VM thread
7989 && ThreadSuspend::SysIsSuspendInProgress()) // EE is trying suspend itself
7991 // Since we're walking a separate thread, we'd have to suspend it first (see below).
7992 // And since the current thread is a VM thread, that means the current thread's
7993 // m_dwForbidSuspendThread count will go up while it's trying to suspend the
7994 // target thread (see Thread::SuspendThread). THAT means no one will be able
7995 // to suspend the current thread until its m_dwForbidSuspendThread is decremented
7996 // (which happens as soon as the target thread of DoStackSnapshot has been suspended).
7997 // Since we're in the process of suspending the entire runtime, now would be a bad time to
7998 // make the walker thread un-suspendable (see VsWhidbey bug 454936). So let's just abort
7999 // now. Note that there is no synchronization around calling Thread::SysIsSuspendInProgress().
8000 // So we will get occasional false positives or false negatives. But that's benign, as the worst
8001 // that might happen is we might occasionally delay the EE suspension a little bit, or we might
8002 // too eagerly fail from ProfToEEInterfaceImpl::DoStackSnapshot sometimes. But there won't
8003 // be any corruption or AV.
8005 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
8006 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
8009 // We only allow stackwalking if:
8010 // 1) Target thread to walk == current thread OR Target thread is suspended, AND
8011 // 2) Target thread to walk is currently executing JITted / NGENd code, AND
8012 // 3) Target thread to walk is seeded OR currently NOT unwinding the stack, AND
8013 // 4) Target thread to walk != current thread OR current thread is NOT in a can't stop or forbid suspend region
8015 // If the thread is in a forbid suspend region, it's dangerous to do anything:
8016 // - The code manager datastructures accessed during the stackwalk may be in inconsistent state.
8017 // - Thread::Suspend won't be able to suspend the thread.
8018 if (pThreadToSnapshot->IsInForbidSuspendRegion())
8020 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8024 HostCallPreference hostCallPreference;
8026 // First, check "1) Target thread to walk == current thread OR Target thread is suspended"
8027 if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
8029 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8033 // Walking separate thread, so it must be suspended. First, ensure that
8034 // target thread exists.
8036 // NOTE: We're using the "dangerous" variant of this refcount function, because we
8037 // rely on the profiler to ensure it never tries to walk a thread being destroyed.
8038 // (Profiler must block in its ThreadDestroyed() callback until all uses of that thread,
8039 // such as walking its stack, are complete.)
8040 cRefsSnapshotThread = pThreadToSnapshot->IncExternalCountDANGEROUSProfilerOnly();
8041 fResetSnapshotThreadExternalCount = TRUE;
8043 if (cRefsSnapshotThread == 1 || !pThreadToSnapshot->HasValidThreadHandle())
8045 // At this point, we've modified the VM state based on bad input
8046 // (pThreadToSnapshot) from the profiler. This could cause
8047 // memory corruption and leave us vulnerable to security problems.
8048 // So destroy the process.
8049 _ASSERTE(!"Profiler trying to walk destroyed thread");
8050 EEPOLICY_HANDLE_FATAL_ERROR(CORPROF_E_STACKSNAPSHOT_INVALID_TGT_THREAD);
8053 // Thread::SuspendThread() ensures that no one else should try to suspend us
8054 // while we're suspending pThreadToSnapshot.
8056 // TRUE: OneTryOnly. Don't loop waiting for others to get out of our way in
8057 // order to suspend the thread. If it's not safe, just return an error immediately.
8058 Thread::SuspendThreadResult str = pThreadToSnapshot->SuspendThread(TRUE);
8059 if (str == Thread::STR_Success)
8061 fResumeThread = TRUE;
8065 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8068 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8071 hostCallPreference =
8072 ShouldAvoidHostCalls() ?
8073 NoHostCalls : // Async call: Ensure this thread won't yield & re-enter host
8074 AllowHostCalls; // Synchronous calls may re-enter host just fine
8076 // If target thread is in pre-emptive mode, the profiler's seed context is unnecessary
8077 // because our frame chain is good enough: it will give us at least as accurate a
8078 // starting point as the profiler could. Also, since profiler contexts cannot be
8079 // trusted, we don't want to set the thread's profiler filter context to this, as a GC
8080 // that interrupts the profiler's stackwalk will end up using the profiler's (potentially
8081 // bogus) filter context.
8082 if (!pThreadToSnapshot->PreemptiveGCDisabledOther())
8084 // Thread to be walked is in preemptive mode. Throw out seed.
8087 else if (pThreadToSnapshot != pCurrentThread)
8089 // With cross-thread stack-walks, the target thread's context could be unreliable.
8090 // That would shed doubt on either a profiler-provided context, or a default
8091 // context we chose. So check if we're in a potentially unreliable case, and return
8094 // These heurisitics are based on an actual bug where GetThreadContext returned a
8095 // self-consistent, but stale, context for a thread suspended after being redirected by
8096 // the GC (TFS Dev 10 bug # 733263).
8098 // (Note that this whole block is skipped if pThreadToSnapshot is in preemptive mode (the IF
8099 // above), as the context is unused in such a case--the EE Frame chain is used
8100 // to seed the walk instead.)
8101 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8105 if (!pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8107 LOG((LF_CORPROF, LL_INFO100, "**PROF: GetSafelyRedirectableThreadContext failure leads to CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8108 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8112 hrCurrentContextIsManaged = IsContextInManagedCode(&ctxCurrent, hostCallPreference);
8113 if (FAILED(hrCurrentContextIsManaged))
8115 // Couldn't get the info. Try again later
8116 _ASSERTE(ShouldAvoidHostCalls());
8117 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8121 if ((hrCurrentContextIsManaged == S_OK) &&
8122 (!pThreadToSnapshot->PreemptiveGCDisabledOther()))
8124 // Thread is in preemptive mode while executing managed code?! This lie is
8125 // an early warning sign that the context is bogus. Bail.
8126 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus. Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8127 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8131 Frame * pFrame = pThreadToSnapshot->GetFrame();
8132 if (pFrame != FRAME_TOP)
8134 TADDR spTargetThread = GetSP(&ctxCurrent);
8135 if (dac_cast<TADDR>(pFrame) < spTargetThread)
8137 // An Explicit EE Frame is more recent on the stack than the current
8138 // stack pointer itself? This lie is an early warning sign that the
8139 // context is bogus. Bail.
8140 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus. Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8141 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8146 // If the profiler did not specify a seed context of its own, use the current one we
8149 // Failing to seed the walk can cause us to to "miss" functions on the stack. This is
8150 // because StackWalkFrames(), when doing an unseeded stackwalk, sets the
8151 // starting regdisplay's IP/SP to 0. This, in turn causes StackWalkFramesEx
8152 // to set cf.isFrameless = (pEEJM != NULL); (which is FALSE, since we have no
8153 // jit manager, since we have no IP). Once frameless is false, we look solely to
8154 // the Frame chain for our goodies, rather than looking at the code actually
8155 // being executed by the thread. The problem with the frame chain is that some
8156 // frames (e.g., GCFrame) don't point to any functions being executed. So
8157 // StackWalkFramesEx just skips such frames and moves to the next one. That
8158 // can cause a chunk of calls to be skipped. To prevent this from happening, we
8159 // "fake" a seed by just seeding the thread with its current context. This forces
8160 // StackWalkFramesEx() to look at the IP rather than just the frame chain.
8161 if (pctxSeed == NULL)
8163 pctxSeed = &ctxCurrent;
8165 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8168 // Second, check "2) Target thread to walk is currently executing JITted / NGENd code"
8169 // To do this, we need to find the proper context to investigate. Start with
8170 // the seeded context, if available. If not, use the target thread's current context.
8171 if (pctxSeed != NULL)
8173 BOOL fSeedIsManaged;
8175 // Short cut: If we're just using the current context as the seed, we may
8176 // already have determined whether it's in managed code. If so, just use that
8177 // result rather than calculating it again
8178 if ((pctxSeed == &ctxCurrent) && SUCCEEDED(hrCurrentContextIsManaged))
8180 fSeedIsManaged = (hrCurrentContextIsManaged == S_OK);
8184 hr = IsContextInManagedCode(pctxSeed, hostCallPreference);
8187 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8190 fSeedIsManaged = (hr == S_OK);
8193 if (!fSeedIsManaged)
8195 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8202 // Sanity check: If we are doing a cross-thread walk and there is no seed context, then
8203 // we better not be in managed code, otw we do not have a Frame on the stack from which to start
8204 // walking and we may miss the leaf-most chain of managed calls due to the way StackWalkFrames
8205 // is implemented. However, there is an exception when the leaf-most EE frame of pThreadToSnapshot
8206 // is an InlinedCallFrame, which has an active call, implying pThreadToShanpshot is inside an
8207 // inlined P/Invoke. In this case, the InlinedCallFrame will be used to help start off our
8208 // stackwalk at the top of the stack.
8210 if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
8212 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8216 if (pctxSeed == NULL)
8218 if (pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8220 BOOL fFailedReaderLock = FALSE;
8221 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(&ctxCurrent), hostCallPreference, &fFailedReaderLock);
8223 if (!fFailedReaderLock)
8225 // not in jitted or ngend code or inside an inlined P/Invoke (the leaf-most EE Frame is
8226 // an InlinedCallFrame with an active call)
8227 _ASSERTE(!fIsManagedCode ||
8228 (InlinedCallFrame::FrameHasActiveCall(pThreadToSnapshot->GetFrame())));
8232 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8235 // Third, verify the target thread is seeded or not in the midst of an unwind.
8236 if (pctxSeed == NULL)
8238 ThreadExceptionState* pExState = pThreadToSnapshot->GetExceptionState();
8240 // this tests to see if there is an exception in flight
8241 if (pExState->IsExceptionInProgress() && pExState->GetFlags()->UnwindHasStarted())
8243 EHClauseInfo *pCurrentEHClauseInfo = pThreadToSnapshot->GetExceptionState()->GetCurrentEHClauseInfo();
8245 // if the exception code is telling us that we have entered a managed context then all is well
8246 if (!pCurrentEHClauseInfo->IsManagedCodeEntered())
8248 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8254 // Check if the exception state is consistent. See the comment for ThreadExceptionFlag for more information.
8255 if (pThreadToSnapshot->GetExceptionState()->HasThreadExceptionFlag(ThreadExceptionState::TEF_InconsistentExceptionState))
8257 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8261 data.callback = callback;
8262 data.infoFlags = infoFlags;
8263 data.contextFlags = 0;
8264 data.clientData = clientData;
8265 #ifdef WIN64EXCEPTIONS
8266 data.sfParent.Clear();
8269 // workaround: The ForbidTypeLoad book keeping in the stackwalker is not robust against exceptions.
8270 // Unfortunately, it is hard to get it right in the stackwalker since it has to be exception
8271 // handling free (frame unwinding may never return). We restore the ForbidTypeLoad counter here
8272 // in case it got messed up by exception thrown during the stackwalk.
8273 INDEBUG(if (pCurrentThread) ulForbidTypeLoad = pCurrentThread->m_ulForbidTypeLoad;)
8276 // An AV during a profiler stackwalk is an isolated event and shouldn't bring
8277 // down the runtime. Need to place the holder here, outside of ProfilerStackWalkFramesWrapper
8278 // since ProfilerStackWalkFramesWrapper uses __try, which doesn't like objects
8279 // with destructors.
8280 AVInRuntimeImplOkayHolder AVOkay;
8282 hr = DoStackSnapshotHelper(
8285 HANDLESKIPPEDFRAMES |
8287 NOTIFY_ON_U2M_TRANSITIONS |
8288 ((pThreadToSnapshot == pCurrentThread) ?
8290 ALLOW_ASYNC_STACK_WALK | THREAD_IS_SUSPENDED) |
8291 THREAD_EXECUTING_MANAGED_CODE |
8292 PROFILER_DO_STACK_SNAPSHOT |
8293 ALLOW_INVALID_OBJECTS, // stack walk logic should not look at objects - we could be in the middle of a gc.
8297 INDEBUG(if (pCurrentThread) pCurrentThread->m_ulForbidTypeLoad = ulForbidTypeLoad;)
8300 #if defined(PLATFORM_SUPPORTS_SAFE_THREADSUSPEND)
8303 pThreadToSnapshot->ResumeThread();
8305 #endif // PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8306 if (fResetSnapshotThreadExternalCount)
8308 pThreadToSnapshot->DecExternalCountDANGEROUSProfilerOnly();
8315 //---------------------------------------------------------------------------------------
8317 // Exception swallowing wrapper around the profiler stackwalk
8320 // pThreadToSnapshot - Thread whose stack should be walked
8321 // pData - data for stack walker
8322 // flags - flags parameter to pass to StackWalkFramesEx, and StackFrameIterator
8323 // pctxSeed - Register context with which to seed the walk
8326 // HRESULT indicating success or failure.
8328 HRESULT ProfToEEInterfaceImpl::DoStackSnapshotHelper(Thread * pThreadToSnapshot,
8329 PROFILER_STACK_WALK_DATA * pData,
8333 STATIC_CONTRACT_NOTHROW;
8335 // We want to catch and swallow AVs here. For example, if the profiler gives
8336 // us a bogus seed context (this happens), we could AV when inspecting memory pointed to
8337 // by the (bogus) EBP register.
8339 // EX_TRY/EX_CATCH does a lot of extras that we do not need and that can go wrong for us.
8340 // E.g. It asserts in debug build for AVs in mscorwks or it synthetizes an object for the exception.
8341 // We use a plain PAL_TRY/PAL_EXCEPT since it is all we need.
8344 Thread * pThreadToSnapshot;
8345 PROFILER_STACK_WALK_DATA * pData;
8347 ProfToEEInterfaceImpl * pProfToEE;
8349 BOOL fResetProfilerFilterContext;
8353 param.hr = E_UNEXPECTED;
8354 param.pThreadToSnapshot = pThreadToSnapshot;
8355 param.pData = pData;
8356 param.flags = flags;
8357 param.pProfToEE = this;
8358 param.pctxSeed = pctxSeed;
8359 param.fResetProfilerFilterContext = FALSE;
8361 PAL_TRY(Param *, pParam, ¶m)
8363 if ((pParam->pData->infoFlags & COR_PRF_SNAPSHOT_X86_OPTIMIZED) != 0)
8365 #ifndef _TARGET_X86_
8366 // If check in the begining of DoStackSnapshot (to return E_INVALIDARG) should
8367 // make this unreachable
8368 _ASSERTE(!"COR_PRF_SNAPSHOT_X86_OPTIMIZED on non-X86 should be unreachable!");
8370 // New, simple EBP walker
8371 pParam->hr = pParam->pProfToEE->ProfilerEbpWalker(
8372 pParam->pThreadToSnapshot,
8374 pParam->pData->callback,
8375 pParam->pData->clientData);
8376 #endif // _TARGET_X86_
8380 // We're now fairly confident the stackwalk should be ok, so set
8381 // the context seed, if one was provided or cooked up.
8382 if (pParam->pctxSeed != NULL)
8384 pParam->pThreadToSnapshot->SetProfilerFilterContext(pParam->pctxSeed);
8385 pParam->fResetProfilerFilterContext = TRUE;
8388 // Whidbey-style walker, uses StackWalkFramesEx
8389 pParam->hr = pParam->pProfToEE->ProfilerStackWalkFramesWrapper(
8390 pParam->pThreadToSnapshot,
8395 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8397 param.hr = E_UNEXPECTED;
8401 // Undo the context seeding & thread suspend we did (if any)
8402 // to ensure that the thread we walked stayed suspended
8403 if (param.fResetProfilerFilterContext)
8405 pThreadToSnapshot->SetProfilerFilterContext(NULL);
8412 HRESULT ProfToEEInterfaceImpl::GetGenerationBounds(ULONG cObjectRanges,
8413 ULONG *pcObjectRanges,
8414 COR_PRF_GC_GENERATION_RANGE ranges[])
8428 EE_THREAD_NOT_REQUIRED;
8434 PRECONDITION(CheckPointer(pcObjectRanges));
8435 PRECONDITION(cObjectRanges <= 0 || ranges != NULL);
8436 PRECONDITION(s_generationTableLock >= 0);
8440 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8443 "**PROF: GetGenerationBounds.\n"));
8445 // Announce we are using the generation table now
8446 CounterHolder genTableLock(&s_generationTableLock);
8448 GenerationTable *generationTable = s_currentGenerationTable;
8450 if (generationTable == NULL)
8455 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8457 GenerationDesc *genDescTable = generationTable->genDescTable;
8458 ULONG count = min(generationTable->count, cObjectRanges);
8459 for (ULONG i = 0; i < count; i++)
8461 ranges[i].generation = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8462 ranges[i].rangeStart = (ObjectID)genDescTable[i].rangeStart;
8463 ranges[i].rangeLength = genDescTable[i].rangeEnd - genDescTable[i].rangeStart;
8464 ranges[i].rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8467 *pcObjectRanges = generationTable->count;
8473 HRESULT ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo(COR_PRF_EX_CLAUSE_INFO * pinfo)
8490 PRECONDITION(CheckPointer(pinfo));
8494 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
8496 "**PROF: GetNotifiedExceptionClauseInfo.\n"));
8500 ThreadExceptionState* pExState = NULL;
8501 EHClauseInfo* pCurrentEHClauseInfo = NULL;
8503 // notification requires that we are on a managed thread with an exception in flight
8504 Thread *pThread = GetThread();
8506 // If pThread is null, then the thread has never run managed code
8507 if (pThread == NULL)
8509 hr = CORPROF_E_NOT_MANAGED_THREAD;
8513 pExState = pThread->GetExceptionState();
8514 if (!pExState->IsExceptionInProgress())
8516 // no exception is in flight -- successful failure
8521 pCurrentEHClauseInfo = pExState->GetCurrentEHClauseInfo();
8522 if (pCurrentEHClauseInfo->GetClauseType() == COR_PRF_CLAUSE_NONE)
8524 // no exception is in flight -- successful failure
8529 pinfo->clauseType = pCurrentEHClauseInfo->GetClauseType();
8530 pinfo->programCounter = pCurrentEHClauseInfo->GetIPForEHClause();
8531 pinfo->framePointer = pCurrentEHClauseInfo->GetFramePointerForEHClause();
8532 pinfo->shadowStackPointer = 0;
8537 memset(pinfo, 0, sizeof(*pinfo));
8542 HRESULT ProfToEEInterfaceImpl::GetObjectGeneration(ObjectID objectId,
8543 COR_PRF_GC_GENERATION_RANGE *range)
8557 EE_THREAD_NOT_REQUIRED;
8563 PRECONDITION(objectId != NULL);
8564 PRECONDITION(CheckPointer(range));
8565 PRECONDITION(s_generationTableLock >= 0);
8569 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8572 "**PROF: GetObjectGeneration 0x%p.\n",
8575 BEGIN_GETTHREAD_ALLOWED;
8576 _ASSERTE((GetThread() == NULL) || (GetThread()->PreemptiveGCDisabled()));
8577 END_GETTHREAD_ALLOWED;
8579 // Announce we are using the generation table now
8580 CounterHolder genTableLock(&s_generationTableLock);
8582 GenerationTable *generationTable = s_currentGenerationTable;
8584 if (generationTable == NULL)
8589 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8591 GenerationDesc *genDescTable = generationTable->genDescTable;
8592 ULONG count = generationTable->count;
8593 for (ULONG i = 0; i < count; i++)
8595 if (genDescTable[i].rangeStart <= (BYTE *)objectId && (BYTE *)objectId < genDescTable[i].rangeEndReserved)
8597 range->generation = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8598 range->rangeStart = (ObjectID)genDescTable[i].rangeStart;
8599 range->rangeLength = genDescTable[i].rangeEnd - genDescTable[i].rangeStart;
8600 range->rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8609 HRESULT ProfToEEInterfaceImpl::GetReJITIDs(
8610 FunctionID functionId, // in
8611 ULONG cReJitIds, // in
8612 ULONG * pcReJitIds, // out
8613 ReJITID reJitIds[]) // out
8620 // taking a lock causes a GC
8626 // The rejit tables use a lock
8630 PRECONDITION(CheckPointer(pcReJitIds, NULL_OK));
8631 PRECONDITION(CheckPointer(reJitIds, NULL_OK));
8636 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8637 kP2EEAllowableAfterAttach,
8640 "**PROF: GetReJITIDs 0x%p.\n",
8643 if (functionId == 0)
8645 return E_INVALIDARG;
8648 if ((cReJitIds == 0) || (pcReJitIds == NULL) || (reJitIds == NULL))
8650 return E_INVALIDARG;
8653 MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
8655 return ReJitManager::GetReJITIDs(pMD, cReJitIds, pcReJitIds, reJitIds);
8658 HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG cFunctions, // in
8659 ModuleID moduleIds[], // in
8660 mdMethodDef methodIds[]) // in
8667 // When we suspend the runtime we drop into premptive mode
8673 // We need to suspend the runtime, this takes a lot of locks!
8677 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8678 PRECONDITION(CheckPointer(methodIds, NULL_OK));
8682 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8683 kP2EETriggers | kP2EEAllowableAfterAttach,
8686 "**PROF: RequestReJIT.\n"));
8688 if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
8690 return CORPROF_E_CALLBACK4_REQUIRED;
8693 if (!CORProfilerEnableRejit())
8695 return CORPROF_E_REJIT_NOT_ENABLED;
8698 // Request at least 1 method to reJIT!
8699 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8701 return E_INVALIDARG;
8704 // Remember the profiler is doing this, as that means we must never detach it!
8705 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8708 return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds, static_cast<COR_PRF_REJIT_FLAGS>(0));
8711 HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG cFunctions, // in
8712 ModuleID moduleIds[], // in
8713 mdMethodDef methodIds[], // in
8714 HRESULT rgHrStatuses[]) // out
8721 // The rejit manager requires a lock to iterate through methods to revert, and
8722 // taking the lock can drop us into preemptive mode.
8728 // The rejit manager requires a lock to iterate through methods to revert
8732 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8733 PRECONDITION(CheckPointer(methodIds, NULL_OK));
8734 PRECONDITION(CheckPointer(rgHrStatuses, NULL_OK));
8738 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8739 kP2EEAllowableAfterAttach | kP2EETriggers,
8742 "**PROF: RequestRevert.\n"));
8744 if (!CORProfilerEnableRejit())
8746 return CORPROF_E_REJIT_NOT_ENABLED;
8749 // Request at least 1 method to revert!
8750 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8752 return E_INVALIDARG;
8755 // Remember the profiler is doing this, as that means we must never detach it!
8756 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8758 // Initialize the status array
8759 if (rgHrStatuses != NULL)
8761 memset(rgHrStatuses, 0, sizeof(HRESULT) * cFunctions);
8762 _ASSERTE(S_OK == rgHrStatuses[0]);
8766 return ReJitManager::RequestRevert(cFunctions, moduleIds, methodIds, rgHrStatuses);
8770 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions(ICorProfilerFunctionEnum ** ppEnum)
8783 // If we're in preemptive mode we need to take a read lock to safely walk
8784 // the JIT data structures.
8788 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8793 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8796 "**PROF: EnumJITedFunctions.\n"));
8800 return E_INVALIDARG;
8805 NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8806 if (pJitEnum == NULL)
8808 return E_OUTOFMEMORY;
8811 if (!pJitEnum->Init())
8813 return E_OUTOFMEMORY;
8816 // Ownership transferred to [out] param. Caller must Release() when done with this.
8817 *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8822 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions2(ICorProfilerFunctionEnum ** ppEnum)
8829 // Gathering rejitids requires taking a lock and that lock might switch to
8830 // preemptimve mode...
8836 // If we're in preemptive mode we need to take a read lock to safely walk
8837 // the JIT data structures.
8838 // Gathering RejitIDs also takes a lock.
8842 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8847 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8848 kP2EEAllowableAfterAttach | kP2EETriggers,
8851 "**PROF: EnumJITedFunctions.\n"));
8855 return E_INVALIDARG;
8860 NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8861 if (pJitEnum == NULL)
8863 return E_OUTOFMEMORY;
8866 if (!pJitEnum->Init(TRUE /* fWithReJITIDs */))
8868 // If it fails, it's because of OOM.
8869 return E_OUTOFMEMORY;
8872 // Ownership transferred to [out] param. Caller must Release() when done with this.
8873 *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8878 HRESULT ProfToEEInterfaceImpl::EnumModules(ICorProfilerModuleEnum ** ppEnum)
8885 // This method populates the enumerator, which requires iterating over
8886 // AppDomains, which adds, then releases, a reference on each AppDomain iterated.
8887 // This causes locking, and can cause triggering if the AppDomain gets destroyed
8888 // as a result of the release. (See code:AppDomainIterator::Next and its call to
8889 // code:AppDomain::Release.)
8895 // (See comment above GC_TRIGGERS.)
8899 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8904 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8905 kP2EEAllowableAfterAttach | kP2EETriggers,
8908 "**PROF: EnumModules.\n"));
8914 return E_INVALIDARG;
8919 // ProfilerModuleEnum uese AppDomainIterator, which cannot be called while the current thead
8920 // is holding the ThreadStore lock.
8921 if (ThreadStore::HoldingThreadStore())
8923 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
8926 NewHolder<ProfilerModuleEnum> pModuleEnum(new (nothrow) ProfilerModuleEnum);
8927 if (pModuleEnum == NULL)
8929 return E_OUTOFMEMORY;
8932 hr = pModuleEnum->Init();
8938 // Ownership transferred to [out] param. Caller must Release() when done with this.
8939 *ppEnum = (ICorProfilerModuleEnum *) pModuleEnum.Extract();
8944 HRESULT ProfToEEInterfaceImpl::GetRuntimeInformation(USHORT * pClrInstanceId,
8945 COR_PRF_RUNTIME_TYPE * pRuntimeType,
8946 USHORT * pMajorVersion,
8947 USHORT * pMinorVersion,
8948 USHORT * pBuildNumber,
8949 USHORT * pQFEVersion,
8950 ULONG cchVersionString,
8951 ULONG * pcchVersionString,
8952 __out_ecount_part_opt(cchVersionString, *pcchVersionString) WCHAR szVersionString[])
8966 EE_THREAD_NOT_REQUIRED;
8974 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8977 "**PROF: GetRuntimeInformation.\n"));
8979 if ((szVersionString != NULL) && (pcchVersionString == NULL))
8981 return E_INVALIDARG;
8984 if (pcchVersionString != NULL)
8986 HRESULT hr = GetCORVersionInternal(szVersionString, (DWORD)cchVersionString, (DWORD *)pcchVersionString);
8991 if (pClrInstanceId != NULL)
8992 *pClrInstanceId = static_cast<USHORT>(GetClrInstanceId());
8994 if (pRuntimeType != NULL)
8996 *pRuntimeType = COR_PRF_CORE_CLR;
8999 if (pMajorVersion != NULL)
9000 *pMajorVersion = CLR_MAJOR_VERSION;
9002 if (pMinorVersion != NULL)
9003 *pMinorVersion = CLR_MINOR_VERSION;
9005 if (pBuildNumber != NULL)
9006 *pBuildNumber = CLR_BUILD_VERSION;
9008 if (pQFEVersion != NULL)
9009 *pQFEVersion = CLR_BUILD_VERSION_QFE;
9015 HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds)
9022 // Crst is used in ProfilingAPIDetach::RequestProfilerDetach so GC may be triggered
9029 EE_THREAD_NOT_REQUIRED;
9031 // Crst is used in ProfilingAPIDetach::RequestProfilerDetach
9036 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9037 kP2EEAllowableAfterAttach | kP2EETriggers,
9040 "**PROF: RequestProfilerDetach.\n"));
9042 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
9043 return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds);
9044 #else // FEATURE_PROFAPI_ATTACH_DETACH
9046 #endif // FEATURE_PROFAPI_ATTACH_DETACH
9049 typedef struct _COR_PRF_ELT_INFO_INTERNAL
9051 // Point to a platform dependent structure ASM helper push on the stack
9052 void * platformSpecificHandle;
9054 // startAddress of COR_PRF_FUNCTION_ARGUMENT_RANGE structure needs to point
9055 // TO the argument value, not BE the argument value. So, when the argument
9056 // is this, we need to point TO this. Because of the calling sequence change
9057 // in ELT3, we need to reserve the pointer here instead of using one of our
9061 // Reserve space for output parameter COR_PRF_FRAME_INFO of
9062 // GetFunctionXXXX3Info functions
9063 COR_PRF_FRAME_INFO_INTERNAL frameInfo;
9065 } COR_PRF_ELT_INFO_INTERNAL;
9067 //---------------------------------------------------------------------------------------
9069 // ProfilingGetFunctionEnter3Info provides frame information and argument infomation of
9070 // the function ELT callback is inspecting. It is called either by the profiler or the
9071 // C helper function.
9074 // * functionId - [in] FunctionId of the function being inspected by ELT3
9075 // * eltInfo - [in] The opaque pointer FunctionEnter3WithInfo callback passed to the profiler
9076 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9078 // * pcbArgumentInfo - [in, out] Pointer to ULONG that specifies the size of structure
9079 // pointed by pArgumentInfo
9080 // * pArgumentInfo - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_INFO structure the profiler
9081 // must preserve enough space for the function it is inspecting
9084 // HRESULT indicating success or failure.
9087 HRESULT ProfilingGetFunctionEnter3Info(FunctionID functionId, // in
9088 COR_PRF_ELT_INFO eltInfo, // in
9089 COR_PRF_FRAME_INFO * pFrameInfo, // out
9090 ULONG * pcbArgumentInfo, // in, out
9091 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo) // out
9104 // ProfileArgIterator::ProfileArgIterator may take locks
9111 if ((functionId == NULL) || (eltInfo == NULL))
9113 return E_INVALIDARG;
9116 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9117 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9119 // The loader won't trigger a GC or throw for already loaded argument types.
9120 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9123 // Find the method this is referring to, so we can get the signature
9125 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9126 MetaSig metaSig(pMethodDesc);
9128 NewHolder<ProfileArgIterator> pProfileArgIterator;
9131 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9134 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9136 if (pProfileArgIterator == NULL)
9138 return E_UNEXPECTED;
9142 if (CORProfilerFrameInfoEnabled())
9144 if (pFrameInfo == NULL)
9146 return E_INVALIDARG;
9150 // Setup the COR_PRF_FRAME_INFO structure first.
9152 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9154 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9155 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9156 pCorPrfFrameInfo->funcID = functionId;
9157 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9158 pCorPrfFrameInfo->extraArg = pProfileArgIterator->GetHiddenArgValue();
9159 pCorPrfFrameInfo->thisArg = pProfileArgIterator->GetThis();
9161 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9165 // Do argument processing if desired.
9167 if (CORProfilerFunctionArgsEnabled())
9169 if (pcbArgumentInfo == NULL)
9171 return E_INVALIDARG;
9174 if ((*pcbArgumentInfo != 0) && (pArgumentInfo == NULL))
9176 return E_INVALIDARG;
9179 ULONG32 count = pProfileArgIterator->GetNumArgs();
9181 if (metaSig.HasThis())
9186 ULONG ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + (count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE));
9188 if (*pcbArgumentInfo < ulArgInfoSize)
9190 *pcbArgumentInfo = ulArgInfoSize;
9191 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
9194 _ASSERTE(pArgumentInfo != NULL);
9196 pArgumentInfo->numRanges = count;
9197 pArgumentInfo->totalArgumentSize = 0;
9201 if (metaSig.HasThis())
9203 pELTInfo->pThis = pProfileArgIterator->GetThis();
9204 pArgumentInfo->ranges[count].startAddress = (UINT_PTR) (&(pELTInfo->pThis));
9206 UINT length = sizeof(pELTInfo->pThis);
9207 pArgumentInfo->ranges[count].length = length;
9208 pArgumentInfo->totalArgumentSize += length;
9212 while (count < pArgumentInfo->numRanges)
9214 pArgumentInfo->ranges[count].startAddress = (UINT_PTR)(pProfileArgIterator->GetNextArgAddr());
9216 UINT length = pProfileArgIterator->GetArgSize();
9217 pArgumentInfo->ranges[count].length = length;
9218 pArgumentInfo->totalArgumentSize += length;
9228 HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId, // in
9229 COR_PRF_ELT_INFO eltInfo, // in
9230 COR_PRF_FRAME_INFO * pFrameInfo, // out
9231 ULONG * pcbArgumentInfo, // in, out
9232 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo) // out
9245 // ProfilingGetFunctionEnter3Info may take locks
9252 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9254 "**PROF: GetFunctionEnter3Info.\n"));
9256 _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL);
9258 if (!CORProfilerELT3SlowPathEnterEnabled())
9260 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9263 return ProfilingGetFunctionEnter3Info(functionId, eltInfo, pFrameInfo, pcbArgumentInfo, pArgumentInfo);
9266 //---------------------------------------------------------------------------------------
9268 // ProfilingGetFunctionLeave3Info provides frame information and return value infomation
9269 // of the function ELT callback is inspecting. It is called either by the profiler or the
9270 // C helper function.
9273 // * functionId - [in] FunctionId of the function being inspected by ELT3
9274 // * eltInfo - [in] The opaque pointer FunctionLeave3WithInfo callback passed to the profiler
9275 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9277 // * pRetvalRange - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_RANGE to store return value
9280 // HRESULT indicating success or failure.
9283 HRESULT ProfilingGetFunctionLeave3Info(FunctionID functionId, // in
9284 COR_PRF_ELT_INFO eltInfo, // in
9285 COR_PRF_FRAME_INFO * pFrameInfo, // out
9286 COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange) // out
9299 // ProfileArgIterator::ProfileArgIterator may take locks
9305 if ((pFrameInfo == NULL) || (eltInfo == NULL))
9307 return E_INVALIDARG;
9310 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9311 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9313 // The loader won't trigger a GC or throw for already loaded argument types.
9314 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9317 // Find the method this is referring to, so we can get the signature
9319 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9320 MetaSig metaSig(pMethodDesc);
9322 NewHolder<ProfileArgIterator> pProfileArgIterator;
9325 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9328 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9330 if (pProfileArgIterator == NULL)
9332 return E_UNEXPECTED;
9336 if (CORProfilerFrameInfoEnabled())
9338 if (pFrameInfo == NULL)
9340 return E_INVALIDARG;
9343 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9346 // Setup the COR_PRF_FRAME_INFO structure first.
9348 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9349 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9350 pCorPrfFrameInfo->funcID = functionId;
9351 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9353 // Upon entering Leave hook, the register assigned to store this pointer on function calls may
9354 // already be reused and is likely not to contain this pointer.
9355 pCorPrfFrameInfo->extraArg = NULL;
9356 pCorPrfFrameInfo->thisArg = NULL;
9358 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9362 // Do argument processing if desired.
9364 if (CORProfilerFunctionReturnValueEnabled())
9366 if (pRetvalRange == NULL)
9368 return E_INVALIDARG;
9371 if (!metaSig.IsReturnTypeVoid())
9373 pRetvalRange->length = metaSig.GetReturnTypeSize();
9374 pRetvalRange->startAddress = (UINT_PTR)pProfileArgIterator->GetReturnBufferAddr();
9378 pRetvalRange->length = 0;
9379 pRetvalRange->startAddress = 0;
9387 HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId, // in
9388 COR_PRF_ELT_INFO eltInfo, // in
9389 COR_PRF_FRAME_INFO * pFrameInfo, // out
9390 COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange) // out
9403 // ProfilingGetFunctionLeave3Info may take locks
9410 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9412 "**PROF: GetFunctionLeave3Info.\n"));
9414 _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL);
9416 if (!CORProfilerELT3SlowPathLeaveEnabled())
9418 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9421 return ProfilingGetFunctionLeave3Info(functionId, eltInfo, pFrameInfo, pRetvalRange);
9424 //---------------------------------------------------------------------------------------
9426 // ProfilingGetFunctionTailcall3Info provides frame information of the function ELT callback
9427 // is inspecting. It is called either by the profiler or the C helper function.
9430 // * functionId - [in] FunctionId of the function being inspected by ELT3
9431 // * eltInfo - [in] The opaque pointer FunctionTailcall3WithInfo callback passed to the
9433 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9437 // HRESULT indicating success or failure.
9440 HRESULT ProfilingGetFunctionTailcall3Info(FunctionID functionId, // in
9441 COR_PRF_ELT_INFO eltInfo, // in
9442 COR_PRF_FRAME_INFO * pFrameInfo) // out
9455 // ProfileArgIterator::ProfileArgIterator may take locks
9462 if ((functionId == NULL) || (eltInfo == NULL) || (pFrameInfo == NULL))
9464 return E_INVALIDARG;
9467 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9468 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9470 // The loader won't trigger a GC or throw for already loaded argument types.
9471 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9474 // Find the method this is referring to, so we can get the signature
9476 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9477 MetaSig metaSig(pMethodDesc);
9479 NewHolder<ProfileArgIterator> pProfileArgIterator;
9482 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9485 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9487 if (pProfileArgIterator == NULL)
9489 return E_UNEXPECTED;
9493 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9496 // Setup the COR_PRF_FRAME_INFO structure first.
9498 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9499 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9500 pCorPrfFrameInfo->funcID = functionId;
9501 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9503 // Tailcall is designed to report the caller, not the callee. But the taillcall hook is invoked
9504 // with registers containing parameters passed to the callee before calling into the callee.
9505 // This pointer we get here is for the callee. Because of the constraints imposed on tailcall
9506 // optimization, this pointer passed to the callee accidentally happens to be the same this pointer
9507 // passed to the caller.
9509 // It is a fragile coincidence we should not depend on because JIT is free to change the
9510 // implementation details in the future.
9511 pCorPrfFrameInfo->extraArg = NULL;
9512 pCorPrfFrameInfo->thisArg = NULL;
9514 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9520 HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId, // in
9521 COR_PRF_ELT_INFO eltInfo, // in
9522 COR_PRF_FRAME_INFO * pFrameInfo) // out
9535 // ProfilingGetFunctionTailcall3Info may take locks
9542 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9544 "**PROF: GetFunctionTailcall3Info.\n"));
9546 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL);
9548 if (!CORProfilerELT3SlowPathTailcallEnabled())
9550 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9553 return ProfilingGetFunctionTailcall3Info(functionId, eltInfo, pFrameInfo);
9556 HRESULT ProfToEEInterfaceImpl::EnumThreads(
9557 /* out */ ICorProfilerThreadEnum ** ppEnum)
9571 // Need to acquire the thread store lock
9575 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
9580 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9581 kP2EEAllowableAfterAttach,
9584 "**PROF: EnumThreads.\n"));
9590 return E_INVALIDARG;
9595 NewHolder<ProfilerThreadEnum> pThreadEnum(new (nothrow) ProfilerThreadEnum);
9596 if (pThreadEnum == NULL)
9598 return E_OUTOFMEMORY;
9601 hr = pThreadEnum->Init();
9607 // Ownership transferred to [out] param. Caller must Release() when done with this.
9608 *ppEnum = (ICorProfilerThreadEnum *) pThreadEnum.Extract();
9613 // This function needs to be called on any thread before making any ICorProfilerInfo* calls and must be
9614 // made before any thread is suspended by this profiler.
9615 // As you might have already figured out, this is done to avoid deadlocks situation when
9616 // the suspended thread holds on the loader lock / heap lock while the current thread is trying to obtain
9618 HRESULT ProfToEEInterfaceImpl::InitializeCurrentThread()
9632 // May take thread store lock and OS APIs may also take locks
9639 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9640 kP2EEAllowableAfterAttach,
9643 "**PROF: InitializeCurrentThread.\n"));
9649 CExecutionEngine::SetupTLSForThread(GetThread());
9651 EX_CATCH_HRESULT(hr);
9659 struct InternalProfilerModuleEnum : public ProfilerModuleEnum
9661 CDynArray<ModuleID> *GetRawElementsArray()
9667 HRESULT ProfToEEInterfaceImpl::EnumNgenModuleMethodsInliningThisMethod(
9668 ModuleID inlinersModuleId,
9669 ModuleID inlineeModuleId,
9670 mdMethodDef inlineeMethodId,
9671 BOOL *incompleteData,
9672 ICorProfilerMethodEnum** ppEnum)
9680 PRECONDITION(CheckPointer(ppEnum));
9684 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: EnumNgenModuleMethodsInliningThisMethod.\n"));
9688 return E_INVALIDARG;
9693 Module *inlineeOwnerModule = reinterpret_cast<Module *>(inlineeModuleId);
9694 if (inlineeOwnerModule == NULL)
9696 return E_INVALIDARG;
9698 if (inlineeOwnerModule->IsBeingUnloaded())
9700 return CORPROF_E_DATAINCOMPLETE;
9703 Module *inlinersModule = reinterpret_cast<Module *>(inlinersModuleId);
9704 if (inlinersModule == NULL)
9706 return E_INVALIDARG;
9708 if(inlinersModule->IsBeingUnloaded())
9710 return CORPROF_E_DATAINCOMPLETE;
9713 if (!inlinersModule->HasNativeOrReadyToRunInlineTrackingMap())
9715 return CORPROF_E_DATAINCOMPLETE;
9718 CDynArray<COR_PRF_METHOD> results;
9719 const COUNT_T staticBufferSize = 10;
9720 MethodInModule staticBuffer[staticBufferSize];
9721 NewArrayHolder<MethodInModule> dynamicBuffer;
9722 MethodInModule *methodsBuffer = staticBuffer;
9725 // Trying to use static buffer
9726 COUNT_T methodsAvailable = inlinersModule->GetNativeOrReadyToRunInliners(inlineeOwnerModule, inlineeMethodId, staticBufferSize, staticBuffer, incompleteData);
9728 // If static buffer is not enough, allocate an array.
9729 if (methodsAvailable > staticBufferSize)
9731 DWORD dynamicBufferSize = methodsAvailable;
9732 dynamicBuffer = methodsBuffer = new MethodInModule[dynamicBufferSize];
9733 methodsAvailable = inlinersModule->GetNativeOrReadyToRunInliners(inlineeOwnerModule, inlineeMethodId, dynamicBufferSize, dynamicBuffer, incompleteData);
9734 if (methodsAvailable > dynamicBufferSize)
9736 _ASSERTE(!"Ngen image inlining info changed, this shouldn't be possible.");
9737 methodsAvailable = dynamicBufferSize;
9741 //Go through all inliners found in the inlinersModule and prepare them to export via results.
9742 results.AllocateBlockThrowing(methodsAvailable);
9743 for (COUNT_T j = 0; j < methodsAvailable; j++)
9745 COR_PRF_METHOD *newPrfMethod = &results[j];
9746 newPrfMethod->moduleId = reinterpret_cast<ModuleID>(methodsBuffer[j].m_module);
9747 newPrfMethod->methodId = methodsBuffer[j].m_methodDef;
9749 *ppEnum = new ProfilerMethodEnum(&results);
9751 EX_CATCH_HRESULT(hr);
9756 HRESULT ProfToEEInterfaceImpl::GetInMemorySymbolsLength(
9758 DWORD* pCountSymbolBytes)
9770 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9771 kP2EEAllowableAfterAttach,
9774 "**PROF: GetInMemorySymbolsLength.\n"));
9777 if (pCountSymbolBytes == NULL)
9779 return E_INVALIDARG;
9781 *pCountSymbolBytes = 0;
9783 Module* pModule = reinterpret_cast< Module* >(moduleId);
9784 if (pModule == NULL)
9786 return E_INVALIDARG;
9788 if (pModule->IsBeingUnloaded())
9790 return CORPROF_E_DATAINCOMPLETE;
9793 //This method would work fine on reflection.emit, but there would be no way to know
9794 //if some other thread was changing the size of the symbols before this method returned.
9795 //Adding events or locks to detect/prevent changes would make the scenario workable
9796 if (pModule->IsReflection())
9798 return COR_PRF_MODULE_DYNAMIC;
9801 CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9802 if (pStream == NULL)
9807 STATSTG SizeData = { 0 };
9808 hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9813 if (SizeData.cbSize.u.HighPart > 0)
9815 return COR_E_OVERFLOW;
9817 *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
9822 HRESULT ProfToEEInterfaceImpl::ReadInMemorySymbols(
9824 DWORD symbolsReadOffset,
9826 DWORD countSymbolBytes,
9827 DWORD* pCountSymbolBytesRead)
9837 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9838 kP2EEAllowableAfterAttach,
9841 "**PROF: ReadInMemorySymbols.\n"));
9844 if (pSymbolBytes == NULL)
9846 return E_INVALIDARG;
9848 if (pCountSymbolBytesRead == NULL)
9850 return E_INVALIDARG;
9852 *pCountSymbolBytesRead = 0;
9854 Module* pModule = reinterpret_cast< Module* >(moduleId);
9855 if (pModule == NULL)
9857 return E_INVALIDARG;
9859 if (pModule->IsBeingUnloaded())
9861 return CORPROF_E_DATAINCOMPLETE;
9864 //This method would work fine on reflection.emit, but there would be no way to know
9865 //if some other thread was changing the size of the symbols before this method returned.
9866 //Adding events or locks to detect/prevent changes would make the scenario workable
9867 if (pModule->IsReflection())
9869 return COR_PRF_MODULE_DYNAMIC;
9872 CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9873 if (pStream == NULL)
9875 return E_INVALIDARG;
9878 STATSTG SizeData = { 0 };
9879 hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9884 if (SizeData.cbSize.u.HighPart > 0)
9886 return COR_E_OVERFLOW;
9888 DWORD streamSize = SizeData.cbSize.u.LowPart;
9889 if (symbolsReadOffset >= streamSize)
9891 return E_INVALIDARG;
9894 *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
9895 memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
9900 HRESULT ProfToEEInterfaceImpl::ApplyMetaData(
9911 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach | kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: ApplyMetaData.\n"));
9913 if (moduleId == NULL)
9915 return E_INVALIDARG;
9921 Module *pModule = (Module *)moduleId;
9922 _ASSERTE(pModule != NULL);
9923 if (pModule->IsBeingUnloaded())
9925 hr = CORPROF_E_DATAINCOMPLETE;
9929 pModule->ApplyMetaData();
9932 EX_CATCH_HRESULT(hr);
9936 //---------------------------------------------------------------------------------------
9938 // Simple wrapper around EEToProfInterfaceImpl::ManagedToUnmanagedTransition. This
9939 // can be called by C++ code and directly by generated stubs.
9942 // pMD - MethodDesc for the managed function involved in the transition
9943 // reason - Passed on to profiler to indicate why the transition is occurring
9946 void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD,
9947 COR_PRF_TRANSITION_REASON reason)
9957 // This function is called within the runtime, not directly from managed code.
9958 // Also, the only case MD is NULL is the calli pinvoke case, and we still
9959 // want to notify the profiler in that case.
9961 // Do not notify the profiler about QCalls
9962 if (pMD == NULL || !pMD->IsQCall())
9964 BEGIN_PIN_PROFILER(CORProfilerPresent());
9965 g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD),
9971 //---------------------------------------------------------------------------------------
9973 // Simple wrapper around EEToProfInterfaceImpl::UnmanagedToManagedTransition. This
9974 // can be called by C++ code and directly by generated stubs.
9977 // pMD - MethodDesc for the managed function involved in the transition
9978 // reason - Passed on to profiler to indicate why the transition is occurring
9981 void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD,
9982 COR_PRF_TRANSITION_REASON reason)
9992 // This function is called within the runtime, not directly from managed code.
9993 // Also, the only case MD is NULL is the calli pinvoke case, and we still
9994 // want to notify the profiler in that case.
9996 // Do not notify the profiler about QCalls
9997 if (pMD == NULL || !pMD->IsQCall())
9999 BEGIN_PIN_PROFILER(CORProfilerPresent());
10000 g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD),
10002 END_PIN_PROFILER();
10008 #endif // PROFILING_SUPPORTED
10011 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemoting)
10015 #ifdef PROFILING_SUPPORTED
10016 FC_RETURN_BOOL(CORProfilerTrackRemoting());
10017 #else // !PROFILING_SUPPORTED
10018 FC_RETURN_BOOL(FALSE);
10019 #endif // !PROFILING_SUPPORTED
10023 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingCookie)
10027 #ifdef PROFILING_SUPPORTED
10028 FC_RETURN_BOOL(CORProfilerTrackRemotingCookie());
10029 #else // !PROFILING_SUPPORTED
10030 FC_RETURN_BOOL(FALSE);
10031 #endif // !PROFILING_SUPPORTED
10035 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingAsync)
10039 #ifdef PROFILING_SUPPORTED
10040 FC_RETURN_BOOL(CORProfilerTrackRemotingAsync());
10041 #else // !PROFILING_SUPPORTED
10042 FC_RETURN_BOOL(FALSE);
10043 #endif // !PROFILING_SUPPORTED
10047 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingClientSendingMessage, GUID *pId, CLR_BOOL fIsAsync)
10051 #ifdef PROFILING_SUPPORTED
10052 // Need to erect a GC frame so that GCs can occur without a problem
10053 // within the profiler code.
10055 // Note that we don't need to worry about pId moving around since
10056 // it is a value class declared on the stack and so GC doesn't
10059 _ASSERTE (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pId)); // should be on the stack, not in the heap
10060 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10063 BEGIN_PIN_PROFILER(CORProfilerPresent());
10065 if (CORProfilerTrackRemotingCookie())
10067 g_profControlBlock.pProfInterface->GetGUID(pId);
10068 _ASSERTE(pId->Data1);
10070 g_profControlBlock.pProfInterface->RemotingClientSendingMessage(pId, fIsAsync);
10074 g_profControlBlock.pProfInterface->RemotingClientSendingMessage(NULL, fIsAsync);
10076 END_PIN_PROFILER();
10078 HELPER_METHOD_FRAME_END_POLL();
10079 #endif // PROFILING_SUPPORTED
10084 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingClientReceivingReply, GUID id, CLR_BOOL fIsAsync)
10088 #ifdef PROFILING_SUPPORTED
10089 // Need to erect a GC frame so that GCs can occur without a problem
10090 // within the profiler code.
10092 // Note that we don't need to worry about pId moving around since
10093 // it is a value class declared on the stack and so GC doesn't
10096 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10100 BEGIN_PIN_PROFILER(CORProfilerPresent());
10102 if (CORProfilerTrackRemotingCookie())
10104 g_profControlBlock.pProfInterface->RemotingClientReceivingReply(&id, fIsAsync);
10108 g_profControlBlock.pProfInterface->RemotingClientReceivingReply(NULL, fIsAsync);
10110 END_PIN_PROFILER();
10113 HELPER_METHOD_FRAME_END_POLL();
10114 #endif // PROFILING_SUPPORTED
10119 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingServerReceivingMessage, GUID id, CLR_BOOL fIsAsync)
10123 #ifdef PROFILING_SUPPORTED
10124 // Need to erect a GC frame so that GCs can occur without a problem
10125 // within the profiler code.
10127 // Note that we don't need to worry about pId moving around since
10128 // it is a value class declared on the stack and so GC doesn't
10131 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10134 BEGIN_PIN_PROFILER(CORProfilerPresent());
10136 if (CORProfilerTrackRemotingCookie())
10138 g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(&id, fIsAsync);
10142 g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(NULL, fIsAsync);
10144 END_PIN_PROFILER();
10147 HELPER_METHOD_FRAME_END_POLL();
10148 #endif // PROFILING_SUPPORTED
10152 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingServerSendingReply, GUID *pId, CLR_BOOL fIsAsync)
10156 #ifdef PROFILING_SUPPORTED
10157 // Need to erect a GC frame so that GCs can occur without a problem
10158 // within the profiler code.
10160 // Note that we don't need to worry about pId moving around since
10161 // it is a value class declared on the stack and so GC doesn't
10164 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10167 BEGIN_PIN_PROFILER(CORProfilerPresent());
10169 if (CORProfilerTrackRemotingCookie())
10171 g_profControlBlock.pProfInterface->GetGUID(pId);
10172 _ASSERTE(pId->Data1);
10174 g_profControlBlock.pProfInterface->RemotingServerSendingReply(pId, fIsAsync);
10178 g_profControlBlock.pProfInterface->RemotingServerSendingReply(NULL, fIsAsync);
10180 END_PIN_PROFILER();
10183 HELPER_METHOD_FRAME_END_POLL();
10184 #endif // PROFILING_SUPPORTED
10189 //*******************************************************************************************
10190 // These do a lot of work for us, setting up Frames, gathering arg info and resolving generics.
10191 //*******************************************************************************************
10193 HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecificHandle)
10197 #ifdef PROFILING_SUPPORTED
10199 #ifdef PROF_TEST_ONLY_FORCE_ELT
10200 // If this test-only flag is set, it's possible we might not have a profiler
10201 // attached, or might not have any of the hooks set. See
10202 // code:ProfControlBlock#TestOnlyELT
10203 if (g_profControlBlock.fTestOnlyForceEnterLeave)
10205 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10207 (g_profControlBlock.pProfInterface->GetEnterHook() == NULL) &&
10208 (g_profControlBlock.pProfInterface->GetEnter2Hook() == NULL) &&
10209 (g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL) &&
10210 (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL)
10217 #endif // PROF_TEST_ONLY_FORCE_ELT
10219 // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10220 _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL);
10221 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10222 _ASSERTE(platformSpecificHandle != NULL);
10225 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10227 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10228 // frame, like we're about to do.
10229 SetCallbackStateFlagsHolder csf(
10230 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10232 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10233 eltInfo.platformSpecificHandle = platformSpecificHandle;
10236 // CLR v4 Slow-Path ELT
10238 if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL)
10240 FunctionIDOrClientID functionIDOrClientID;
10241 functionIDOrClientID.clientID = clientData;
10242 g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()(
10243 functionIDOrClientID,
10244 (COR_PRF_ELT_INFO)&eltInfo);
10248 if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL)
10250 // We have run out of heap memory, so the content of the mapping table becomes stale.
10251 // All Whidbey ETL hooks must be turned off.
10252 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10257 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10258 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10259 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10260 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10261 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10262 FunctionID functionId = clientData;
10263 _ASSERTE(functionId != NULL);
10264 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10267 // Whidbey Fast-Path ELT
10269 if (CORProfilerELT2FastPathEnterEnabled())
10271 g_profControlBlock.pProfInterface->GetEnter2Hook()(
10280 // Whidbey Slow-Path ELT
10282 ProfileSetFunctionIDInPlatformSpecificHandle(platformSpecificHandle, functionId);
10284 COR_PRF_FRAME_INFO frameInfo = NULL;
10285 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo = NULL;
10286 ULONG ulArgInfoSize = 0;
10288 if (CORProfilerFunctionArgsEnabled())
10290 // The loader won't trigger a GC or throw for already loaded argument types.
10291 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
10294 // Find the method this is referring to, so we can get the signature
10296 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
10297 MetaSig metaSig(pMethodDesc);
10299 NewHolder<ProfileArgIterator> pProfileArgIterator;
10302 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
10305 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, platformSpecificHandle);
10307 if (pProfileArgIterator == NULL)
10313 ULONG32 count = pProfileArgIterator->GetNumArgs();
10315 if (metaSig.HasThis())
10320 ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE);
10321 pArgumentInfo = (COR_PRF_FUNCTION_ARGUMENT_INFO *)_alloca(ulArgInfoSize);
10324 HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo);
10326 _ASSERTE(hr == S_OK);
10327 g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
10333 // We will not be here unless the jit'd or ngen'd function we're about to enter
10334 // was backpatched with this wrapper around the profiler's hook, and that
10335 // wouldn't have happened unless the profiler supplied us with a hook
10336 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10337 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10338 // its mind about where the hooks are.)
10339 _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL);
10341 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10342 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10343 // to enable the jitter to add enter/leave callouts independently of whether
10344 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10345 // the callouts quickly return and do nothing.)
10351 g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData);
10357 HELPER_METHOD_FRAME_END(); // Un-link the frame
10359 #endif // PROFILING_SUPPORTED
10363 HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecificHandle)
10367 FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
10369 #ifdef PROFILING_SUPPORTED
10371 #ifdef PROF_TEST_ONLY_FORCE_ELT
10372 // If this test-only flag is set, it's possible we might not have a profiler
10373 // attached, or might not have any of the hooks set. See
10374 // code:ProfControlBlock#TestOnlyELT
10375 if (g_profControlBlock.fTestOnlyForceEnterLeave)
10377 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10379 (g_profControlBlock.pProfInterface->GetLeaveHook() == NULL) &&
10380 (g_profControlBlock.pProfInterface->GetLeave2Hook() == NULL) &&
10381 (g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL) &&
10382 (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL)
10389 #endif // PROF_TEST_ONLY_FORCE_ELT
10391 // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10392 _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL);
10393 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10394 _ASSERTE(platformSpecificHandle != NULL);
10397 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10399 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10400 // frame, like we're about to do.
10401 SetCallbackStateFlagsHolder csf(
10402 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10404 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10405 eltInfo.platformSpecificHandle = platformSpecificHandle;
10408 // CLR v4 Slow-Path ELT
10410 if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL)
10412 FunctionIDOrClientID functionIDOrClientID;
10413 functionIDOrClientID.clientID = clientData;
10414 g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()(
10415 functionIDOrClientID,
10416 (COR_PRF_ELT_INFO)&eltInfo);
10420 if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL)
10422 // We have run out of heap memory, so the content of the mapping table becomes stale.
10423 // All Whidbey ETL hooks must be turned off.
10424 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10429 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10430 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10431 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10432 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10433 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10434 FunctionID functionId = clientData;
10435 _ASSERTE(functionId != NULL);
10436 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10439 // Whidbey Fast-Path ELT
10441 if (CORProfilerELT2FastPathLeaveEnabled())
10443 g_profControlBlock.pProfInterface->GetLeave2Hook()(
10452 // Whidbey Slow-Path ELT
10454 COR_PRF_FRAME_INFO frameInfo = NULL;
10455 COR_PRF_FUNCTION_ARGUMENT_RANGE argumentRange;
10457 HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange);
10458 _ASSERTE(hr == S_OK);
10460 g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
10464 // We will not be here unless the jit'd or ngen'd function we're about to leave
10465 // was backpatched with this wrapper around the profiler's hook, and that
10466 // wouldn't have happened unless the profiler supplied us with a hook
10467 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10468 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10469 // its mind about where the hooks are.)
10470 _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL);
10472 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10473 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10474 // to enable the jitter to add enter/leave callouts independently of whether
10475 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10476 // the callouts quickly return and do nothing.)
10482 g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData);
10489 HELPER_METHOD_FRAME_END(); // Un-link the frame
10491 #endif // PROFILING_SUPPORTED
10495 HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpecificHandle)
10499 FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
10501 #ifdef PROFILING_SUPPORTED
10503 #ifdef PROF_TEST_ONLY_FORCE_ELT
10504 // If this test-only flag is set, it's possible we might not have a profiler
10505 // attached, or might not have any of the hooks set. See
10506 // code:ProfControlBlock#TestOnlyELT
10507 if (g_profControlBlock.fTestOnlyForceEnterLeave)
10509 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10511 (g_profControlBlock.pProfInterface->GetTailcallHook() == NULL) &&
10512 (g_profControlBlock.pProfInterface->GetTailcall2Hook() == NULL) &&
10513 (g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL) &&
10514 (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL)
10521 #endif // PROF_TEST_ONLY_FORCE_ELT
10523 // ELT3 fast-path hooks should be NULL when ELT intermediary is used.
10524 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL);
10525 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10526 _ASSERTE(platformSpecificHandle != NULL);
10529 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10531 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10532 // frame, like we're about to do.
10533 SetCallbackStateFlagsHolder csf(
10534 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10536 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10537 eltInfo.platformSpecificHandle = platformSpecificHandle;
10540 // CLR v4 Slow-Path ELT
10542 if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL)
10544 FunctionIDOrClientID functionIDOrClientID;
10545 functionIDOrClientID.clientID = clientData;
10546 g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()(
10547 functionIDOrClientID,
10548 (COR_PRF_ELT_INFO)&eltInfo);
10552 if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL)
10554 // We have run out of heap memory, so the content of the mapping table becomes stale.
10555 // All Whidbey ETL hooks must be turned off.
10556 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10561 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10562 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10563 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10564 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10565 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10566 FunctionID functionId = clientData;
10567 _ASSERTE(functionId != NULL);
10568 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10571 // Whidbey Fast-Path ELT
10573 if (CORProfilerELT2FastPathTailcallEnabled())
10575 g_profControlBlock.pProfInterface->GetTailcall2Hook()(
10583 // Whidbey Slow-Path ELT
10585 COR_PRF_FRAME_INFO frameInfo = NULL;
10587 HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo);
10588 _ASSERTE(hr == S_OK);
10590 g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
10594 // We will not be here unless the jit'd or ngen'd function we're about to tailcall
10595 // was backpatched with this wrapper around the profiler's hook, and that
10596 // wouldn't have happened unless the profiler supplied us with a hook
10597 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10598 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10599 // its mind about where the hooks are.)
10600 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL);
10602 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10603 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10604 // to enable the jitter to add enter/leave callouts independently of whether
10605 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10606 // the callouts quickly return and do nothing.)
10611 g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData);
10617 HELPER_METHOD_FRAME_END(); // Un-link the frame
10619 #endif // PROFILING_SUPPORTED