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();
6809 HRESULT hr = SetupThreadForReJIT();
6816 return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds, static_cast<COR_PRF_REJIT_FLAGS>(dwRejitFlags));
6820 * EnumerateObjectReferences
6822 * Enumerates the object references (if any) from the ObjectID.
6825 * objectId - object id of interest
6826 * callback - callback to call for each object reference
6827 * clientData - client data for the profiler to pass and receive for each reference
6830 * S_OK if successful, S_FALSE if no references
6833 HRESULT ProfToEEInterfaceImpl::EnumerateObjectReferences(ObjectID objectId, ObjectReferenceCallback callback, void* clientData)
6840 EE_THREAD_NOT_REQUIRED;
6845 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6846 kP2EEAllowableAfterAttach,
6849 "**PROF: EnumerateObjectReferences 0x%p.\n",
6852 if (callback == nullptr)
6854 return E_INVALIDARG;
6857 Object* pBO = (Object*)objectId;
6858 MethodTable *pMT = pBO->GetMethodTable();
6860 if (pMT->ContainsPointersOrCollectible())
6862 GCHeapUtilities::GetGCHeap()->DiagWalkObject2(pBO, (walk_fn2)callback, clientData);
6874 * Determines whether the object is in a read-only segment
6877 * objectId - object id of interest
6880 * S_OK if successful
6883 HRESULT ProfToEEInterfaceImpl::IsFrozenObject(ObjectID objectId, BOOL *pbFrozen)
6890 EE_THREAD_NOT_REQUIRED;
6895 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6896 kP2EEAllowableAfterAttach,
6899 "**PROF: IsFrozenObject 0x%p.\n",
6902 *pbFrozen = GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)objectId) ? TRUE : FALSE;
6908 * GetLOHObjectSizeThreshold
6910 * Gets the value of the configured LOH Threshold.
6913 * pThreshold - value of the threshold in bytes
6916 * S_OK if successful
6919 HRESULT ProfToEEInterfaceImpl::GetLOHObjectSizeThreshold(DWORD *pThreshold)
6926 EE_THREAD_NOT_REQUIRED;
6931 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6932 kP2EEAllowableAfterAttach,
6935 "**PROF: GetLOHObjectSizeThreshold\n"));
6937 if (pThreshold == nullptr)
6939 return E_INVALIDARG;
6942 *pThreshold = g_pConfig->GetGCLOHThreshold();
6947 HRESULT ProfToEEInterfaceImpl::SuspendRuntime()
6955 EE_THREAD_NOT_REQUIRED;
6959 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6960 kP2EEAllowableAfterAttach | kP2EETriggers,
6963 "**PROF: SuspendRuntime\n"));
6967 return CORPROF_E_RUNTIME_UNINITIALIZED;
6970 if (ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0))
6972 return CORPROF_E_SUSPENSION_IN_PROGRESS;
6975 g_profControlBlock.fProfilerRequestedRuntimeSuspend = TRUE;
6976 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_REASON::SUSPEND_FOR_PROFILER);
6980 HRESULT ProfToEEInterfaceImpl::ResumeRuntime()
6991 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6992 kP2EEAllowableAfterAttach | kP2EETriggers,
6995 "**PROF: ResumeRuntime\n"));
6999 return CORPROF_E_RUNTIME_UNINITIALIZED;
7002 if (!g_profControlBlock.fProfilerRequestedRuntimeSuspend)
7004 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
7007 ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */);
7008 g_profControlBlock.fProfilerRequestedRuntimeSuspend = FALSE;
7015 * This function describes to a profiler the internal layout of a string.
7018 * pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7019 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7020 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7023 * S_OK if successful.
7025 HRESULT ProfToEEInterfaceImpl::GetStringLayout(ULONG *pBufferLengthOffset,
7026 ULONG *pStringLengthOffset,
7027 ULONG *pBufferOffset)
7041 EE_THREAD_NOT_REQUIRED;
7047 PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7048 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7049 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
7053 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7056 "**PROF: GetStringLayout.\n"));
7058 return this->GetStringLayoutHelper(pBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7064 * This function describes to a profiler the internal layout of a string.
7067 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7068 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7071 * S_OK if successful.
7073 HRESULT ProfToEEInterfaceImpl::GetStringLayout2(ULONG *pStringLengthOffset,
7074 ULONG *pBufferOffset)
7088 EE_THREAD_NOT_REQUIRED;
7094 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7095 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
7099 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7102 "**PROF: GetStringLayout2.\n"));
7104 ULONG dummyBufferLengthOffset;
7105 return this->GetStringLayoutHelper(&dummyBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7109 * GetStringLayoutHelper
7111 * This function describes to a profiler the internal layout of a string.
7114 * pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7115 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7116 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7119 * S_OK if successful.
7121 HRESULT ProfToEEInterfaceImpl::GetStringLayoutHelper(ULONG *pBufferLengthOffset,
7122 ULONG *pStringLengthOffset,
7123 ULONG *pBufferOffset)
7137 EE_THREAD_NOT_REQUIRED;
7143 PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7144 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7145 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
7149 // The String class no longer has a bufferLength field in it.
7150 // We are returning the offset of the stringLength because that is the closest we can get
7151 // This is most certainly a breaking change and a new method
7152 // ICorProfilerInfo3::GetStringLayout2 has been added on the interface ICorProfilerInfo3
7153 if (pBufferLengthOffset != NULL)
7155 *pBufferLengthOffset = StringObject::GetStringLengthOffset();
7158 if (pStringLengthOffset != NULL)
7160 *pStringLengthOffset = StringObject::GetStringLengthOffset();
7163 if (pBufferOffset != NULL)
7165 *pBufferOffset = StringObject::GetBufferOffset();
7174 * This function describes to a profiler the internal layout of a class.
7177 * classID - The class that is being queried. It is really a TypeHandle.
7178 * rFieldOffset - An array to store information about each field in the class.
7179 * cFieldOffset - Count of the number of elements in rFieldOffset.
7180 * pcFieldOffset - Upon return contains the number of elements filled in, or if
7181 * cFieldOffset is zero, the number of elements needed.
7182 * pulClassSize - Optional parameter for containing the size in bytes of the underlying
7183 * internal class structure.
7186 * S_OK if successful.
7188 HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID,
7189 COR_FIELD_OFFSET rFieldOffset[],
7191 ULONG *pcFieldOffset,
7192 ULONG *pulClassSize)
7206 EE_THREAD_NOT_REQUIRED;
7212 PRECONDITION(CheckPointer(rFieldOffset, NULL_OK));
7213 PRECONDITION(CheckPointer(pcFieldOffset));
7214 PRECONDITION(CheckPointer(pulClassSize, NULL_OK));
7218 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7221 "**PROF: GetClassLayout 0x%p.\n",
7225 // Verify parameters
7227 if ((pcFieldOffset == NULL) || (classID == NULL))
7229 return E_INVALIDARG;
7232 if ((cFieldOffset != 0) && (rFieldOffset == NULL))
7234 return E_INVALIDARG;
7237 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classID);
7240 // This is the incorrect API for arrays or strings. Use GetArrayObjectInfo, and GetStringLayout
7242 if (typeHandle.IsTypeDesc() || typeHandle.AsMethodTable()->IsArray())
7244 return E_INVALIDARG;
7248 // We used to have a bug where this API incorrectly succeeded for strings during startup. Profilers
7249 // took dependency on this bug. Let the API to succeed for strings during startup for backward compatibility.
7251 if (typeHandle.AsMethodTable()->IsString() && g_profControlBlock.fBaseSystemClassesLoaded)
7253 return E_INVALIDARG;
7257 // If this class is not fully restored, that is all the information we can get at this time.
7259 if (!typeHandle.IsRestored())
7261 return CORPROF_E_DATAINCOMPLETE;
7264 // Types can be pre-restored, but they still aren't expected to handle queries before
7265 // eager fixups have run. This is a targetted band-aid for a bug intellitrace was
7266 // running into - attempting to get the class layout for all types at module load time.
7267 // If we don't detect this the runtime will AV during the field iteration below. Feel
7268 // free to eliminate this check when a more complete solution is available.
7269 if (MethodTable::IsParentMethodTableTagged(typeHandle.AsMethodTable()))
7271 return CORPROF_E_DATAINCOMPLETE;
7274 // !IsValueType = IsArray || IsReferenceType Since IsArry has been ruled out above, it must
7275 // be a reference type if !IsValueType.
7276 BOOL fReferenceType = !typeHandle.IsValueType();
7279 // Fill in class size now
7281 // Move after the check for typeHandle.GetMethodTable()->IsRestored()
7282 // because an unrestored MethodTable may have a bad EE class pointer
7283 // which will be used by MethodTable::GetNumInstanceFieldBytes
7285 if (pulClassSize != NULL)
7289 // aligned size including the object header for reference types
7290 *pulClassSize = typeHandle.GetMethodTable()->GetBaseSize();
7294 // unboxed and unaligned size for value types
7295 *pulClassSize = typeHandle.GetMethodTable()->GetNumInstanceFieldBytes();
7299 ApproxFieldDescIterator fieldDescIterator(typeHandle.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
7301 ULONG cFields = fieldDescIterator.Count();
7304 // If they are looking to just get the count, return that.
7306 if ((cFieldOffset == 0) || (rFieldOffset == NULL))
7308 *pcFieldOffset = cFields;
7313 // Dont put too many in the array.
7315 if (cFields > cFieldOffset)
7317 cFields = cFieldOffset;
7320 *pcFieldOffset = cFields;
7323 // Now fill in the array
7328 for (i = 0; i < cFields; i++)
7330 pField = fieldDescIterator.Next();
7331 rFieldOffset[i].ridOfField = (ULONG)pField->GetMemberDef();
7332 rFieldOffset[i].ulOffset = (ULONG)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
7339 typedef struct _PROFILER_STACK_WALK_DATA
7341 StackSnapshotCallback *callback;
7343 ULONG32 contextFlags;
7346 #ifdef WIN64EXCEPTIONS
7347 StackFrame sfParent;
7349 } PROFILER_STACK_WALK_DATA;
7353 * ProfilerStackWalkCallback
7355 * This routine is used as the callback from the general stack walker for
7356 * doing snapshot stack walks
7359 StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_DATA *pData)
7363 NOTHROW; // throw is RIGHT out... the throw at minimum allocates the thrown object which we *must* not do
7364 GC_NOTRIGGER; // the stack is not necessarily crawlable at this state !!!) we must not induce a GC
7368 MethodDesc *pFunc = pCf->GetFunction();
7370 COR_PRF_FRAME_INFO_INTERNAL frameInfo;
7371 ULONG32 contextSize = 0;
7372 BYTE *context = NULL;
7374 UINT_PTR currentIP = 0;
7375 REGDISPLAY *pRegDisplay = pCf->GetRegisterSet();
7376 #if defined(_TARGET_X86_)
7377 CONTEXT builtContext;
7381 // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want
7382 // to return to the profiler as the context seed if it wants to walk the unmanaged
7383 // stack frame, so we report the functionId as NULL to indicate this.
7385 if (pCf->IsNativeMarker())
7391 // Skip all Lightweight reflection/emit functions
7393 if ((pFunc != NULL) && pFunc->IsNoMetadata())
7395 return SWA_CONTINUE;
7399 // If this is not a transition of any sort and not a managed
7400 // method, ignore it.
7402 if (!pCf->IsNativeMarker() && !pCf->IsFrameless())
7404 return SWA_CONTINUE;
7407 currentIP = (UINT_PTR)pRegDisplay->ControlPC;
7409 frameInfo.size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
7410 frameInfo.version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
7414 frameInfo.funcID = MethodDescToFunctionID(pFunc);
7415 frameInfo.extraArg = NULL;
7419 frameInfo.funcID = NULL;
7420 frameInfo.extraArg = NULL;
7423 frameInfo.IP = currentIP;
7424 frameInfo.thisArg = NULL;
7426 if (pData->infoFlags & COR_PRF_SNAPSHOT_REGISTER_CONTEXT)
7428 #if defined(_TARGET_X86_)
7430 // X86 stack walking does not keep the context up-to-date during the
7431 // walk. Instead it keeps the REGDISPLAY up-to-date. Thus, we need to
7432 // build a CONTEXT from the REGDISPLAY.
7435 memset(&builtContext, 0, sizeof(builtContext));
7436 builtContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
7437 CopyRegDisplay(pRegDisplay, NULL, &builtContext);
7438 context = (BYTE *)(&builtContext);
7440 context = (BYTE *)pRegDisplay->pCurrentContext;
7442 contextSize = sizeof(CONTEXT);
7445 // NOTE: We are intentionally not setting any callback state flags here (i.e., not using
7446 // SetCallbackStateFlagsHolder), as we want the DSS callback to "inherit" the
7447 // same callback state that DSS has: if DSS was called asynchronously, then consider
7448 // the DSS callback to be called asynchronously.
7449 if (pData->callback(frameInfo.funcID,
7451 (COR_PRF_FRAME_INFO)&frameInfo,
7454 pData->clientData) == S_OK)
7456 return SWA_CONTINUE;
7464 //---------------------------------------------------------------------------------------
7465 // Normally, calling GetFunction() on the frame is sufficient to ensure
7466 // HelperMethodFrames are intialized. However, sometimes we need to be able to specify
7467 // that we should not enter the host while initializing, so we need to initialize such
7468 // frames more directly. This small helper function directly forces the initialization,
7469 // and ensures we don't enter the host as a result if we're executing in an asynchronous
7470 // call (i.e., hijacked thread)
7473 // pFrame - Frame to initialize.
7476 // TRUE iff pFrame was successfully initialized (or was already initialized). If
7477 // pFrame is not a HelperMethodFrame (or derived type), this returns TRUE
7478 // immediately. FALSE indicates we tried to initialize w/out entering the host, and
7479 // had to abort as a result when a reader lock was needed but unavailable.
7482 static BOOL EnsureFrameInitialized(Frame * pFrame)
7489 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7490 // host (SQL). Corners will be cut to ensure this is the case
7491 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7497 if (pFrame->GetFrameType() != Frame::TYPE_HELPER_METHOD_FRAME)
7499 // This frame is not a HelperMethodFrame or a frame derived from
7500 // HelperMethodFrame, so HMF-specific lazy initialization is not an issue.
7504 HelperMethodFrame * pHMF = (HelperMethodFrame *) pFrame;
7506 if (pHMF->InsureInit(
7507 false, // initialInit
7508 NULL, // unwindState
7509 (ShouldAvoidHostCalls() ?
7514 // InsureInit() succeeded and found the return address
7518 // No return address was found. It must be because we asked InsureInit() to bail if
7519 // it would have entered the host
7520 _ASSERTE(ShouldAvoidHostCalls());
7524 //---------------------------------------------------------------------------------------
7526 // Implements the COR_PRF_SNAPSHOT_X86_OPTIMIZED algorithm called by DoStackSnapshot.
7527 // Does a simple EBP walk, rather than invoking all of StackWalkFramesEx.
7530 // pThreadToSnapshot - Thread whose stack should be walked
7531 // pctxSeed - Register context with which to seed the walk
7532 // callback - Function to call at each frame found during the walk
7533 // clientData - Parameter to pass through to callback
7536 // HRESULT indicating success or failure.
7539 HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
7540 Thread * pThreadToSnapshot,
7542 StackSnapshotCallback * callback,
7550 EE_THREAD_NOT_REQUIRED;
7552 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7553 // host (SQL). Corners will be cut to ensure this is the case
7554 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7560 // We haven't set the stackwalker thread type flag yet (see next line), so it shouldn't be set. Only
7561 // exception to this is if the current call is made by a hijacking profiler which
7562 // redirected this thread while it was previously in the middle of another stack walk
7563 _ASSERTE(IsCalledAsynchronously() || !IsStackWalkerThread());
7565 // Remember that we're walking the stack. This holder will reinstate the original
7566 // value of the stackwalker flag (from the thread type mask) in its destructor.
7567 ClrFlsValueSwitch _threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThreadToSnapshot);
7569 // This flag remembers if we reported a managed frame since the last unmanaged block
7570 // we reported. It's used to avoid reporting two unmanaged blocks in a row.
7571 BOOL fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7573 Frame * pFrameCur = pThreadToSnapshot->GetFrame();
7576 ZeroMemory(&ctxCur, sizeof(ctxCur));
7578 // Use seed if we got one. Otherwise, EE explicit Frame chain will seed the walk.
7579 if (pctxSeed != NULL)
7581 ctxCur.Ebp = pctxSeed->Ebp;
7582 ctxCur.Eip = pctxSeed->Eip;
7583 ctxCur.Esp = pctxSeed->Esp;
7588 // At each iteration of the loop:
7589 // * Analyze current frame (get managed data if it's a managed frame)
7590 // * Report current frame via callback()
7591 // * Walk down to next frame
7593 // **** Managed or unmanaged frame? ****
7595 EECodeInfo codeInfo;
7596 MethodDesc * pMethodDescCur = NULL;
7598 if (ctxCur.Eip != 0)
7600 hr = GetFunctionInfoInternal(
7601 (LPCBYTE) ctxCur.Eip,
7603 if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
7605 _ASSERTE(ShouldAvoidHostCalls());
7610 pMethodDescCur = codeInfo.GetMethodDesc();
7614 // **** Report frame to profiler ****
7617 // Make sure the frame gave us an IP
7618 (ctxCur.Eip != 0) &&
7620 // Make sure any managed frame isn't for an IL stub or LCG
7621 ((pMethodDescCur == NULL) || !pMethodDescCur->IsNoMetadata()) &&
7623 // Only report unmanaged frames if the last frame we reported was managed
7624 // (avoid reporting two unmanaged blocks in a row)
7625 ((pMethodDescCur != NULL) || fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock))
7627 // Around the call to the profiler, temporarily clear the
7628 // ThreadType_StackWalker type flag, as we have no control over what the
7629 // profiler may do inside its callback (it could theoretically attempt to
7630 // load other types, though I don't personally know of profilers that
7631 // currently do this).
7633 CLEAR_THREAD_TYPE_STACKWALKER();
7635 (FunctionID) pMethodDescCur,
7637 NULL, // COR_PRF_FRAME_INFO
7638 sizeof(ctxCur), // contextSize,
7639 (LPBYTE) &ctxCur, // context,
7641 SET_THREAD_TYPE_STACKWALKER(pThreadToSnapshot);
7647 if (pMethodDescCur == NULL)
7649 // Just reported an unmanaged block, so reset the flag
7650 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7654 // Just reported a managed block, so remember it
7655 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = TRUE;
7659 // **** Walk down to next frame ****
7661 // Is current frame managed or unmanaged?
7662 if (pMethodDescCur == NULL)
7664 // Unmanaged frame. Use explicit EE Frame chain to help
7667 ZeroMemory(&frameRD, sizeof(frameRD));
7669 while (pFrameCur != FRAME_TOP)
7671 // Frame is only useful if it will contain register context info
7672 if (!pFrameCur->NeedsUpdateRegDisplay())
7678 // This should be the first call we make to the Frame, as it will
7679 // ensure we force lazy initialize of HelperMethodFrames
7680 if (!EnsureFrameInitialized(pFrameCur))
7682 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7685 // This frame is only useful if it gives us an actual return address,
7686 // and is situated on the stack at or below our current ESP (stack
7688 if ((pFrameCur->GetReturnAddress() != NULL) &&
7689 (dac_cast<TADDR>(pFrameCur) >= dac_cast<TADDR>(ctxCur.Esp)))
7691 pFrameCur->UpdateRegDisplay(&frameRD);
7696 pFrameCur = pFrameCur->PtrNextFrame();
7699 if (pFrameCur == FRAME_TOP)
7701 // No more frames. Stackwalk is over
7705 // Update ctxCur based on frame
7706 ctxCur.Eip = pFrameCur->GetReturnAddress();
7707 ctxCur.Ebp = GetRegdisplayFP(&frameRD);
7708 ctxCur.Esp = GetRegdisplaySP(&frameRD);
7714 // GC info will assist us in determining whether this is a non-EBP frame and
7715 // info about pushed arguments.
7716 GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
7717 PTR_VOID gcInfo = gcInfoToken.Info;
7719 unsigned uiMethodSizeDummy;
7720 PTR_CBYTE table = PTR_CBYTE(gcInfo);
7721 table += decodeUnsigned(table, &uiMethodSizeDummy);
7722 table = decodeHeader(table, gcInfoToken.Version, &header);
7724 // Ok, GCInfo, can we do a simple EBP walk or what?
7726 if ((codeInfo.GetRelOffset() < header.prologSize) ||
7727 (!header.ebpFrame && !header.doubleAlign))
7729 // We're either in the prolog or we're not in an EBP frame, in which case
7730 // we'll just defer to the code manager to unwind for us. This condition
7731 // is relatively rare, but can occur if:
7733 // * The profiler did a DSS from its Enter hook, in which case we're
7734 // still inside the prolog, OR
7735 // * The seed context or explicit EE Frame chain seeded us with a
7736 // non-EBP frame function. In this case, using a naive EBP
7737 // unwinding algorithm would actually skip over the next EBP
7738 // frame, and would get SP all wrong as we try skipping over
7739 // the pushed parameters. So let's just ask the code manager for
7742 // Note that there are yet more conditions (much more rare) where the EBP
7743 // walk could get lost (e.g., we're inside an epilog). But we only care
7744 // about the most likely cases, and it's ok if the unlikely cases result
7745 // in truncated stacks, as unlikely cases will be statistically
7746 // irrelevant to CPU performance sampling profilers
7747 CodeManState codeManState;
7748 codeManState.dwIsSet = 0;
7750 FillRegDisplay(&rd, &ctxCur);
7752 rd.SetEbpLocation(&ctxCur.Ebp);
7754 rd.ControlPC = ctxCur.Eip;
7756 codeInfo.GetCodeManager()->UnwindStackFrame(
7759 SpeculativeStackwalk,
7763 ctxCur.Ebp = *rd.GetEbpLocation();
7765 ctxCur.Eip = rd.ControlPC;
7769 // We're in an actual EBP frame, so we can simplistically walk down to
7770 // the next frame using EBP.
7772 // Return address is stored just below saved EBP (stack grows up)
7773 ctxCur.Eip = *(DWORD *) (ctxCur.Ebp + sizeof(DWORD));
7776 // Stack location where current function pushed its EBP
7779 // Skip past that EBP
7782 // Skip past return address pushed by caller
7785 // Skip past arguments to current function that were pushed by caller.
7786 // (Caller will pop varargs, so don't count those.)
7787 (header.varargs ? 0 : (header.argCount * sizeof(DWORD)));
7789 // EBP for frame below us (stack grows up) has been saved onto our own
7790 // frame. Dereference it now.
7791 ctxCur.Ebp = *(DWORD *) ctxCur.Ebp;
7796 #endif // _TARGET_X86_
7798 //*****************************************************************************
7799 // The profiler stackwalk Wrapper
7800 //*****************************************************************************
7801 HRESULT ProfToEEInterfaceImpl::ProfilerStackWalkFramesWrapper(Thread * pThreadToSnapshot, PROFILER_STACK_WALK_DATA * pData, unsigned flags)
7803 STATIC_CONTRACT_WRAPPER;
7805 StackWalkAction swaRet = pThreadToSnapshot->StackWalkFrames(
7806 (PSTACKWALKFRAMESCALLBACK)ProfilerStackWalkCallback,
7814 _ASSERTE(!"Unexpected StackWalkAction returned from Thread::StackWalkFrames");
7821 return CORPROF_E_STACKSNAPSHOT_ABORTED;
7828 //---------------------------------------------------------------------------------------
7830 // DoStackSnapshot helper to call FindJitMan to determine if the specified
7831 // context is in managed code.
7834 // pCtx - Context to look at
7835 // hostCallPreference - Describes how to acquire the reader lock--either AllowHostCalls
7836 // or NoHostCalls (see code:HostCallPreference).
7839 // S_OK: The context is in managed code
7840 // S_FALSE: The context is not in managed code.
7841 // Error: Unable to determine (typically because hostCallPreference was NoHostCalls
7842 // and the reader lock was unattainable without yielding)
7845 HRESULT IsContextInManagedCode(const CONTEXT * pCtx, HostCallPreference hostCallPreference)
7847 WRAPPER_NO_CONTRACT;
7848 BOOL fFailedReaderLock = FALSE;
7850 // if there's no Jit Manager for the IP, it's not managed code.
7851 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(pCtx), hostCallPreference, &fFailedReaderLock);
7852 if (fFailedReaderLock)
7854 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7857 return fIsManagedCode ? S_OK : S_FALSE;
7860 //*****************************************************************************
7861 // Perform a stack walk, calling back to callback at each managed frame.
7862 //*****************************************************************************
7863 HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread,
7864 StackSnapshotCallback *callback,
7868 ULONG32 contextSize)
7872 // Yay! (Note: NOTHROW is vital. The throw at minimum allocates
7873 // the thrown object which we *must* not do.)
7876 // Yay! (Note: this is called asynchronously to view the stack at arbitrary times,
7877 // so the stack is not necessarily crawlable for GC at this state!)
7884 EE_THREAD_NOT_REQUIRED;
7886 // #DisableLockOnAsyncCalls
7887 // This call is allowed asynchronously, however it does take locks. Therefore,
7888 // we will hit contract asserts if we happen to be in a CANNOT_TAKE_LOCK zone when
7889 // a hijacking profiler hijacks this thread to run DoStackSnapshot. CANNOT_RETAKE_LOCK
7890 // is a more granular locking contract that says "I promise that if I take locks, I
7891 // won't reenter any locks that were taken before this function was called".
7892 DISABLED(CAN_TAKE_LOCK);
7894 // Asynchronous functions can be called at arbitrary times when runtime
7895 // is holding locks that cannot be reentered without causing deadlock.
7896 // This contract detects any attempts to reenter locks held at the time
7897 // this function was called.
7903 // This CONTRACT_VIOLATION is still needed because DISABLED(CAN_TAKE_LOCK) does not
7904 // turn off contract violations.
7905 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
7907 LPCONTEXT pctxSeed = reinterpret_cast<LPCONTEXT> (pbContext);
7909 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7912 "**PROF: DoStackSnapshot 0x%p, 0x%p, 0x%08x, 0x%p, 0x%p, 0x%08x.\n",
7920 HRESULT hr = E_UNEXPECTED;
7921 // (hr assignment is to appease the compiler; we won't actually return without explicitly setting hr again)
7923 Thread *pThreadToSnapshot = NULL;
7924 Thread * pCurrentThread = GetThreadNULLOk();
7925 BOOL fResumeThread = FALSE;
7926 INDEBUG(ULONG ulForbidTypeLoad = 0;)
7927 BOOL fResetSnapshotThreadExternalCount = FALSE;
7928 int cRefsSnapshotThread = 0;
7930 // Remember whether we've already determined the current context of the target thread
7931 // is in managed (S_OK), not in managed (S_FALSE), or unknown (error).
7932 HRESULT hrCurrentContextIsManaged = E_FAIL;
7935 memset(&ctxCurrent, 0, sizeof(ctxCurrent));
7939 PROFILER_STACK_WALK_DATA data;
7943 // no managed code has run and things are likely in a very bad have loaded state
7944 // this is a bad time to try to walk the stack
7946 // Returning directly as there is nothing to cleanup yet
7947 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7950 if (!CORProfilerStackSnapshotEnabled())
7952 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7953 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
7958 pThreadToSnapshot = pCurrentThread;
7962 pThreadToSnapshot = (Thread *)thread;
7966 if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT | COR_PRF_SNAPSHOT_X86_OPTIMIZED)) != 0)
7968 if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT)) != 0)
7971 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7972 return E_INVALIDARG;
7975 if (!IsManagedThread(pThreadToSnapshot) || !IsGarbageCollectorFullyInitialized())
7978 // No managed frames, return now.
7980 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7984 // We must make sure no other thread tries to hijack the thread we're about to walk
7985 // Hijacking means Thread::HijackThread, i.e. bashing return addresses which would break the stack walk
7986 Thread::HijackLockHolder hijackLockHolder(pThreadToSnapshot);
7987 if (!hijackLockHolder.Acquired())
7989 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7990 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7993 if (pThreadToSnapshot != pCurrentThread // Walking separate thread
7994 && pCurrentThread != NULL // Walker (current) thread is a managed / VM thread
7995 && ThreadSuspend::SysIsSuspendInProgress()) // EE is trying suspend itself
7997 // Since we're walking a separate thread, we'd have to suspend it first (see below).
7998 // And since the current thread is a VM thread, that means the current thread's
7999 // m_dwForbidSuspendThread count will go up while it's trying to suspend the
8000 // target thread (see Thread::SuspendThread). THAT means no one will be able
8001 // to suspend the current thread until its m_dwForbidSuspendThread is decremented
8002 // (which happens as soon as the target thread of DoStackSnapshot has been suspended).
8003 // Since we're in the process of suspending the entire runtime, now would be a bad time to
8004 // make the walker thread un-suspendable (see VsWhidbey bug 454936). So let's just abort
8005 // now. Note that there is no synchronization around calling Thread::SysIsSuspendInProgress().
8006 // So we will get occasional false positives or false negatives. But that's benign, as the worst
8007 // that might happen is we might occasionally delay the EE suspension a little bit, or we might
8008 // too eagerly fail from ProfToEEInterfaceImpl::DoStackSnapshot sometimes. But there won't
8009 // be any corruption or AV.
8011 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
8012 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
8015 // We only allow stackwalking if:
8016 // 1) Target thread to walk == current thread OR Target thread is suspended, AND
8017 // 2) Target thread to walk is currently executing JITted / NGENd code, AND
8018 // 3) Target thread to walk is seeded OR currently NOT unwinding the stack, AND
8019 // 4) Target thread to walk != current thread OR current thread is NOT in a can't stop or forbid suspend region
8021 // If the thread is in a forbid suspend region, it's dangerous to do anything:
8022 // - The code manager datastructures accessed during the stackwalk may be in inconsistent state.
8023 // - Thread::Suspend won't be able to suspend the thread.
8024 if (pThreadToSnapshot->IsInForbidSuspendRegion())
8026 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8030 HostCallPreference hostCallPreference;
8032 // First, check "1) Target thread to walk == current thread OR Target thread is suspended"
8033 if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
8035 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8039 // Walking separate thread, so it must be suspended. First, ensure that
8040 // target thread exists.
8042 // NOTE: We're using the "dangerous" variant of this refcount function, because we
8043 // rely on the profiler to ensure it never tries to walk a thread being destroyed.
8044 // (Profiler must block in its ThreadDestroyed() callback until all uses of that thread,
8045 // such as walking its stack, are complete.)
8046 cRefsSnapshotThread = pThreadToSnapshot->IncExternalCountDANGEROUSProfilerOnly();
8047 fResetSnapshotThreadExternalCount = TRUE;
8049 if (cRefsSnapshotThread == 1 || !pThreadToSnapshot->HasValidThreadHandle())
8051 // At this point, we've modified the VM state based on bad input
8052 // (pThreadToSnapshot) from the profiler. This could cause
8053 // memory corruption and leave us vulnerable to security problems.
8054 // So destroy the process.
8055 _ASSERTE(!"Profiler trying to walk destroyed thread");
8056 EEPOLICY_HANDLE_FATAL_ERROR(CORPROF_E_STACKSNAPSHOT_INVALID_TGT_THREAD);
8059 // Thread::SuspendThread() ensures that no one else should try to suspend us
8060 // while we're suspending pThreadToSnapshot.
8062 // TRUE: OneTryOnly. Don't loop waiting for others to get out of our way in
8063 // order to suspend the thread. If it's not safe, just return an error immediately.
8064 Thread::SuspendThreadResult str = pThreadToSnapshot->SuspendThread(TRUE);
8065 if (str == Thread::STR_Success)
8067 fResumeThread = TRUE;
8071 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8074 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8077 hostCallPreference =
8078 ShouldAvoidHostCalls() ?
8079 NoHostCalls : // Async call: Ensure this thread won't yield & re-enter host
8080 AllowHostCalls; // Synchronous calls may re-enter host just fine
8082 // If target thread is in pre-emptive mode, the profiler's seed context is unnecessary
8083 // because our frame chain is good enough: it will give us at least as accurate a
8084 // starting point as the profiler could. Also, since profiler contexts cannot be
8085 // trusted, we don't want to set the thread's profiler filter context to this, as a GC
8086 // that interrupts the profiler's stackwalk will end up using the profiler's (potentially
8087 // bogus) filter context.
8088 if (!pThreadToSnapshot->PreemptiveGCDisabledOther())
8090 // Thread to be walked is in preemptive mode. Throw out seed.
8093 else if (pThreadToSnapshot != pCurrentThread)
8095 // With cross-thread stack-walks, the target thread's context could be unreliable.
8096 // That would shed doubt on either a profiler-provided context, or a default
8097 // context we chose. So check if we're in a potentially unreliable case, and return
8100 // These heurisitics are based on an actual bug where GetThreadContext returned a
8101 // self-consistent, but stale, context for a thread suspended after being redirected by
8102 // the GC (TFS Dev 10 bug # 733263).
8104 // (Note that this whole block is skipped if pThreadToSnapshot is in preemptive mode (the IF
8105 // above), as the context is unused in such a case--the EE Frame chain is used
8106 // to seed the walk instead.)
8107 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8111 if (!pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8113 LOG((LF_CORPROF, LL_INFO100, "**PROF: GetSafelyRedirectableThreadContext failure leads to CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8114 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8118 hrCurrentContextIsManaged = IsContextInManagedCode(&ctxCurrent, hostCallPreference);
8119 if (FAILED(hrCurrentContextIsManaged))
8121 // Couldn't get the info. Try again later
8122 _ASSERTE(ShouldAvoidHostCalls());
8123 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8127 if ((hrCurrentContextIsManaged == S_OK) &&
8128 (!pThreadToSnapshot->PreemptiveGCDisabledOther()))
8130 // Thread is in preemptive mode while executing managed code?! This lie is
8131 // an early warning sign that the context is bogus. Bail.
8132 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus. Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8133 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8137 Frame * pFrame = pThreadToSnapshot->GetFrame();
8138 if (pFrame != FRAME_TOP)
8140 TADDR spTargetThread = GetSP(&ctxCurrent);
8141 if (dac_cast<TADDR>(pFrame) < spTargetThread)
8143 // An Explicit EE Frame is more recent on the stack than the current
8144 // stack pointer itself? This lie is an early warning sign that the
8145 // context is bogus. Bail.
8146 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus. Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8147 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8152 // If the profiler did not specify a seed context of its own, use the current one we
8155 // Failing to seed the walk can cause us to to "miss" functions on the stack. This is
8156 // because StackWalkFrames(), when doing an unseeded stackwalk, sets the
8157 // starting regdisplay's IP/SP to 0. This, in turn causes StackWalkFramesEx
8158 // to set cf.isFrameless = (pEEJM != NULL); (which is FALSE, since we have no
8159 // jit manager, since we have no IP). Once frameless is false, we look solely to
8160 // the Frame chain for our goodies, rather than looking at the code actually
8161 // being executed by the thread. The problem with the frame chain is that some
8162 // frames (e.g., GCFrame) don't point to any functions being executed. So
8163 // StackWalkFramesEx just skips such frames and moves to the next one. That
8164 // can cause a chunk of calls to be skipped. To prevent this from happening, we
8165 // "fake" a seed by just seeding the thread with its current context. This forces
8166 // StackWalkFramesEx() to look at the IP rather than just the frame chain.
8167 if (pctxSeed == NULL)
8169 pctxSeed = &ctxCurrent;
8171 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8174 // Second, check "2) Target thread to walk is currently executing JITted / NGENd code"
8175 // To do this, we need to find the proper context to investigate. Start with
8176 // the seeded context, if available. If not, use the target thread's current context.
8177 if (pctxSeed != NULL)
8179 BOOL fSeedIsManaged;
8181 // Short cut: If we're just using the current context as the seed, we may
8182 // already have determined whether it's in managed code. If so, just use that
8183 // result rather than calculating it again
8184 if ((pctxSeed == &ctxCurrent) && SUCCEEDED(hrCurrentContextIsManaged))
8186 fSeedIsManaged = (hrCurrentContextIsManaged == S_OK);
8190 hr = IsContextInManagedCode(pctxSeed, hostCallPreference);
8193 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8196 fSeedIsManaged = (hr == S_OK);
8199 if (!fSeedIsManaged)
8201 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8208 // Sanity check: If we are doing a cross-thread walk and there is no seed context, then
8209 // we better not be in managed code, otw we do not have a Frame on the stack from which to start
8210 // walking and we may miss the leaf-most chain of managed calls due to the way StackWalkFrames
8211 // is implemented. However, there is an exception when the leaf-most EE frame of pThreadToSnapshot
8212 // is an InlinedCallFrame, which has an active call, implying pThreadToShanpshot is inside an
8213 // inlined P/Invoke. In this case, the InlinedCallFrame will be used to help start off our
8214 // stackwalk at the top of the stack.
8216 if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
8218 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8222 if (pctxSeed == NULL)
8224 if (pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8226 BOOL fFailedReaderLock = FALSE;
8227 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(&ctxCurrent), hostCallPreference, &fFailedReaderLock);
8229 if (!fFailedReaderLock)
8231 // not in jitted or ngend code or inside an inlined P/Invoke (the leaf-most EE Frame is
8232 // an InlinedCallFrame with an active call)
8233 _ASSERTE(!fIsManagedCode ||
8234 (InlinedCallFrame::FrameHasActiveCall(pThreadToSnapshot->GetFrame())));
8238 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8241 // Third, verify the target thread is seeded or not in the midst of an unwind.
8242 if (pctxSeed == NULL)
8244 ThreadExceptionState* pExState = pThreadToSnapshot->GetExceptionState();
8246 // this tests to see if there is an exception in flight
8247 if (pExState->IsExceptionInProgress() && pExState->GetFlags()->UnwindHasStarted())
8249 EHClauseInfo *pCurrentEHClauseInfo = pThreadToSnapshot->GetExceptionState()->GetCurrentEHClauseInfo();
8251 // if the exception code is telling us that we have entered a managed context then all is well
8252 if (!pCurrentEHClauseInfo->IsManagedCodeEntered())
8254 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8260 // Check if the exception state is consistent. See the comment for ThreadExceptionFlag for more information.
8261 if (pThreadToSnapshot->GetExceptionState()->HasThreadExceptionFlag(ThreadExceptionState::TEF_InconsistentExceptionState))
8263 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8267 data.callback = callback;
8268 data.infoFlags = infoFlags;
8269 data.contextFlags = 0;
8270 data.clientData = clientData;
8271 #ifdef WIN64EXCEPTIONS
8272 data.sfParent.Clear();
8275 // workaround: The ForbidTypeLoad book keeping in the stackwalker is not robust against exceptions.
8276 // Unfortunately, it is hard to get it right in the stackwalker since it has to be exception
8277 // handling free (frame unwinding may never return). We restore the ForbidTypeLoad counter here
8278 // in case it got messed up by exception thrown during the stackwalk.
8279 INDEBUG(if (pCurrentThread) ulForbidTypeLoad = pCurrentThread->m_ulForbidTypeLoad;)
8282 // An AV during a profiler stackwalk is an isolated event and shouldn't bring
8283 // down the runtime. Need to place the holder here, outside of ProfilerStackWalkFramesWrapper
8284 // since ProfilerStackWalkFramesWrapper uses __try, which doesn't like objects
8285 // with destructors.
8286 AVInRuntimeImplOkayHolder AVOkay;
8288 hr = DoStackSnapshotHelper(
8291 HANDLESKIPPEDFRAMES |
8293 NOTIFY_ON_U2M_TRANSITIONS |
8294 ((pThreadToSnapshot == pCurrentThread) ?
8296 ALLOW_ASYNC_STACK_WALK | THREAD_IS_SUSPENDED) |
8297 THREAD_EXECUTING_MANAGED_CODE |
8298 PROFILER_DO_STACK_SNAPSHOT |
8299 ALLOW_INVALID_OBJECTS, // stack walk logic should not look at objects - we could be in the middle of a gc.
8303 INDEBUG(if (pCurrentThread) pCurrentThread->m_ulForbidTypeLoad = ulForbidTypeLoad;)
8306 #if defined(PLATFORM_SUPPORTS_SAFE_THREADSUSPEND)
8309 pThreadToSnapshot->ResumeThread();
8311 #endif // PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8312 if (fResetSnapshotThreadExternalCount)
8314 pThreadToSnapshot->DecExternalCountDANGEROUSProfilerOnly();
8321 //---------------------------------------------------------------------------------------
8323 // Exception swallowing wrapper around the profiler stackwalk
8326 // pThreadToSnapshot - Thread whose stack should be walked
8327 // pData - data for stack walker
8328 // flags - flags parameter to pass to StackWalkFramesEx, and StackFrameIterator
8329 // pctxSeed - Register context with which to seed the walk
8332 // HRESULT indicating success or failure.
8334 HRESULT ProfToEEInterfaceImpl::DoStackSnapshotHelper(Thread * pThreadToSnapshot,
8335 PROFILER_STACK_WALK_DATA * pData,
8339 STATIC_CONTRACT_NOTHROW;
8341 // We want to catch and swallow AVs here. For example, if the profiler gives
8342 // us a bogus seed context (this happens), we could AV when inspecting memory pointed to
8343 // by the (bogus) EBP register.
8345 // EX_TRY/EX_CATCH does a lot of extras that we do not need and that can go wrong for us.
8346 // E.g. It asserts in debug build for AVs in mscorwks or it synthetizes an object for the exception.
8347 // We use a plain PAL_TRY/PAL_EXCEPT since it is all we need.
8350 Thread * pThreadToSnapshot;
8351 PROFILER_STACK_WALK_DATA * pData;
8353 ProfToEEInterfaceImpl * pProfToEE;
8355 BOOL fResetProfilerFilterContext;
8359 param.hr = E_UNEXPECTED;
8360 param.pThreadToSnapshot = pThreadToSnapshot;
8361 param.pData = pData;
8362 param.flags = flags;
8363 param.pProfToEE = this;
8364 param.pctxSeed = pctxSeed;
8365 param.fResetProfilerFilterContext = FALSE;
8367 PAL_TRY(Param *, pParam, ¶m)
8369 if ((pParam->pData->infoFlags & COR_PRF_SNAPSHOT_X86_OPTIMIZED) != 0)
8371 #ifndef _TARGET_X86_
8372 // If check in the begining of DoStackSnapshot (to return E_INVALIDARG) should
8373 // make this unreachable
8374 _ASSERTE(!"COR_PRF_SNAPSHOT_X86_OPTIMIZED on non-X86 should be unreachable!");
8376 // New, simple EBP walker
8377 pParam->hr = pParam->pProfToEE->ProfilerEbpWalker(
8378 pParam->pThreadToSnapshot,
8380 pParam->pData->callback,
8381 pParam->pData->clientData);
8382 #endif // _TARGET_X86_
8386 // We're now fairly confident the stackwalk should be ok, so set
8387 // the context seed, if one was provided or cooked up.
8388 if (pParam->pctxSeed != NULL)
8390 pParam->pThreadToSnapshot->SetProfilerFilterContext(pParam->pctxSeed);
8391 pParam->fResetProfilerFilterContext = TRUE;
8394 // Whidbey-style walker, uses StackWalkFramesEx
8395 pParam->hr = pParam->pProfToEE->ProfilerStackWalkFramesWrapper(
8396 pParam->pThreadToSnapshot,
8401 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8403 param.hr = E_UNEXPECTED;
8407 // Undo the context seeding & thread suspend we did (if any)
8408 // to ensure that the thread we walked stayed suspended
8409 if (param.fResetProfilerFilterContext)
8411 pThreadToSnapshot->SetProfilerFilterContext(NULL);
8418 HRESULT ProfToEEInterfaceImpl::GetGenerationBounds(ULONG cObjectRanges,
8419 ULONG *pcObjectRanges,
8420 COR_PRF_GC_GENERATION_RANGE ranges[])
8434 EE_THREAD_NOT_REQUIRED;
8440 PRECONDITION(CheckPointer(pcObjectRanges));
8441 PRECONDITION(cObjectRanges <= 0 || ranges != NULL);
8442 PRECONDITION(s_generationTableLock >= 0);
8446 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8449 "**PROF: GetGenerationBounds.\n"));
8451 // Announce we are using the generation table now
8452 CounterHolder genTableLock(&s_generationTableLock);
8454 GenerationTable *generationTable = s_currentGenerationTable;
8456 if (generationTable == NULL)
8461 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8463 GenerationDesc *genDescTable = generationTable->genDescTable;
8464 ULONG count = min(generationTable->count, cObjectRanges);
8465 for (ULONG i = 0; i < count; i++)
8467 ranges[i].generation = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8468 ranges[i].rangeStart = (ObjectID)genDescTable[i].rangeStart;
8469 ranges[i].rangeLength = genDescTable[i].rangeEnd - genDescTable[i].rangeStart;
8470 ranges[i].rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8473 *pcObjectRanges = generationTable->count;
8479 HRESULT ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo(COR_PRF_EX_CLAUSE_INFO * pinfo)
8496 PRECONDITION(CheckPointer(pinfo));
8500 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
8502 "**PROF: GetNotifiedExceptionClauseInfo.\n"));
8506 ThreadExceptionState* pExState = NULL;
8507 EHClauseInfo* pCurrentEHClauseInfo = NULL;
8509 // notification requires that we are on a managed thread with an exception in flight
8510 Thread *pThread = GetThread();
8512 // If pThread is null, then the thread has never run managed code
8513 if (pThread == NULL)
8515 hr = CORPROF_E_NOT_MANAGED_THREAD;
8519 pExState = pThread->GetExceptionState();
8520 if (!pExState->IsExceptionInProgress())
8522 // no exception is in flight -- successful failure
8527 pCurrentEHClauseInfo = pExState->GetCurrentEHClauseInfo();
8528 if (pCurrentEHClauseInfo->GetClauseType() == COR_PRF_CLAUSE_NONE)
8530 // no exception is in flight -- successful failure
8535 pinfo->clauseType = pCurrentEHClauseInfo->GetClauseType();
8536 pinfo->programCounter = pCurrentEHClauseInfo->GetIPForEHClause();
8537 pinfo->framePointer = pCurrentEHClauseInfo->GetFramePointerForEHClause();
8538 pinfo->shadowStackPointer = 0;
8543 memset(pinfo, 0, sizeof(*pinfo));
8548 HRESULT ProfToEEInterfaceImpl::GetObjectGeneration(ObjectID objectId,
8549 COR_PRF_GC_GENERATION_RANGE *range)
8563 EE_THREAD_NOT_REQUIRED;
8569 PRECONDITION(objectId != NULL);
8570 PRECONDITION(CheckPointer(range));
8571 PRECONDITION(s_generationTableLock >= 0);
8575 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8578 "**PROF: GetObjectGeneration 0x%p.\n",
8581 BEGIN_GETTHREAD_ALLOWED;
8582 _ASSERTE((GetThread() == NULL) || (GetThread()->PreemptiveGCDisabled()));
8583 END_GETTHREAD_ALLOWED;
8585 // Announce we are using the generation table now
8586 CounterHolder genTableLock(&s_generationTableLock);
8588 GenerationTable *generationTable = s_currentGenerationTable;
8590 if (generationTable == NULL)
8595 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8597 GenerationDesc *genDescTable = generationTable->genDescTable;
8598 ULONG count = generationTable->count;
8599 for (ULONG i = 0; i < count; i++)
8601 if (genDescTable[i].rangeStart <= (BYTE *)objectId && (BYTE *)objectId < genDescTable[i].rangeEndReserved)
8603 range->generation = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8604 range->rangeStart = (ObjectID)genDescTable[i].rangeStart;
8605 range->rangeLength = genDescTable[i].rangeEnd - genDescTable[i].rangeStart;
8606 range->rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8615 HRESULT ProfToEEInterfaceImpl::GetReJITIDs(
8616 FunctionID functionId, // in
8617 ULONG cReJitIds, // in
8618 ULONG * pcReJitIds, // out
8619 ReJITID reJitIds[]) // out
8626 // taking a lock causes a GC
8632 // The rejit tables use a lock
8636 PRECONDITION(CheckPointer(pcReJitIds, NULL_OK));
8637 PRECONDITION(CheckPointer(reJitIds, NULL_OK));
8642 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8643 kP2EEAllowableAfterAttach,
8646 "**PROF: GetReJITIDs 0x%p.\n",
8649 if (functionId == 0)
8651 return E_INVALIDARG;
8654 if ((cReJitIds == 0) || (pcReJitIds == NULL) || (reJitIds == NULL))
8656 return E_INVALIDARG;
8659 MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
8661 return ReJitManager::GetReJITIDs(pMD, cReJitIds, pcReJitIds, reJitIds);
8665 HRESULT ProfToEEInterfaceImpl::SetupThreadForReJIT()
8667 LIMITED_METHOD_CONTRACT;
8672 if (GetThread() == NULL)
8677 Thread *pThread = GetThread();
8678 pThread->SetProfilerCallbackStateFlags(COR_PRF_CALLBACKSTATE_REJIT_WAS_CALLED);
8680 EX_CATCH_HRESULT(hr);
8685 HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG cFunctions, // in
8686 ModuleID moduleIds[], // in
8687 mdMethodDef methodIds[]) // in
8694 // When we suspend the runtime we drop into premptive mode
8700 // We need to suspend the runtime, this takes a lot of locks!
8704 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8705 PRECONDITION(CheckPointer(methodIds, NULL_OK));
8709 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8710 kP2EETriggers | kP2EEAllowableAfterAttach,
8713 "**PROF: RequestReJIT.\n"));
8715 if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
8717 return CORPROF_E_CALLBACK4_REQUIRED;
8720 if (!CORProfilerEnableRejit())
8722 return CORPROF_E_REJIT_NOT_ENABLED;
8725 // Request at least 1 method to reJIT!
8726 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8728 return E_INVALIDARG;
8731 // Remember the profiler is doing this, as that means we must never detach it!
8732 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8734 HRESULT hr = SetupThreadForReJIT();
8741 return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds, static_cast<COR_PRF_REJIT_FLAGS>(0));
8744 HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG cFunctions, // in
8745 ModuleID moduleIds[], // in
8746 mdMethodDef methodIds[], // in
8747 HRESULT rgHrStatuses[]) // out
8754 // The rejit manager requires a lock to iterate through methods to revert, and
8755 // taking the lock can drop us into preemptive mode.
8761 // The rejit manager requires a lock to iterate through methods to revert
8765 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8766 PRECONDITION(CheckPointer(methodIds, NULL_OK));
8767 PRECONDITION(CheckPointer(rgHrStatuses, NULL_OK));
8771 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8772 kP2EEAllowableAfterAttach | kP2EETriggers,
8775 "**PROF: RequestRevert.\n"));
8777 if (!CORProfilerEnableRejit())
8779 return CORPROF_E_REJIT_NOT_ENABLED;
8782 // Request at least 1 method to revert!
8783 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8785 return E_INVALIDARG;
8788 // Remember the profiler is doing this, as that means we must never detach it!
8789 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8791 // Initialize the status array
8792 if (rgHrStatuses != NULL)
8794 memset(rgHrStatuses, 0, sizeof(HRESULT) * cFunctions);
8795 _ASSERTE(S_OK == rgHrStatuses[0]);
8798 HRESULT hr = SetupThreadForReJIT();
8805 return ReJitManager::RequestRevert(cFunctions, moduleIds, methodIds, rgHrStatuses);
8809 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions(ICorProfilerFunctionEnum ** ppEnum)
8822 // If we're in preemptive mode we need to take a read lock to safely walk
8823 // the JIT data structures.
8827 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8832 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8835 "**PROF: EnumJITedFunctions.\n"));
8839 return E_INVALIDARG;
8844 NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8845 if (pJitEnum == NULL)
8847 return E_OUTOFMEMORY;
8850 if (!pJitEnum->Init())
8852 return E_OUTOFMEMORY;
8855 // Ownership transferred to [out] param. Caller must Release() when done with this.
8856 *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8861 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions2(ICorProfilerFunctionEnum ** ppEnum)
8868 // Gathering rejitids requires taking a lock and that lock might switch to
8869 // preemptimve mode...
8875 // If we're in preemptive mode we need to take a read lock to safely walk
8876 // the JIT data structures.
8877 // Gathering RejitIDs also takes a lock.
8881 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8886 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8887 kP2EEAllowableAfterAttach | kP2EETriggers,
8890 "**PROF: EnumJITedFunctions.\n"));
8894 return E_INVALIDARG;
8899 NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8900 if (pJitEnum == NULL)
8902 return E_OUTOFMEMORY;
8905 if (!pJitEnum->Init(TRUE /* fWithReJITIDs */))
8907 // If it fails, it's because of OOM.
8908 return E_OUTOFMEMORY;
8911 // Ownership transferred to [out] param. Caller must Release() when done with this.
8912 *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8917 HRESULT ProfToEEInterfaceImpl::EnumModules(ICorProfilerModuleEnum ** ppEnum)
8924 // This method populates the enumerator, which requires iterating over
8925 // AppDomains, which adds, then releases, a reference on each AppDomain iterated.
8926 // This causes locking, and can cause triggering if the AppDomain gets destroyed
8927 // as a result of the release. (See code:AppDomainIterator::Next and its call to
8928 // code:AppDomain::Release.)
8934 // (See comment above GC_TRIGGERS.)
8938 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8943 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8944 kP2EEAllowableAfterAttach | kP2EETriggers,
8947 "**PROF: EnumModules.\n"));
8953 return E_INVALIDARG;
8958 // ProfilerModuleEnum uese AppDomainIterator, which cannot be called while the current thead
8959 // is holding the ThreadStore lock.
8960 if (ThreadStore::HoldingThreadStore())
8962 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
8965 NewHolder<ProfilerModuleEnum> pModuleEnum(new (nothrow) ProfilerModuleEnum);
8966 if (pModuleEnum == NULL)
8968 return E_OUTOFMEMORY;
8971 hr = pModuleEnum->Init();
8977 // Ownership transferred to [out] param. Caller must Release() when done with this.
8978 *ppEnum = (ICorProfilerModuleEnum *) pModuleEnum.Extract();
8983 HRESULT ProfToEEInterfaceImpl::GetRuntimeInformation(USHORT * pClrInstanceId,
8984 COR_PRF_RUNTIME_TYPE * pRuntimeType,
8985 USHORT * pMajorVersion,
8986 USHORT * pMinorVersion,
8987 USHORT * pBuildNumber,
8988 USHORT * pQFEVersion,
8989 ULONG cchVersionString,
8990 ULONG * pcchVersionString,
8991 __out_ecount_part_opt(cchVersionString, *pcchVersionString) WCHAR szVersionString[])
9005 EE_THREAD_NOT_REQUIRED;
9013 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
9016 "**PROF: GetRuntimeInformation.\n"));
9018 if ((szVersionString != NULL) && (pcchVersionString == NULL))
9020 return E_INVALIDARG;
9023 if (pcchVersionString != NULL)
9025 HRESULT hr = GetCORVersionInternal(szVersionString, (DWORD)cchVersionString, (DWORD *)pcchVersionString);
9030 if (pClrInstanceId != NULL)
9031 *pClrInstanceId = static_cast<USHORT>(GetClrInstanceId());
9033 if (pRuntimeType != NULL)
9035 *pRuntimeType = COR_PRF_CORE_CLR;
9038 if (pMajorVersion != NULL)
9039 *pMajorVersion = CLR_MAJOR_VERSION;
9041 if (pMinorVersion != NULL)
9042 *pMinorVersion = CLR_MINOR_VERSION;
9044 if (pBuildNumber != NULL)
9045 *pBuildNumber = CLR_BUILD_VERSION;
9047 if (pQFEVersion != NULL)
9048 *pQFEVersion = CLR_BUILD_VERSION_QFE;
9054 HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds)
9061 // Crst is used in ProfilingAPIDetach::RequestProfilerDetach so GC may be triggered
9068 EE_THREAD_NOT_REQUIRED;
9070 // Crst is used in ProfilingAPIDetach::RequestProfilerDetach
9075 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9076 kP2EEAllowableAfterAttach | kP2EETriggers,
9079 "**PROF: RequestProfilerDetach.\n"));
9081 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
9082 return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds);
9083 #else // FEATURE_PROFAPI_ATTACH_DETACH
9085 #endif // FEATURE_PROFAPI_ATTACH_DETACH
9088 typedef struct _COR_PRF_ELT_INFO_INTERNAL
9090 // Point to a platform dependent structure ASM helper push on the stack
9091 void * platformSpecificHandle;
9093 // startAddress of COR_PRF_FUNCTION_ARGUMENT_RANGE structure needs to point
9094 // TO the argument value, not BE the argument value. So, when the argument
9095 // is this, we need to point TO this. Because of the calling sequence change
9096 // in ELT3, we need to reserve the pointer here instead of using one of our
9100 // Reserve space for output parameter COR_PRF_FRAME_INFO of
9101 // GetFunctionXXXX3Info functions
9102 COR_PRF_FRAME_INFO_INTERNAL frameInfo;
9104 } COR_PRF_ELT_INFO_INTERNAL;
9106 //---------------------------------------------------------------------------------------
9108 // ProfilingGetFunctionEnter3Info provides frame information and argument infomation of
9109 // the function ELT callback is inspecting. It is called either by the profiler or the
9110 // C helper function.
9113 // * functionId - [in] FunctionId of the function being inspected by ELT3
9114 // * eltInfo - [in] The opaque pointer FunctionEnter3WithInfo callback passed to the profiler
9115 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9117 // * pcbArgumentInfo - [in, out] Pointer to ULONG that specifies the size of structure
9118 // pointed by pArgumentInfo
9119 // * pArgumentInfo - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_INFO structure the profiler
9120 // must preserve enough space for the function it is inspecting
9123 // HRESULT indicating success or failure.
9126 HRESULT ProfilingGetFunctionEnter3Info(FunctionID functionId, // in
9127 COR_PRF_ELT_INFO eltInfo, // in
9128 COR_PRF_FRAME_INFO * pFrameInfo, // out
9129 ULONG * pcbArgumentInfo, // in, out
9130 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo) // out
9143 // ProfileArgIterator::ProfileArgIterator may take locks
9150 if ((functionId == NULL) || (eltInfo == NULL))
9152 return E_INVALIDARG;
9155 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9156 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9158 // The loader won't trigger a GC or throw for already loaded argument types.
9159 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9162 // Find the method this is referring to, so we can get the signature
9164 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9165 MetaSig metaSig(pMethodDesc);
9167 NewHolder<ProfileArgIterator> pProfileArgIterator;
9170 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9173 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9175 if (pProfileArgIterator == NULL)
9177 return E_UNEXPECTED;
9181 if (CORProfilerFrameInfoEnabled())
9183 if (pFrameInfo == NULL)
9185 return E_INVALIDARG;
9189 // Setup the COR_PRF_FRAME_INFO structure first.
9191 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9193 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9194 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9195 pCorPrfFrameInfo->funcID = functionId;
9196 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9197 pCorPrfFrameInfo->extraArg = pProfileArgIterator->GetHiddenArgValue();
9198 pCorPrfFrameInfo->thisArg = pProfileArgIterator->GetThis();
9200 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9204 // Do argument processing if desired.
9206 if (CORProfilerFunctionArgsEnabled())
9208 if (pcbArgumentInfo == NULL)
9210 return E_INVALIDARG;
9213 if ((*pcbArgumentInfo != 0) && (pArgumentInfo == NULL))
9215 return E_INVALIDARG;
9218 ULONG32 count = pProfileArgIterator->GetNumArgs();
9220 if (metaSig.HasThis())
9225 ULONG ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + (count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE));
9227 if (*pcbArgumentInfo < ulArgInfoSize)
9229 *pcbArgumentInfo = ulArgInfoSize;
9230 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
9233 _ASSERTE(pArgumentInfo != NULL);
9235 pArgumentInfo->numRanges = count;
9236 pArgumentInfo->totalArgumentSize = 0;
9240 if (metaSig.HasThis())
9242 pELTInfo->pThis = pProfileArgIterator->GetThis();
9243 pArgumentInfo->ranges[count].startAddress = (UINT_PTR) (&(pELTInfo->pThis));
9245 UINT length = sizeof(pELTInfo->pThis);
9246 pArgumentInfo->ranges[count].length = length;
9247 pArgumentInfo->totalArgumentSize += length;
9251 while (count < pArgumentInfo->numRanges)
9253 pArgumentInfo->ranges[count].startAddress = (UINT_PTR)(pProfileArgIterator->GetNextArgAddr());
9255 UINT length = pProfileArgIterator->GetArgSize();
9256 pArgumentInfo->ranges[count].length = length;
9257 pArgumentInfo->totalArgumentSize += length;
9267 HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId, // in
9268 COR_PRF_ELT_INFO eltInfo, // in
9269 COR_PRF_FRAME_INFO * pFrameInfo, // out
9270 ULONG * pcbArgumentInfo, // in, out
9271 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo) // out
9284 // ProfilingGetFunctionEnter3Info may take locks
9291 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9293 "**PROF: GetFunctionEnter3Info.\n"));
9295 _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL);
9297 if (!CORProfilerELT3SlowPathEnterEnabled())
9299 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9302 return ProfilingGetFunctionEnter3Info(functionId, eltInfo, pFrameInfo, pcbArgumentInfo, pArgumentInfo);
9305 //---------------------------------------------------------------------------------------
9307 // ProfilingGetFunctionLeave3Info provides frame information and return value infomation
9308 // of the function ELT callback is inspecting. It is called either by the profiler or the
9309 // C helper function.
9312 // * functionId - [in] FunctionId of the function being inspected by ELT3
9313 // * eltInfo - [in] The opaque pointer FunctionLeave3WithInfo callback passed to the profiler
9314 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9316 // * pRetvalRange - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_RANGE to store return value
9319 // HRESULT indicating success or failure.
9322 HRESULT ProfilingGetFunctionLeave3Info(FunctionID functionId, // in
9323 COR_PRF_ELT_INFO eltInfo, // in
9324 COR_PRF_FRAME_INFO * pFrameInfo, // out
9325 COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange) // out
9338 // ProfileArgIterator::ProfileArgIterator may take locks
9344 if ((pFrameInfo == NULL) || (eltInfo == NULL))
9346 return E_INVALIDARG;
9349 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9350 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9352 // The loader won't trigger a GC or throw for already loaded argument types.
9353 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9356 // Find the method this is referring to, so we can get the signature
9358 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9359 MetaSig metaSig(pMethodDesc);
9361 NewHolder<ProfileArgIterator> pProfileArgIterator;
9364 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9367 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9369 if (pProfileArgIterator == NULL)
9371 return E_UNEXPECTED;
9375 if (CORProfilerFrameInfoEnabled())
9377 if (pFrameInfo == NULL)
9379 return E_INVALIDARG;
9382 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9385 // Setup the COR_PRF_FRAME_INFO structure first.
9387 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9388 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9389 pCorPrfFrameInfo->funcID = functionId;
9390 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9392 // Upon entering Leave hook, the register assigned to store this pointer on function calls may
9393 // already be reused and is likely not to contain this pointer.
9394 pCorPrfFrameInfo->extraArg = NULL;
9395 pCorPrfFrameInfo->thisArg = NULL;
9397 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9401 // Do argument processing if desired.
9403 if (CORProfilerFunctionReturnValueEnabled())
9405 if (pRetvalRange == NULL)
9407 return E_INVALIDARG;
9410 if (!metaSig.IsReturnTypeVoid())
9412 pRetvalRange->length = metaSig.GetReturnTypeSize();
9413 pRetvalRange->startAddress = (UINT_PTR)pProfileArgIterator->GetReturnBufferAddr();
9417 pRetvalRange->length = 0;
9418 pRetvalRange->startAddress = 0;
9426 HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId, // in
9427 COR_PRF_ELT_INFO eltInfo, // in
9428 COR_PRF_FRAME_INFO * pFrameInfo, // out
9429 COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange) // out
9442 // ProfilingGetFunctionLeave3Info may take locks
9449 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9451 "**PROF: GetFunctionLeave3Info.\n"));
9453 _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL);
9455 if (!CORProfilerELT3SlowPathLeaveEnabled())
9457 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9460 return ProfilingGetFunctionLeave3Info(functionId, eltInfo, pFrameInfo, pRetvalRange);
9463 //---------------------------------------------------------------------------------------
9465 // ProfilingGetFunctionTailcall3Info provides frame information of the function ELT callback
9466 // is inspecting. It is called either by the profiler or the C helper function.
9469 // * functionId - [in] FunctionId of the function being inspected by ELT3
9470 // * eltInfo - [in] The opaque pointer FunctionTailcall3WithInfo callback passed to the
9472 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9476 // HRESULT indicating success or failure.
9479 HRESULT ProfilingGetFunctionTailcall3Info(FunctionID functionId, // in
9480 COR_PRF_ELT_INFO eltInfo, // in
9481 COR_PRF_FRAME_INFO * pFrameInfo) // out
9494 // ProfileArgIterator::ProfileArgIterator may take locks
9501 if ((functionId == NULL) || (eltInfo == NULL) || (pFrameInfo == NULL))
9503 return E_INVALIDARG;
9506 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9507 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9509 // The loader won't trigger a GC or throw for already loaded argument types.
9510 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9513 // Find the method this is referring to, so we can get the signature
9515 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9516 MetaSig metaSig(pMethodDesc);
9518 NewHolder<ProfileArgIterator> pProfileArgIterator;
9521 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9524 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9526 if (pProfileArgIterator == NULL)
9528 return E_UNEXPECTED;
9532 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9535 // Setup the COR_PRF_FRAME_INFO structure first.
9537 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9538 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9539 pCorPrfFrameInfo->funcID = functionId;
9540 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9542 // Tailcall is designed to report the caller, not the callee. But the taillcall hook is invoked
9543 // with registers containing parameters passed to the callee before calling into the callee.
9544 // This pointer we get here is for the callee. Because of the constraints imposed on tailcall
9545 // optimization, this pointer passed to the callee accidentally happens to be the same this pointer
9546 // passed to the caller.
9548 // It is a fragile coincidence we should not depend on because JIT is free to change the
9549 // implementation details in the future.
9550 pCorPrfFrameInfo->extraArg = NULL;
9551 pCorPrfFrameInfo->thisArg = NULL;
9553 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9559 HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId, // in
9560 COR_PRF_ELT_INFO eltInfo, // in
9561 COR_PRF_FRAME_INFO * pFrameInfo) // out
9574 // ProfilingGetFunctionTailcall3Info may take locks
9581 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9583 "**PROF: GetFunctionTailcall3Info.\n"));
9585 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL);
9587 if (!CORProfilerELT3SlowPathTailcallEnabled())
9589 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9592 return ProfilingGetFunctionTailcall3Info(functionId, eltInfo, pFrameInfo);
9595 HRESULT ProfToEEInterfaceImpl::EnumThreads(
9596 /* out */ ICorProfilerThreadEnum ** ppEnum)
9610 // Need to acquire the thread store lock
9614 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
9619 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9620 kP2EEAllowableAfterAttach,
9623 "**PROF: EnumThreads.\n"));
9629 return E_INVALIDARG;
9634 NewHolder<ProfilerThreadEnum> pThreadEnum(new (nothrow) ProfilerThreadEnum);
9635 if (pThreadEnum == NULL)
9637 return E_OUTOFMEMORY;
9640 hr = pThreadEnum->Init();
9646 // Ownership transferred to [out] param. Caller must Release() when done with this.
9647 *ppEnum = (ICorProfilerThreadEnum *) pThreadEnum.Extract();
9652 // This function needs to be called on any thread before making any ICorProfilerInfo* calls and must be
9653 // made before any thread is suspended by this profiler.
9654 // As you might have already figured out, this is done to avoid deadlocks situation when
9655 // the suspended thread holds on the loader lock / heap lock while the current thread is trying to obtain
9657 HRESULT ProfToEEInterfaceImpl::InitializeCurrentThread()
9671 // May take thread store lock and OS APIs may also take locks
9678 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9679 kP2EEAllowableAfterAttach,
9682 "**PROF: InitializeCurrentThread.\n"));
9688 CExecutionEngine::SetupTLSForThread(GetThread());
9690 EX_CATCH_HRESULT(hr);
9698 struct InternalProfilerModuleEnum : public ProfilerModuleEnum
9700 CDynArray<ModuleID> *GetRawElementsArray()
9706 HRESULT ProfToEEInterfaceImpl::EnumNgenModuleMethodsInliningThisMethod(
9707 ModuleID inlinersModuleId,
9708 ModuleID inlineeModuleId,
9709 mdMethodDef inlineeMethodId,
9710 BOOL *incompleteData,
9711 ICorProfilerMethodEnum** ppEnum)
9719 PRECONDITION(CheckPointer(ppEnum));
9723 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: EnumNgenModuleMethodsInliningThisMethod.\n"));
9727 return E_INVALIDARG;
9732 Module *inlineeOwnerModule = reinterpret_cast<Module *>(inlineeModuleId);
9733 if (inlineeOwnerModule == NULL)
9735 return E_INVALIDARG;
9737 if (inlineeOwnerModule->IsBeingUnloaded())
9739 return CORPROF_E_DATAINCOMPLETE;
9742 Module *inlinersModule = reinterpret_cast<Module *>(inlinersModuleId);
9743 if (inlinersModule == NULL)
9745 return E_INVALIDARG;
9747 if(inlinersModule->IsBeingUnloaded())
9749 return CORPROF_E_DATAINCOMPLETE;
9752 if (!inlinersModule->HasNativeOrReadyToRunInlineTrackingMap())
9754 return CORPROF_E_DATAINCOMPLETE;
9757 CDynArray<COR_PRF_METHOD> results;
9758 const COUNT_T staticBufferSize = 10;
9759 MethodInModule staticBuffer[staticBufferSize];
9760 NewArrayHolder<MethodInModule> dynamicBuffer;
9761 MethodInModule *methodsBuffer = staticBuffer;
9764 // Trying to use static buffer
9765 COUNT_T methodsAvailable = inlinersModule->GetNativeOrReadyToRunInliners(inlineeOwnerModule, inlineeMethodId, staticBufferSize, staticBuffer, incompleteData);
9767 // If static buffer is not enough, allocate an array.
9768 if (methodsAvailable > staticBufferSize)
9770 DWORD dynamicBufferSize = methodsAvailable;
9771 dynamicBuffer = methodsBuffer = new MethodInModule[dynamicBufferSize];
9772 methodsAvailable = inlinersModule->GetNativeOrReadyToRunInliners(inlineeOwnerModule, inlineeMethodId, dynamicBufferSize, dynamicBuffer, incompleteData);
9773 if (methodsAvailable > dynamicBufferSize)
9775 _ASSERTE(!"Ngen image inlining info changed, this shouldn't be possible.");
9776 methodsAvailable = dynamicBufferSize;
9780 //Go through all inliners found in the inlinersModule and prepare them to export via results.
9781 results.AllocateBlockThrowing(methodsAvailable);
9782 for (COUNT_T j = 0; j < methodsAvailable; j++)
9784 COR_PRF_METHOD *newPrfMethod = &results[j];
9785 newPrfMethod->moduleId = reinterpret_cast<ModuleID>(methodsBuffer[j].m_module);
9786 newPrfMethod->methodId = methodsBuffer[j].m_methodDef;
9788 *ppEnum = new ProfilerMethodEnum(&results);
9790 EX_CATCH_HRESULT(hr);
9795 HRESULT ProfToEEInterfaceImpl::GetInMemorySymbolsLength(
9797 DWORD* pCountSymbolBytes)
9809 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9810 kP2EEAllowableAfterAttach,
9813 "**PROF: GetInMemorySymbolsLength.\n"));
9816 if (pCountSymbolBytes == NULL)
9818 return E_INVALIDARG;
9820 *pCountSymbolBytes = 0;
9822 Module* pModule = reinterpret_cast< Module* >(moduleId);
9823 if (pModule == NULL)
9825 return E_INVALIDARG;
9827 if (pModule->IsBeingUnloaded())
9829 return CORPROF_E_DATAINCOMPLETE;
9832 //This method would work fine on reflection.emit, but there would be no way to know
9833 //if some other thread was changing the size of the symbols before this method returned.
9834 //Adding events or locks to detect/prevent changes would make the scenario workable
9835 if (pModule->IsReflection())
9837 return COR_PRF_MODULE_DYNAMIC;
9840 CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9841 if (pStream == NULL)
9846 STATSTG SizeData = { 0 };
9847 hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9852 if (SizeData.cbSize.u.HighPart > 0)
9854 return COR_E_OVERFLOW;
9856 *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
9861 HRESULT ProfToEEInterfaceImpl::ReadInMemorySymbols(
9863 DWORD symbolsReadOffset,
9865 DWORD countSymbolBytes,
9866 DWORD* pCountSymbolBytesRead)
9876 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9877 kP2EEAllowableAfterAttach,
9880 "**PROF: ReadInMemorySymbols.\n"));
9883 if (pSymbolBytes == NULL)
9885 return E_INVALIDARG;
9887 if (pCountSymbolBytesRead == NULL)
9889 return E_INVALIDARG;
9891 *pCountSymbolBytesRead = 0;
9893 Module* pModule = reinterpret_cast< Module* >(moduleId);
9894 if (pModule == NULL)
9896 return E_INVALIDARG;
9898 if (pModule->IsBeingUnloaded())
9900 return CORPROF_E_DATAINCOMPLETE;
9903 //This method would work fine on reflection.emit, but there would be no way to know
9904 //if some other thread was changing the size of the symbols before this method returned.
9905 //Adding events or locks to detect/prevent changes would make the scenario workable
9906 if (pModule->IsReflection())
9908 return COR_PRF_MODULE_DYNAMIC;
9911 CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9912 if (pStream == NULL)
9914 return E_INVALIDARG;
9917 STATSTG SizeData = { 0 };
9918 hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9923 if (SizeData.cbSize.u.HighPart > 0)
9925 return COR_E_OVERFLOW;
9927 DWORD streamSize = SizeData.cbSize.u.LowPart;
9928 if (symbolsReadOffset >= streamSize)
9930 return E_INVALIDARG;
9933 *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
9934 memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
9939 HRESULT ProfToEEInterfaceImpl::ApplyMetaData(
9950 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach | kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: ApplyMetaData.\n"));
9952 if (moduleId == NULL)
9954 return E_INVALIDARG;
9960 Module *pModule = (Module *)moduleId;
9961 _ASSERTE(pModule != NULL);
9962 if (pModule->IsBeingUnloaded())
9964 hr = CORPROF_E_DATAINCOMPLETE;
9968 pModule->ApplyMetaData();
9971 EX_CATCH_HRESULT(hr);
9975 //---------------------------------------------------------------------------------------
9977 // Simple wrapper around EEToProfInterfaceImpl::ManagedToUnmanagedTransition. This
9978 // can be called by C++ code and directly by generated stubs.
9981 // pMD - MethodDesc for the managed function involved in the transition
9982 // reason - Passed on to profiler to indicate why the transition is occurring
9985 void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD,
9986 COR_PRF_TRANSITION_REASON reason)
9996 // This function is called within the runtime, not directly from managed code.
9997 // Also, the only case MD is NULL is the calli pinvoke case, and we still
9998 // want to notify the profiler in that case.
10000 // Do not notify the profiler about QCalls
10001 if (pMD == NULL || !pMD->IsQCall())
10003 BEGIN_PIN_PROFILER(CORProfilerPresent());
10004 g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD),
10006 END_PIN_PROFILER();
10010 //---------------------------------------------------------------------------------------
10012 // Simple wrapper around EEToProfInterfaceImpl::UnmanagedToManagedTransition. This
10013 // can be called by C++ code and directly by generated stubs.
10016 // pMD - MethodDesc for the managed function involved in the transition
10017 // reason - Passed on to profiler to indicate why the transition is occurring
10020 void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD,
10021 COR_PRF_TRANSITION_REASON reason)
10031 // This function is called within the runtime, not directly from managed code.
10032 // Also, the only case MD is NULL is the calli pinvoke case, and we still
10033 // want to notify the profiler in that case.
10035 // Do not notify the profiler about QCalls
10036 if (pMD == NULL || !pMD->IsQCall())
10038 BEGIN_PIN_PROFILER(CORProfilerPresent());
10039 g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD),
10041 END_PIN_PROFILER();
10047 #endif // PROFILING_SUPPORTED
10050 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemoting)
10054 #ifdef PROFILING_SUPPORTED
10055 FC_RETURN_BOOL(CORProfilerTrackRemoting());
10056 #else // !PROFILING_SUPPORTED
10057 FC_RETURN_BOOL(FALSE);
10058 #endif // !PROFILING_SUPPORTED
10062 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingCookie)
10066 #ifdef PROFILING_SUPPORTED
10067 FC_RETURN_BOOL(CORProfilerTrackRemotingCookie());
10068 #else // !PROFILING_SUPPORTED
10069 FC_RETURN_BOOL(FALSE);
10070 #endif // !PROFILING_SUPPORTED
10074 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingAsync)
10078 #ifdef PROFILING_SUPPORTED
10079 FC_RETURN_BOOL(CORProfilerTrackRemotingAsync());
10080 #else // !PROFILING_SUPPORTED
10081 FC_RETURN_BOOL(FALSE);
10082 #endif // !PROFILING_SUPPORTED
10086 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingClientSendingMessage, GUID *pId, CLR_BOOL fIsAsync)
10090 #ifdef PROFILING_SUPPORTED
10091 // Need to erect a GC frame so that GCs can occur without a problem
10092 // within the profiler code.
10094 // Note that we don't need to worry about pId moving around since
10095 // it is a value class declared on the stack and so GC doesn't
10098 _ASSERTE (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pId)); // should be on the stack, not in the heap
10099 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10102 BEGIN_PIN_PROFILER(CORProfilerPresent());
10104 if (CORProfilerTrackRemotingCookie())
10106 g_profControlBlock.pProfInterface->GetGUID(pId);
10107 _ASSERTE(pId->Data1);
10109 g_profControlBlock.pProfInterface->RemotingClientSendingMessage(pId, fIsAsync);
10113 g_profControlBlock.pProfInterface->RemotingClientSendingMessage(NULL, fIsAsync);
10115 END_PIN_PROFILER();
10117 HELPER_METHOD_FRAME_END_POLL();
10118 #endif // PROFILING_SUPPORTED
10123 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingClientReceivingReply, GUID id, CLR_BOOL fIsAsync)
10127 #ifdef PROFILING_SUPPORTED
10128 // Need to erect a GC frame so that GCs can occur without a problem
10129 // within the profiler code.
10131 // Note that we don't need to worry about pId moving around since
10132 // it is a value class declared on the stack and so GC doesn't
10135 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10139 BEGIN_PIN_PROFILER(CORProfilerPresent());
10141 if (CORProfilerTrackRemotingCookie())
10143 g_profControlBlock.pProfInterface->RemotingClientReceivingReply(&id, fIsAsync);
10147 g_profControlBlock.pProfInterface->RemotingClientReceivingReply(NULL, fIsAsync);
10149 END_PIN_PROFILER();
10152 HELPER_METHOD_FRAME_END_POLL();
10153 #endif // PROFILING_SUPPORTED
10158 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingServerReceivingMessage, GUID id, CLR_BOOL fIsAsync)
10162 #ifdef PROFILING_SUPPORTED
10163 // Need to erect a GC frame so that GCs can occur without a problem
10164 // within the profiler code.
10166 // Note that we don't need to worry about pId moving around since
10167 // it is a value class declared on the stack and so GC doesn't
10170 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10173 BEGIN_PIN_PROFILER(CORProfilerPresent());
10175 if (CORProfilerTrackRemotingCookie())
10177 g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(&id, fIsAsync);
10181 g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(NULL, fIsAsync);
10183 END_PIN_PROFILER();
10186 HELPER_METHOD_FRAME_END_POLL();
10187 #endif // PROFILING_SUPPORTED
10191 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingServerSendingReply, GUID *pId, CLR_BOOL fIsAsync)
10195 #ifdef PROFILING_SUPPORTED
10196 // Need to erect a GC frame so that GCs can occur without a problem
10197 // within the profiler code.
10199 // Note that we don't need to worry about pId moving around since
10200 // it is a value class declared on the stack and so GC doesn't
10203 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10206 BEGIN_PIN_PROFILER(CORProfilerPresent());
10208 if (CORProfilerTrackRemotingCookie())
10210 g_profControlBlock.pProfInterface->GetGUID(pId);
10211 _ASSERTE(pId->Data1);
10213 g_profControlBlock.pProfInterface->RemotingServerSendingReply(pId, fIsAsync);
10217 g_profControlBlock.pProfInterface->RemotingServerSendingReply(NULL, fIsAsync);
10219 END_PIN_PROFILER();
10222 HELPER_METHOD_FRAME_END_POLL();
10223 #endif // PROFILING_SUPPORTED
10228 //*******************************************************************************************
10229 // These do a lot of work for us, setting up Frames, gathering arg info and resolving generics.
10230 //*******************************************************************************************
10232 HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecificHandle)
10236 #ifdef PROFILING_SUPPORTED
10238 // We might have already torn down the profiler, if so we need to abort.
10239 if (g_profControlBlock.curProfStatus.Get() != kProfStatusActive
10240 #ifdef PROF_TEST_ONLY_FORCE_ELT
10241 // If this test-only flag is set, it's possible we might not have a profiler
10242 // attached, or might not have any of the hooks set. See
10243 // code:ProfControlBlock#TestOnlyELT
10244 || g_profControlBlock.fTestOnlyForceEnterLeave
10245 #endif // PROF_TEST_ONLY_FORCE_ELT
10248 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10250 (g_profControlBlock.pProfInterface->GetEnterHook() == NULL) &&
10251 (g_profControlBlock.pProfInterface->GetEnter2Hook() == NULL) &&
10252 (g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL) &&
10253 (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL)
10261 // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10262 _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL);
10263 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10264 _ASSERTE(platformSpecificHandle != NULL);
10267 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10269 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10270 // frame, like we're about to do.
10271 SetCallbackStateFlagsHolder csf(
10272 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10274 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10275 eltInfo.platformSpecificHandle = platformSpecificHandle;
10278 // CLR v4 Slow-Path ELT
10280 if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL)
10282 FunctionIDOrClientID functionIDOrClientID;
10283 functionIDOrClientID.clientID = clientData;
10284 g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()(
10285 functionIDOrClientID,
10286 (COR_PRF_ELT_INFO)&eltInfo);
10290 if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL)
10292 // We have run out of heap memory, so the content of the mapping table becomes stale.
10293 // All Whidbey ETL hooks must be turned off.
10294 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10299 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10300 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10301 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10302 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10303 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10304 FunctionID functionId = clientData;
10305 _ASSERTE(functionId != NULL);
10306 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10309 // Whidbey Fast-Path ELT
10311 if (CORProfilerELT2FastPathEnterEnabled())
10313 g_profControlBlock.pProfInterface->GetEnter2Hook()(
10322 // Whidbey Slow-Path ELT
10324 ProfileSetFunctionIDInPlatformSpecificHandle(platformSpecificHandle, functionId);
10326 COR_PRF_FRAME_INFO frameInfo = NULL;
10327 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo = NULL;
10328 ULONG ulArgInfoSize = 0;
10330 if (CORProfilerFunctionArgsEnabled())
10332 // The loader won't trigger a GC or throw for already loaded argument types.
10333 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
10336 // Find the method this is referring to, so we can get the signature
10338 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
10339 MetaSig metaSig(pMethodDesc);
10341 NewHolder<ProfileArgIterator> pProfileArgIterator;
10344 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
10347 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, platformSpecificHandle);
10349 if (pProfileArgIterator == NULL)
10355 ULONG32 count = pProfileArgIterator->GetNumArgs();
10357 if (metaSig.HasThis())
10362 ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE);
10363 pArgumentInfo = (COR_PRF_FUNCTION_ARGUMENT_INFO *)_alloca(ulArgInfoSize);
10366 HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo);
10368 _ASSERTE(hr == S_OK);
10369 g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
10375 // We will not be here unless the jit'd or ngen'd function we're about to enter
10376 // was backpatched with this wrapper around the profiler's hook, and that
10377 // wouldn't have happened unless the profiler supplied us with a hook
10378 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10379 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10380 // its mind about where the hooks are.)
10381 _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL);
10383 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10384 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10385 // to enable the jitter to add enter/leave callouts independently of whether
10386 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10387 // the callouts quickly return and do nothing.)
10393 g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData);
10399 HELPER_METHOD_FRAME_END(); // Un-link the frame
10401 #endif // PROFILING_SUPPORTED
10405 HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecificHandle)
10409 FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
10411 #ifdef PROFILING_SUPPORTED
10413 // We might have already torn down the profiler, if so we need to abort.
10414 if (g_profControlBlock.curProfStatus.Get() != kProfStatusActive
10415 #ifdef PROF_TEST_ONLY_FORCE_ELT
10416 // If this test-only flag is set, it's possible we might not have a profiler
10417 // attached, or might not have any of the hooks set. See
10418 // code:ProfControlBlock#TestOnlyELT
10419 || g_profControlBlock.fTestOnlyForceEnterLeave
10420 #endif // PROF_TEST_ONLY_FORCE_ELT
10423 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10425 (g_profControlBlock.pProfInterface->GetLeaveHook() == NULL) &&
10426 (g_profControlBlock.pProfInterface->GetLeave2Hook() == NULL) &&
10427 (g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL) &&
10428 (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL)
10436 // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10437 _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL);
10438 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10439 _ASSERTE(platformSpecificHandle != NULL);
10442 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10444 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10445 // frame, like we're about to do.
10446 SetCallbackStateFlagsHolder csf(
10447 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10449 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10450 eltInfo.platformSpecificHandle = platformSpecificHandle;
10453 // CLR v4 Slow-Path ELT
10455 if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL)
10457 FunctionIDOrClientID functionIDOrClientID;
10458 functionIDOrClientID.clientID = clientData;
10459 g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()(
10460 functionIDOrClientID,
10461 (COR_PRF_ELT_INFO)&eltInfo);
10465 if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL)
10467 // We have run out of heap memory, so the content of the mapping table becomes stale.
10468 // All Whidbey ETL hooks must be turned off.
10469 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10474 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10475 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10476 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10477 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10478 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10479 FunctionID functionId = clientData;
10480 _ASSERTE(functionId != NULL);
10481 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10484 // Whidbey Fast-Path ELT
10486 if (CORProfilerELT2FastPathLeaveEnabled())
10488 g_profControlBlock.pProfInterface->GetLeave2Hook()(
10497 // Whidbey Slow-Path ELT
10499 COR_PRF_FRAME_INFO frameInfo = NULL;
10500 COR_PRF_FUNCTION_ARGUMENT_RANGE argumentRange;
10502 HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange);
10503 _ASSERTE(hr == S_OK);
10505 g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
10509 // We will not be here unless the jit'd or ngen'd function we're about to leave
10510 // was backpatched with this wrapper around the profiler's hook, and that
10511 // wouldn't have happened unless the profiler supplied us with a hook
10512 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10513 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10514 // its mind about where the hooks are.)
10515 _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL);
10517 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10518 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10519 // to enable the jitter to add enter/leave callouts independently of whether
10520 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10521 // the callouts quickly return and do nothing.)
10527 g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData);
10534 HELPER_METHOD_FRAME_END(); // Un-link the frame
10536 #endif // PROFILING_SUPPORTED
10540 HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpecificHandle)
10544 FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
10546 #ifdef PROFILING_SUPPORTED
10548 // We might have already torn down the profiler, if so we need to abort.
10549 if (g_profControlBlock.curProfStatus.Get() != kProfStatusActive
10550 #ifdef PROF_TEST_ONLY_FORCE_ELT
10551 // If this test-only flag is set, it's possible we might not have a profiler
10552 // attached, or might not have any of the hooks set. See
10553 // code:ProfControlBlock#TestOnlyELT
10554 || g_profControlBlock.fTestOnlyForceEnterLeave
10555 #endif // PROF_TEST_ONLY_FORCE_ELT
10558 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10560 (g_profControlBlock.pProfInterface->GetTailcallHook() == NULL) &&
10561 (g_profControlBlock.pProfInterface->GetTailcall2Hook() == NULL) &&
10562 (g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL) &&
10563 (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL)
10571 // ELT3 fast-path hooks should be NULL when ELT intermediary is used.
10572 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL);
10573 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10574 _ASSERTE(platformSpecificHandle != NULL);
10577 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10579 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10580 // frame, like we're about to do.
10581 SetCallbackStateFlagsHolder csf(
10582 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10584 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10585 eltInfo.platformSpecificHandle = platformSpecificHandle;
10588 // CLR v4 Slow-Path ELT
10590 if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL)
10592 FunctionIDOrClientID functionIDOrClientID;
10593 functionIDOrClientID.clientID = clientData;
10594 g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()(
10595 functionIDOrClientID,
10596 (COR_PRF_ELT_INFO)&eltInfo);
10600 if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL)
10602 // We have run out of heap memory, so the content of the mapping table becomes stale.
10603 // All Whidbey ETL hooks must be turned off.
10604 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10609 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10610 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10611 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10612 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10613 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10614 FunctionID functionId = clientData;
10615 _ASSERTE(functionId != NULL);
10616 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10619 // Whidbey Fast-Path ELT
10621 if (CORProfilerELT2FastPathTailcallEnabled())
10623 g_profControlBlock.pProfInterface->GetTailcall2Hook()(
10631 // Whidbey Slow-Path ELT
10633 COR_PRF_FRAME_INFO frameInfo = NULL;
10635 HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo);
10636 _ASSERTE(hr == S_OK);
10638 g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
10642 // We will not be here unless the jit'd or ngen'd function we're about to tailcall
10643 // was backpatched with this wrapper around the profiler's hook, and that
10644 // wouldn't have happened unless the profiler supplied us with a hook
10645 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10646 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10647 // its mind about where the hooks are.)
10648 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL);
10650 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10651 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10652 // to enable the jitter to add enter/leave callouts independently of whether
10653 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10654 // the callouts quickly return and do nothing.)
10659 g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData);
10665 HELPER_METHOD_FRAME_END(); // Un-link the frame
10667 #endif // PROFILING_SUPPORTED