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):
49 // (EE_THREAD_(NOT)_REQUIRED are unenforced and are thus optional. If you wish
50 // to specify these, EE_THREAD_NOT_REQUIRED is preferred.)
51 // Note that the preferred contracts in this file are DIFFERENT than the preferred
52 // contracts for eetoprofinterfaceimpl.cpp.
54 // Private helper functions in this file do not have the same preferred contracts as
55 // public entrypoints, and they should be contracted following the same guidelines
56 // as per the rest of the EE.
58 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
59 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
62 // #P2CLRRestrictionsOverview
64 // The public ICorProfilerInfo(N) functions below have different restrictions on when
65 // they're allowed to be called. Listed roughly in order from most to least restrictive:
66 // * PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY: Functions that are only
67 // allowed to be called while the profiler is initializing on startup, from
68 // inside the profiler's ICorProfilerCallback::Initialize method
69 // * PROFILER_TO_CLR_ENTRYPOINT_SYNC: Functions that may be called from within any of
70 // the profiler's callbacks, or anytime from a thread created by the profiler.
71 // These functions may only be called by profilers loaded on startup
72 // * PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach): Same as above,
73 // except these may be called by startup AND attaching profilers.
74 // * PROFILER_TO_CLR_ENTRYPOINT_ASYNC: Functions that may be called at any time and
75 // from any thread by a profiler loaded on startup
76 // * PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach): Same as above,
77 // except these may be called by startup AND attaching profilers.
79 // The above restrictions are lifted for certain tests that run with these environment
80 // variables set. (These are only available on DEBUG builds--including chk--not retail
82 // * COMPlus_TestOnlyEnableSlowELTHooks:
83 // * If nonzero, then on startup the runtime will act as if a profiler was loaded
84 // on startup and requested ELT slow-path (even if no profiler is loaded on
85 // startup). This will also allow the SetEnterLeaveFunctionHooks(2) info
86 // functions to be called outside of Initialize(). If a profiler later
87 // attaches and calls these functions, then the slow-path wrapper will call
88 // into the profiler's ELT hooks.
89 // * COMPlus_TestOnlyEnableObjectAllocatedHook:
90 // * If nonzero, then on startup the runtime will act as if a profiler was loaded
91 // on startup and requested ObjectAllocated callback (even if no profiler is loaded
92 // on startup). If a profiler later attaches and calls these functions, then the
93 // ObjectAllocated notifications will call into the profiler's ObjectAllocated callback.
94 // * COMPlus_TestOnlyEnableICorProfilerInfo:
95 // * If nonzero, then attaching profilers allows to call ICorProfilerInfo inteface,
96 // which would otherwise be disallowed for attaching profilers
97 // * COMPlus_TestOnlyAllowedEventMask
98 // * If a profiler needs to work around the restrictions of either
99 // COR_PRF_ALLOWABLE_AFTER_ATTACH or COR_PRF_MONITOR_IMMUTABLE it may set
100 // this environment variable. Its value should be a bitmask containing all
101 // the flags that are:
102 // * normally immutable or disallowed after attach, AND
103 // * that the test plans to set after startup and / or by an attaching
109 // ======================================================================================
112 #include <posterror.h>
113 #include "proftoeeinterfaceimpl.h"
114 #include "proftoeeinterfaceimpl.inl"
115 #include "dllimport.h"
117 #include "method.hpp"
119 #include "dbginterface.h"
124 #include "eeconfig.h"
125 #include "generics.h"
127 #include "safemath.h"
128 #include "threadsuspend.h"
129 #include "inlinetracking.h"
131 #ifdef PROFILING_SUPPORTED
132 #include "profilinghelper.h"
133 #include "profilinghelper.inl"
134 #include "eetoprofinterfaceimpl.inl"
135 #include "profilingenumerators.h"
138 #include "profdetach.h"
140 #include "metadataexports.h"
142 //---------------------------------------------------------------------------------------
145 // An OR'd combination of these flags may be specified in the _EX entrypoint macros to
146 // customize the behavior.
147 enum ProfToClrEntrypointFlags
149 // Just use the default behavior (this one is used if the non-_EX entrypoint macro is
150 // specified without any flags).
151 kP2EENone = 0x00000000,
153 // By default, Info functions are not allowed to be used by an attaching profiler.
154 // Specify this flag to override the default.
155 kP2EEAllowableAfterAttach = 0x00000001,
157 // This info method has a GC_TRIGGERS contract. Whereas contracts are debug-only,
158 // this flag is used in retail builds as well.
159 kP2EETriggers = 0x00000002,
162 // Default versions of the entrypoint macros use kP2EENone if no
163 // ProfToClrEntrypointFlags are specified
165 #define PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams) \
166 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EENone, logParams)
168 #define PROFILER_TO_CLR_ENTRYPOINT_SYNC(logParams) \
169 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EENone, logParams)
171 // ASYNC entrypoints log and ensure an attaching profiler isn't making a call that's
172 // only supported by startup profilers.
174 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags) \
177 if ((((p2eeFlags) & kP2EEAllowableAfterAttach) == 0) && \
178 (g_profControlBlock.pProfInterface->IsLoadedViaAttach())) \
182 "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER " \
183 "due to a call illegally made by an attaching profiler \n")); \
184 return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER; \
190 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags) \
193 if (!((&g_profControlBlock)->fTestOnlyEnableICorProfilerInfo)) \
195 CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags); \
203 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags) \
206 CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags); \
211 #define PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(p2eeFlags, logParams) \
214 INCONTRACT(AssertTriggersContract(((p2eeFlags) & kP2EETriggers))); \
215 _ASSERTE(g_profControlBlock.curProfStatus.Get() != kProfStatusNone); \
217 /* If profiler was neutered, disallow call */ \
218 if (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \
222 "**PROF: ERROR: Returning CORPROF_E_PROFILER_DETACHING " \
223 "due to a post-neutered profiler call\n")); \
224 return CORPROF_E_PROFILER_DETACHING; \
226 CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags); \
229 // SYNC entrypoints must ensure the current EE Thread shows evidence that we're
230 // inside a callback. If there's no EE Thread, then we automatically "pass"
231 // the check, and the SYNC call is allowed.
232 #define PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(p2eeFlags, logParams) \
235 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(p2eeFlags, logParams); \
236 DWORD __dwExpectedCallbackState = COR_PRF_CALLBACKSTATE_INCALLBACK; \
237 if (((p2eeFlags) & kP2EETriggers) != 0) \
239 __dwExpectedCallbackState |= COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE; \
241 if (!AreCallbackStateFlagsSet(__dwExpectedCallbackState)) \
245 "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE " \
246 "due to illegal asynchronous profiler call\n")); \
247 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE; \
251 // INIT_ONLY entrypoints must ensure we're executing inside the profiler's
252 // Initialize() implementation on startup (attach init doesn't count!).
253 #define PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams) \
256 PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams); \
257 if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad && \
258 g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForAttachLoad) \
260 return CORPROF_E_CALL_ONLY_FROM_INIT; \
264 // This macro is used to ensure that the current thread is not in a forbid
265 // suspend region. Some methods are allowed to be called asynchronously,
266 // but some of them call JIT functions that take a reader lock. So we need to ensure
267 // the current thread hasn't been hijacked by a profiler while it was holding the writer lock.
268 // Checking the ForbidSuspendThread region is a sufficient test for this
269 #define FAIL_IF_IN_FORBID_SUSPEND_REGION() \
272 Thread * __pThread = GetThreadNULLOk(); \
273 if ((__pThread != NULL) && (__pThread->IsInForbidSuspendRegion())) \
275 return CORPROF_E_ASYNCHRONOUS_UNSAFE; \
280 // This type is an overlay onto the exported type COR_PRF_FRAME_INFO.
281 // The first four fields *must* line up with the same fields in the
282 // exported type. After that, we can add to the end as we wish.
284 typedef struct _COR_PRF_FRAME_INFO_INTERNAL {
291 } COR_PRF_FRAME_INFO_INTERNAL, *PCOR_PRF_FRAME_INFO_INTERNAL;
294 // After we ship a product with a certain struct type for COR_PRF_FRAME_INFO_INTERNAL
295 // we have that as a version. If we change that in a later product, we can increment
296 // the counter below and then we can properly do versioning.
298 #define COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION 1
301 //---------------------------------------------------------------------------------------
303 // Converts TypeHandle to a ClassID
306 // th - TypeHandle to convert
309 // Requested ClassID.
312 ClassID TypeHandleToClassID(TypeHandle th)
315 return reinterpret_cast<ClassID> (th.AsPtr());
318 //---------------------------------------------------------------------------------------
320 // Converts TypeHandle for a non-generic type to a ClassID
323 // th - TypeHandle to convert
326 // Requested ClassID. NULL if th represents a generic type
328 #ifdef PROFILING_SUPPORTED
330 static ClassID NonGenericTypeHandleToClassID(TypeHandle th)
340 if ((!th.IsNull()) && (th.HasInstantiation()))
345 return TypeHandleToClassID(th);
348 //---------------------------------------------------------------------------------------
350 // Converts MethodDesc * to FunctionID
353 // pMD - MethodDesc * to convert
356 // Requested FunctionID
359 static FunctionID MethodDescToFunctionID(MethodDesc * pMD)
361 LIMITED_METHOD_CONTRACT;
362 return reinterpret_cast< FunctionID > (pMD);
367 //---------------------------------------------------------------------------------------
369 // Converts FunctionID to MethodDesc *
372 // functionID - FunctionID to convert
375 // MethodDesc * requested
378 MethodDesc *FunctionIdToMethodDesc(FunctionID functionID)
380 LIMITED_METHOD_CONTRACT;
382 MethodDesc *pMethodDesc;
384 pMethodDesc = reinterpret_cast< MethodDesc* >(functionID);
386 _ASSERTE(pMethodDesc != NULL);
390 // (See comments for ArrayKindFromTypeHandle below.)
393 ARRAY_KIND_TYPEDESC, // Normal, garden-variety typedesc array
394 ARRAY_KIND_METHODTABLE, // Weirdo array with its own unshared methodtable (e.g., System.Object[])
395 ARRAY_KIND_NOTARRAY, // Not an array
398 //---------------------------------------------------------------------------------------
400 // A couple Info calls need to understand what constitutes an "array", and what
401 // kinds of arrays there are. ArrayKindFromTypeHandle tries to put some of this
402 // knowledge in a single place
405 // th - TypeHandle to inspect
408 // ARRAY_KIND describing th
411 inline ARRAY_KIND ArrayKindFromTypeHandle(TypeHandle th)
413 LIMITED_METHOD_CONTRACT;
417 return ARRAY_KIND_TYPEDESC;
420 if (!th.IsTypeDesc() && th.GetMethodTable()->IsArray())
422 return ARRAY_KIND_METHODTABLE;
425 return ARRAY_KIND_NOTARRAY;
428 #ifdef PROFILING_SUPPORTED
430 //---------------------------------------------------------------------------------------
431 // ModuleILHeap IUnknown implementation
433 // Function headers unnecessary, as MSDN adequately documents IUnknown
436 ULONG ModuleILHeap::AddRef()
438 // Lifetime of this object is controlled entirely by the CLR. This
439 // is created on first request, and is automatically destroyed when
440 // the profiler is detached.
445 ULONG ModuleILHeap::Release()
447 // Lifetime of this object is controlled entirely by the CLR. This
448 // is created on first request, and is automatically destroyed when
449 // the profiler is detached.
454 HRESULT ModuleILHeap::QueryInterface(REFIID riid, void ** pp)
464 if (riid == IID_IUnknown)
466 *pp = static_cast<IUnknown *>(this);
468 else if (riid == IID_IMethodMalloc)
470 *pp = static_cast<IMethodMalloc *>(this);
479 // CLR manages lifetime of this object, but in case that changes (or
480 // this code gets copied/pasted elsewhere), we'll still AddRef here so
481 // QI remains a good citizen either way.
487 //---------------------------------------------------------------------------------------
488 // Profiler entrypoint to allocate space from this module's heap.
491 // cb - size in bytes of allocation request
494 // pointer to allocated memory, or NULL if there was an error
496 void * STDMETHODCALLTYPE ModuleILHeap::Alloc(ULONG cb)
503 // (see GC_TRIGGERS comment below)
506 // Allocations using loader heaps below enter a critsec, which switches
507 // to preemptive, which is effectively a GC trigger
517 LOG((LF_CORPROF, LL_INFO1000, "**PROF: ModuleILHeap::Alloc 0x%08xp.\n", cb));
524 return new (nothrow) BYTE[cb];
527 //---------------------------------------------------------------------------------------
528 // The one and only instance of the IL heap
530 ModuleILHeap ModuleILHeap::s_Heap;
532 //---------------------------------------------------------------------------------------
533 // Implementation of ProfToEEInterfaceImpl's IUnknown
536 // The VM controls the lifetime of ProfToEEInterfaceImpl, not the
537 // profiler. We'll automatically take care of cleanup when profilers
538 // unload and detach.
541 ULONG STDMETHODCALLTYPE ProfToEEInterfaceImpl::AddRef()
543 LIMITED_METHOD_CONTRACT;
547 ULONG STDMETHODCALLTYPE ProfToEEInterfaceImpl::Release()
549 LIMITED_METHOD_CONTRACT;
553 COM_METHOD ProfToEEInterfaceImpl::QueryInterface(REFIID id, void ** pInterface)
555 if (pInterface == NULL)
560 if (id == IID_ICorProfilerInfo)
562 *pInterface = static_cast<ICorProfilerInfo *>(this);
564 else if (id == IID_ICorProfilerInfo2)
566 *pInterface = static_cast<ICorProfilerInfo2 *>(this);
568 else if (id == IID_ICorProfilerInfo3)
570 *pInterface = static_cast<ICorProfilerInfo3 *>(this);
572 else if (id == IID_ICorProfilerInfo4)
574 *pInterface = static_cast<ICorProfilerInfo4 *>(this);
576 else if (id == IID_ICorProfilerInfo5)
578 *pInterface = static_cast<ICorProfilerInfo5 *>(this);
580 else if (id == IID_ICorProfilerInfo6)
582 *pInterface = static_cast<ICorProfilerInfo6 *>(this);
584 else if (id == IID_ICorProfilerInfo7)
586 *pInterface = static_cast<ICorProfilerInfo7 *>(this);
588 else if (id == IID_ICorProfilerInfo8)
590 *pInterface = static_cast<ICorProfilerInfo8 *>(this);
592 else if (id == IID_IUnknown)
594 *pInterface = static_cast<IUnknown *>(static_cast<ICorProfilerInfo *>(this));
599 return E_NOINTERFACE;
602 // CLR manages lifetime of this object, but in case that changes (or
603 // this code gets copied/pasted elsewhere), we'll still AddRef here so
604 // QI remains a good citizen either way.
609 #endif // PROFILING_SUPPORTED
611 //---------------------------------------------------------------------------------------
613 // GC-related helpers. These are called from elsewhere in the EE to determine profiler
614 // state, and to update the profiling API with info from the GC.
617 //---------------------------------------------------------------------------------------
619 // ProfilerObjectAllocatedCallback is called if a profiler is attached, requesting
620 // ObjectAllocated callbacks.
623 // objref - Reference to newly-allocated object
624 // classId - ClassID of newly-allocated object
627 void __stdcall ProfilerObjectAllocatedCallback(OBJECTREF objref, ClassID classId)
637 TypeHandle th = OBJECTREFToObject(objref)->GetTypeHandle();
639 // WARNING: objref can move as a result of the ObjectAllocated() call below if
640 // the profiler causes a GC, so any operations on the objref should occur above
641 // this comment (unless you're prepared to add a GCPROTECT around the objref).
643 #ifdef PROFILING_SUPPORTED
644 // Notify the profiler of the allocation
647 BEGIN_PIN_PROFILER(CORProfilerTrackAllocations());
648 // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs.
649 // Thus we strip any instantiations of the ClassID (which is really a type handle) here.
650 g_profControlBlock.pProfInterface->ObjectAllocated(
651 (ObjectID) OBJECTREFToObject(objref),
655 #endif // PROFILING_SUPPORTED
658 //---------------------------------------------------------------------------------------
660 // Wrapper around the GC Started callback
663 // generation - Generation being collected
664 // induced - Was this GC induced by GC.Collect?
667 void __stdcall GarbageCollectionStartedCallback(int generation, BOOL induced)
673 MODE_ANY; // can be called even on GC threads
677 #ifdef PROFILING_SUPPORTED
679 // Mark that we are starting a GC. This will allow profilers to do limited object inspection
680 // during callbacks that occur while a GC is happening.
682 g_profControlBlock.fGCInProgress = TRUE;
684 // Notify the profiler of start of the collection
686 BEGIN_PIN_PROFILER(CORProfilerTrackGC());
687 BOOL generationCollected[COR_PRF_GC_LARGE_OBJECT_HEAP+1];
688 if (generation == COR_PRF_GC_GEN_2)
689 generation = COR_PRF_GC_LARGE_OBJECT_HEAP;
690 for (int gen = 0; gen <= COR_PRF_GC_LARGE_OBJECT_HEAP; gen++)
691 generationCollected[gen] = gen <= generation;
693 g_profControlBlock.pProfInterface->GarbageCollectionStarted(
694 COR_PRF_GC_LARGE_OBJECT_HEAP+1,
696 induced ? COR_PRF_GC_INDUCED : COR_PRF_GC_OTHER);
699 #endif // PROFILING_SUPPORTED
702 //---------------------------------------------------------------------------------------
704 // Wrapper around the GC Finished callback
707 void __stdcall GarbageCollectionFinishedCallback()
713 MODE_ANY; // can be called even on GC threads
717 #ifdef PROFILING_SUPPORTED
718 // Notify the profiler of end of the collection
720 BEGIN_PIN_PROFILER(CORProfilerTrackGC());
721 g_profControlBlock.pProfInterface->GarbageCollectionFinished();
725 // Mark that GC is finished.
726 g_profControlBlock.fGCInProgress = FALSE;
727 #endif // PROFILING_SUPPORTED
730 #ifdef PROFILING_SUPPORTED
731 //---------------------------------------------------------------------------------------
733 // Describes a GC generation by number and address range
736 struct GenerationDesc
741 BYTE *rangeEndReserved;
744 struct GenerationTable
748 static const ULONG defaultCapacity = 4; // that's the minimum for 3 generation plus the large object heap
749 GenerationTable *prev;
750 GenerationDesc *genDescTable;
753 #define GENERATION_TABLE_MAGIC 0x34781256
754 #define GENERATION_TABLE_BAD_MAGIC 0x55aa55aa
759 //---------------------------------------------------------------------------------------
761 // This is a callback used by the GC when we call GCHeapUtilities::DiagDescrGenerations
762 // (from UpdateGenerationBounds() below). The GC gives us generation information through
763 // this callback, which we use to update the GenerationDesc in the corresponding
767 // context - The containing GenerationTable
768 // generation - Generation number
769 // rangeStart - Address where generation starts
770 // rangeEnd - Address where generation ends
771 // rangeEndReserved - Address where generation reserved space ends
775 static void GenWalkFunc(void * context,
779 BYTE * rangeEndReserved)
785 MODE_ANY; // can be called even on GC threads
786 PRECONDITION(CheckPointer(context));
787 PRECONDITION(0 <= generation && generation <= 3);
788 PRECONDITION(CheckPointer(rangeStart));
789 PRECONDITION(CheckPointer(rangeEnd));
790 PRECONDITION(CheckPointer(rangeEndReserved));
793 GenerationTable *generationTable = (GenerationTable *)context;
795 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
797 ULONG count = generationTable->count;
798 if (count >= generationTable->capacity)
800 ULONG newCapacity = generationTable->capacity == 0 ? GenerationTable::defaultCapacity : generationTable->capacity * 2;
801 GenerationDesc *newGenDescTable = new (nothrow) GenerationDesc[newCapacity];
802 if (newGenDescTable == NULL)
804 // if we can't allocate a bigger table, we'll have to ignore this call
807 memcpy(newGenDescTable, generationTable->genDescTable, sizeof(generationTable->genDescTable[0]) * generationTable->count);
808 delete[] generationTable->genDescTable;
809 generationTable->genDescTable = newGenDescTable;
810 generationTable->capacity = newCapacity;
812 _ASSERTE(count < generationTable->capacity);
814 GenerationDesc *genDescTable = generationTable->genDescTable;
816 genDescTable[count].generation = generation;
817 genDescTable[count].rangeStart = rangeStart;
818 genDescTable[count].rangeEnd = rangeEnd;
819 genDescTable[count].rangeEndReserved = rangeEndReserved;
821 generationTable->count = count + 1;
824 // This is the table of generation bounds updated by the gc
825 // and read by the profiler. So this is a single writer,
826 // multiple readers scenario.
827 static GenerationTable *s_currentGenerationTable;
829 // The generation table is updated atomically by replacing the
830 // pointer to it. The only tricky part is knowing when
831 // the old table can be deleted.
832 static Volatile<LONG> s_generationTableLock;
834 // This is just so we can assert there's a single writer
835 #ifdef ENABLE_CONTRACTS
836 static Volatile<LONG> s_generationTableWriterCount;
838 #endif // PROFILING_SUPPORTED
840 //---------------------------------------------------------------------------------------
842 // This is called from the gc to push a new set of generation bounds
845 void __stdcall UpdateGenerationBounds()
851 MODE_ANY; // can be called even on GC threads
852 #ifdef PROFILING_SUPPORTED
853 PRECONDITION(FastInterlockIncrement(&s_generationTableWriterCount) == 1);
854 POSTCONDITION(FastInterlockDecrement(&s_generationTableWriterCount) == 0);
855 #endif // PROFILING_SUPPORTED
858 #ifdef PROFILING_SUPPORTED
859 // Notify the profiler of start of the collection
860 if (CORProfilerTrackGC())
862 // generate a new generation table
863 GenerationTable *newGenerationTable = new (nothrow) GenerationTable();
864 if (newGenerationTable == NULL)
866 newGenerationTable->count = 0;
867 newGenerationTable->capacity = GenerationTable::defaultCapacity;
868 // if there is already a current table, use its count as a guess for the capacity
869 if (s_currentGenerationTable != NULL)
870 newGenerationTable->capacity = s_currentGenerationTable->count;
871 newGenerationTable->prev = NULL;
872 newGenerationTable->genDescTable = new (nothrow) GenerationDesc[newGenerationTable->capacity];
873 if (newGenerationTable->genDescTable == NULL)
874 newGenerationTable->capacity = 0;
877 newGenerationTable->magic = GENERATION_TABLE_MAGIC;
879 // fill in the values by calling back into the gc, which will report
880 // the ranges by calling GenWalkFunc for each one
881 IGCHeap *hp = GCHeapUtilities::GetGCHeap();
882 hp->DiagDescrGenerations(GenWalkFunc, newGenerationTable);
884 // remember the old table and plug in the new one
885 GenerationTable *oldGenerationTable = s_currentGenerationTable;
886 s_currentGenerationTable = newGenerationTable;
888 // WARNING: tricky code!
890 // We sample the generation table lock *after* plugging in the new table
891 // We do so using an interlocked operation so the cpu can't reorder
892 // the write to the s_currentGenerationTable with the increment.
893 // If the interlocked increment returns 1, we know nobody can be using
894 // the old table (readers increment the lock before using the table,
895 // and decrement it afterwards). Any new readers coming in
896 // will use the new table. So it's safe to delete the old
898 // On the other hand, if the interlocked increment returns
899 // something other than one, we put the old table on a list
900 // dangling off of the new one. Next time around, we'll try again
901 // deleting any old tables.
902 if (FastInterlockIncrement(&s_generationTableLock) == 1)
904 // We know nobody can be using any of the old tables
905 while (oldGenerationTable != NULL)
907 _ASSERTE(oldGenerationTable->magic == GENERATION_TABLE_MAGIC);
909 oldGenerationTable->magic = GENERATION_TABLE_BAD_MAGIC;
911 GenerationTable *temp = oldGenerationTable;
912 oldGenerationTable = oldGenerationTable->prev;
913 delete[] temp->genDescTable;
919 // put the old table on a list
920 newGenerationTable->prev = oldGenerationTable;
922 FastInterlockDecrement(&s_generationTableLock);
924 #endif // PROFILING_SUPPORTED
928 #ifdef PROFILING_SUPPORTED
930 //---------------------------------------------------------------------------------------
932 // Determines whether we are in a window to allow object inspection.
935 // Returns S_OK if we can determine that we are in a window to allow object
936 // inspection. Otherwise a failure HRESULT is returned
939 HRESULT AllowObjectInspection()
945 MODE_ANY; // tests for preemptive mode dynamically as its main function so contract enforcement is not appropriate
950 // Check first to see if we are in the process of doing a GC and presume that the profiler
951 // is making this object inspection from the same thread that notified of a valid ObjectID.
953 if (g_profControlBlock.fGCInProgress)
959 // Thus we must have a managed thread, and it must be in coop mode.
960 // (That will also guarantee we're in a callback).
962 Thread * pThread = GetThreadNULLOk();
966 return CORPROF_E_NOT_MANAGED_THREAD;
969 // Note this is why we don't enforce the contract of being in cooperative mode the whole point
970 // is that clients of this fellow want to return a robust error if not cooperative
971 // so technically they are mode_any although the only true preemptive support they offer
972 // is graceful failure in that case
973 if (!pThread->PreemptiveGCDisabled())
975 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
981 //---------------------------------------------------------------------------------------
983 // helper functions for the GC events
987 #endif // PROFILING_SUPPORTED
989 #if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
991 //---------------------------------------------------------------------------------------
993 // It's generally unsafe for profiling API code to call Get(GCSafe)TypeHandle() on
994 // objects, since we can encounter objects on the heap whose types belong to unloading
995 // AppDomains. In such cases, getting the type handle of the object could AV. Use this
996 // function instead, which will return NULL for potentially unloaded types.
999 // pObj - Object * whose ClassID is desired
1002 // ClassID of the object, if it's safe to look it up. Else NULL.
1005 ClassID SafeGetClassIDFromObject(Object * pObj)
1014 TypeHandle th = pObj->GetGCSafeTypeHandleIfPossible();
1020 return TypeHandleToClassID(th);
1023 //---------------------------------------------------------------------------------------
1025 // Callback of type walk_fn used by GCHeapUtilities::DiagWalkObject. Keeps a count of each
1026 // object reference found.
1029 // pBO - Object reference encountered in walk
1030 // context - running count of object references encountered
1033 // Always returns TRUE to object walker so it walks the entire object
1036 BOOL CountContainedObjectRef(Object * pBO, void * context)
1038 LIMITED_METHOD_CONTRACT;
1039 // Increase the count
1040 (*((size_t *)context))++;
1045 //---------------------------------------------------------------------------------------
1047 // Callback of type walk_fn used by GCHeapUtilities::DiagWalkObject. Stores each object reference
1048 // encountered into an array.
1051 // pBO - Object reference encountered in walk
1052 // context - Array of locations within the walked object that point to other
1053 // objects. On entry, (*context) points to the next unfilled array
1054 // entry. On exit, that location is filled, and (*context) is incremented
1055 // to point to the next entry.
1058 // Always returns TRUE to object walker so it walks the entire object
1061 BOOL SaveContainedObjectRef(Object * pBO, void * context)
1063 LIMITED_METHOD_CONTRACT;
1065 **((Object ***)context) = pBO;
1067 // Now increment the array pointer
1069 // Note that HeapWalkHelper has already walked the references once to count them up,
1070 // and then allocated an array big enough to hold those references. First time this
1071 // callback is called for a given object, (*context) points to the first entry in the
1072 // array. So "blindly" incrementing (*context) here and using it next time around
1073 // for the next reference, over and over again, should be safe.
1074 (*((Object ***)context))++;
1079 //---------------------------------------------------------------------------------------
1081 // Callback of type walk_fn used by the GC when walking the heap, to help profapi and ETW
1082 // track objects. This guy orchestrates the use of the above callbacks which dig
1083 // into object references contained each object encountered by this callback.
1084 // This method is defined when either GC_PROFILING is defined or FEATURE_EVENT_TRACING
1085 // is defined and can operate fully when only one of the two is defined.
1088 // pBO - Object reference encountered on the heap
1089 // pvContext - Pointer to ProfilerWalkHeapContext, containing ETW context built up
1090 // during this GC, and which remembers if profapi-profiler is supposed to be called.
1093 // BOOL indicating whether the heap walk should continue.
1097 extern bool s_forcedGCInProgress;
1099 BOOL HeapWalkHelper(Object * pBO, void * pvContext)
1110 OBJECTREF * arrObjRef = NULL;
1111 size_t cNumRefs = 0;
1112 bool bOnStack = false;
1113 MethodTable * pMT = pBO->GetMethodTable();
1115 ProfilerWalkHeapContext * pProfilerWalkHeapContext = (ProfilerWalkHeapContext *) pvContext;
1117 if (pMT->ContainsPointersOrCollectible())
1119 // First round through calculates the number of object refs for this class
1120 GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &CountContainedObjectRef, (void *)&cNumRefs);
1124 // Create an array to contain all of the refs for this object
1125 bOnStack = cNumRefs <= 32 ? true : false;
1129 // It's small enough, so just allocate on the stack
1130 arrObjRef = (OBJECTREF *)_alloca(cNumRefs * sizeof(OBJECTREF));
1134 // Otherwise, allocate from the heap
1135 arrObjRef = new (nothrow) OBJECTREF[cNumRefs];
1143 // Second round saves off all of the ref values
1144 OBJECTREF * pCurObjRef = arrObjRef;
1145 GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &SaveContainedObjectRef, (void *)&pCurObjRef);
1149 HRESULT hr = E_FAIL;
1151 #if defined(GC_PROFILING)
1152 if (pProfilerWalkHeapContext->fProfilerPinned)
1154 // It is not safe and could be overflowed to downcast size_t to ULONG on WIN64.
1155 // However, we have to do this dangerous downcast here to comply with the existing Profiling COM interface.
1156 // We are currently evaluating ways to fix this potential overflow issue.
1157 hr = g_profControlBlock.pProfInterface->ObjectReference(
1159 SafeGetClassIDFromObject(pBO),
1161 (ObjectID *) arrObjRef);
1165 #ifdef FEATURE_EVENT_TRACE
1166 if (s_forcedGCInProgress &&
1167 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
1168 TRACE_LEVEL_INFORMATION,
1169 CLR_GCHEAPDUMP_KEYWORD))
1171 ETW::GCLog::ObjectReference(
1172 pProfilerWalkHeapContext,
1174 (ULONGLONG) SafeGetClassIDFromObject(pBO),
1176 (Object **) arrObjRef);
1179 #endif // FEATURE_EVENT_TRACE
1181 // If the data was not allocated on the stack, need to clean it up.
1182 if ((arrObjRef != NULL) && !bOnStack)
1184 delete [] arrObjRef;
1187 // Return TRUE iff we want to the heap walk to continue. The only way we'd abort the
1188 // heap walk is if we're issuing profapi callbacks, and the profapi profiler
1189 // intentionally returned a failed HR (as its request that we stop the walk). There's
1190 // a potential conflict here. If a profapi profiler and an ETW profiler are both
1191 // monitoring the heap dump, and the profapi profiler requests to abort the walk (but
1192 // the ETW profiler may not want to abort the walk), then what do we do? The profapi
1193 // profiler gets precedence. We don't want to accidentally send more callbacks to a
1194 // profapi profiler that explicitly requested an abort. The ETW profiler will just
1195 // have to deal. In theory, I could make the code more complex by remembering that a
1196 // profapi profiler requested to abort the dump but an ETW profiler is still
1197 // attached, and then intentionally inhibit the remainder of the profapi callbacks
1198 // for this GC. But that's unnecessary complexity. In practice, it should be
1199 // extremely rare that a profapi profiler is monitoring heap dumps AND an ETW
1200 // profiler is also monitoring heap dumps.
1201 return (pProfilerWalkHeapContext->fProfilerPinned) ? SUCCEEDED(hr) : TRUE;
1204 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACING)
1206 #ifdef PROFILING_SUPPORTED
1207 //---------------------------------------------------------------------------------------
1209 // Callback of type walk_fn used by the GC when walking the heap, to help profapi
1210 // track objects. This is really just a wrapper around
1211 // EEToProfInterfaceImpl::AllocByClass, which does the real work
1214 // pBO - Object reference encountered on the heap
1215 // pv - Structure used by EEToProfInterfaceImpl::AllocByClass to do its work.
1218 // BOOL indicating whether the heap walk should continue.
1221 // Currently always returns TRUE
1224 BOOL AllocByClassHelper(Object * pBO, void * pv)
1233 _ASSERTE(pv != NULL);
1236 BEGIN_PIN_PROFILER(CORProfilerPresent());
1237 // Pass along the call
1238 g_profControlBlock.pProfInterface->AllocByClass(
1240 SafeGetClassIDFromObject(pBO),
1248 #endif // PROFILING_SUPPORTED
1249 #if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1251 //---------------------------------------------------------------------------------------
1253 // Callback of type promote_func called by GC while scanning roots (in GCProfileWalkHeap,
1254 // called after the collection). Wrapper around EEToProfInterfaceImpl::RootReference2,
1255 // which does the real work.
1258 // pObj - Object reference encountered
1259 /// ppRoot - Address that references ppObject (can be interior pointer)
1260 // pSC - ProfilingScanContext * containing the root kind and GCReferencesData used
1261 // by RootReference2
1262 // dwFlags - Properties of the root as GC_CALL* constants (this function converts
1263 // to COR_PRF_GC_ROOT_FLAGS.
1266 void ScanRootsHelper(Object* pObj, Object ** ppRoot, ScanContext *pSC, uint32_t dwFlags)
1277 // RootReference2 can return E_OUTOFMEMORY, and we're swallowing that.
1278 // Furthermore, we can't really handle it because we're callable during GC promotion.
1279 // On the other hand, this only means profiling information will be incomplete,
1280 // so it's ok to swallow E_OUTOFMEMORY.
1284 ProfilingScanContext *pPSC = (ProfilingScanContext *)pSC;
1286 DWORD dwEtwRootFlags = 0;
1287 if (dwFlags & GC_CALL_INTERIOR)
1288 dwEtwRootFlags |= kEtwGCRootFlagsInterior;
1289 if (dwFlags & GC_CALL_PINNED)
1290 dwEtwRootFlags |= kEtwGCRootFlagsPinning;
1292 #if defined(GC_PROFILING)
1293 void *rootID = NULL;
1294 switch (pPSC->dwEtwRootKind)
1296 case kEtwGCRootKindStack:
1300 case kEtwGCRootKindHandle:
1301 _ASSERT(!"Shouldn't see handle here");
1303 case kEtwGCRootKindFinalizer:
1308 // Notify profiling API of the root
1309 if (pPSC->fProfilerPinned)
1311 // Let the profiling code know about this root reference
1312 g_profControlBlock.pProfInterface->
1313 RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId));
1317 #ifdef FEATURE_EVENT_TRACE
1318 // Notify ETW of the root
1319 if (s_forcedGCInProgress &&
1320 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
1321 TRACE_LEVEL_INFORMATION,
1322 CLR_GCHEAPDUMP_KEYWORD))
1324 ETW::GCLog::RootReference(
1325 NULL, // handle is NULL, cuz this is a non-HANDLE root
1326 pObj, // object being rooted
1327 NULL, // pSecondaryNodeForDependentHandle is NULL, cuz this isn't a dependent handle
1328 FALSE, // is dependent handle
1330 dwFlags, // dwGCFlags
1333 #endif // FEATURE_EVENT_TRACE
1336 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1337 #ifdef PROFILING_SUPPORTED
1339 //---------------------------------------------------------------------------------------
1341 // Private ProfToEEInterfaceImpl maintenance functions
1345 //---------------------------------------------------------------------------------------
1347 // Initialize ProfToEEInterfaceImpl (including ModuleILHeap statics)
1350 // HRESULT indicating success
1353 HRESULT ProfToEEInterfaceImpl::Init()
1364 LOG((LF_CORPROF, LL_INFO1000, "**PROF: Init.\n"));
1367 if (ProfilingAPIUtility::ShouldInjectProfAPIFault(kProfAPIFault_StartupInternal))
1369 return E_OUTOFMEMORY;
1377 //---------------------------------------------------------------------------------------
1379 // Destroy ProfToEEInterfaceImpl (including ModuleILHeap statics)
1382 ProfToEEInterfaceImpl::~ProfToEEInterfaceImpl()
1392 LOG((LF_CORPROF, LL_INFO1000, "**PROF: Terminate.\n"));
1395 //---------------------------------------------------------------------------------------
1397 // Obsolete info functions
1400 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionInterface(IUnknown **)
1402 LIMITED_METHOD_CONTRACT;
1406 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionIThisThread(IUnknown **)
1408 LIMITED_METHOD_CONTRACT;
1412 HRESULT ProfToEEInterfaceImpl::BeginInprocDebugging(BOOL, DWORD *)
1414 LIMITED_METHOD_CONTRACT;
1418 HRESULT ProfToEEInterfaceImpl::EndInprocDebugging(DWORD)
1420 LIMITED_METHOD_CONTRACT;
1424 HRESULT ProfToEEInterfaceImpl::SetFunctionReJIT(FunctionID)
1426 LIMITED_METHOD_CONTRACT;
1433 //---------------------------------------------------------------------------------------
1435 // *******************************
1436 // Public Profiler->EE entrypoints
1437 // *******************************
1439 // ProfToEEInterfaceImpl implementation of public ICorProfilerInfo* methods
1441 // NOTE: All ICorProfilerInfo* method implementations must follow the rules stated
1442 // at the top of this file!
1445 // See corprof.idl / MSDN for detailed comments about each of these public
1446 // functions, their parameters, return values, etc.
1448 HRESULT ProfToEEInterfaceImpl::SetEventMask(DWORD dwEventMask)
1462 EE_THREAD_NOT_REQUIRED;
1470 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1473 "**PROF: SetEventMask 0x%08x.\n",
1476 _ASSERTE(CORProfilerPresentOrInitializing());
1478 return g_profControlBlock.pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */);
1481 HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHigh)
1495 EE_THREAD_NOT_REQUIRED;
1503 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1506 "**PROF: SetEventMask2 0x%08x, 0x%08x.\n",
1507 dwEventsLow, dwEventsHigh));
1509 _ASSERTE(CORProfilerPresentOrInitializing());
1511 return g_profControlBlock.pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh);
1515 HRESULT ProfToEEInterfaceImpl::GetHandleFromThread(ThreadID threadId, HANDLE *phThread)
1529 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;
1585 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1588 "**PROF: GetObjectSize 0x%p.\n",
1591 if (objectId == NULL)
1593 return E_INVALIDARG;
1596 HRESULT hr = AllowObjectInspection();
1602 // Get the object pointer
1603 Object *pObj = reinterpret_cast<Object *>(objectId);
1608 SIZE_T size = pObj->GetSize();
1610 if(size < MIN_OBJECT_SIZE)
1612 size = PtrAlign(size);
1615 if (size > ULONG_MAX)
1617 *pcSize = ULONG_MAX;
1618 return COR_E_OVERFLOW;
1620 *pcSize = (ULONG)size;
1627 HRESULT ProfToEEInterfaceImpl::GetObjectSize2(ObjectID objectId, SIZE_T *pcSize)
1637 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
1641 EE_THREAD_NOT_REQUIRED;
1650 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1653 "**PROF: GetObjectSize2 0x%p.\n",
1656 if (objectId == NULL)
1658 return E_INVALIDARG;
1661 HRESULT hr = AllowObjectInspection();
1667 // Get the object pointer
1668 Object *pObj = reinterpret_cast<Object *>(objectId);
1673 SIZE_T size = pObj->GetSize();
1675 if(size < MIN_OBJECT_SIZE)
1677 size = PtrAlign(size);
1688 HRESULT ProfToEEInterfaceImpl::IsArrayClass(
1689 /* [in] */ ClassID classId,
1690 /* [out] */ CorElementType *pBaseElemType,
1691 /* [out] */ ClassID *pBaseClassId,
1692 /* [out] */ ULONG *pcRank)
1704 EE_THREAD_NOT_REQUIRED;
1713 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1716 "**PROF: IsArrayClass 0x%p.\n",
1721 if (classId == NULL)
1723 return E_INVALIDARG;
1726 TypeHandle th = TypeHandle::FromPtr((void *)classId);
1728 ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(th);
1730 // If this is indeed an array class, get some info about it
1735 _ASSERTE(!"Unexpected return from ArrayKindFromTypeHandle()");
1740 case ARRAY_KIND_TYPEDESC:
1742 // This is actually an array, so cast it up
1743 ArrayTypeDesc *pArr = th.AsArray();
1745 // Fill in the type if they want it
1746 if (pBaseElemType != NULL)
1748 *pBaseElemType = pArr->GetArrayElementTypeHandle().GetVerifierCorElementType();
1751 // If this is an array of classes and they wish to have the base type
1752 // If there is no associated class with this type, then there's no problem
1753 // because GetClass returns NULL which is the default we want to return in
1755 // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
1756 if (pBaseClassId != NULL)
1758 *pBaseClassId = TypeHandleToClassID(pArr->GetTypeParam());
1761 // If they want the number of dimensions of the array
1764 *pcRank = (ULONG) pArr->GetRank();
1767 // S_OK indicates that this was indeed an array
1771 case ARRAY_KIND_METHODTABLE:
1773 MethodTable *pArrMT = th.GetMethodTable();
1775 // Fill in the type if they want it
1776 if (pBaseElemType != NULL)
1778 *pBaseElemType = pArrMT->GetArrayElementType();
1781 // If this is an array of classes and they wish to have the base type.
1782 if (pBaseClassId != NULL)
1784 *pBaseClassId = TypeHandleToClassID(pArrMT->GetApproxArrayElementTypeHandle());
1787 // If they want the number of dimensions of the array
1790 *pcRank = (ULONG) pArrMT->GetRank();
1793 // S_OK indicates that this was indeed an array
1797 case ARRAY_KIND_NOTARRAY:
1799 if (pBaseClassId != NULL)
1801 *pBaseClassId = NULL;
1804 // This is not an array, S_FALSE indicates so.
1813 HRESULT ProfToEEInterfaceImpl::GetThreadInfo(ThreadID threadId, DWORD *pdwWin32ThreadId)
1827 EE_THREAD_NOT_REQUIRED;
1836 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1839 "**PROF: GetThreadInfo 0x%p.\n",
1842 if (!IsManagedThread(threadId))
1844 return E_INVALIDARG;
1847 if (pdwWin32ThreadId)
1849 *pdwWin32ThreadId = ((Thread *)threadId)->GetOSThreadId();
1855 HRESULT ProfToEEInterfaceImpl::GetCurrentThreadID(ThreadID *pThreadId)
1869 EE_THREAD_NOT_REQUIRED;
1878 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1881 "**PROF: GetCurrentThreadID.\n"));
1885 // No longer assert that GetThread doesn't return NULL, since callbacks
1886 // can now occur on non-managed threads (such as the GC helper threads)
1887 Thread * pThread = GetThreadNULLOk();
1889 // If pThread is null, then the thread has never run managed code and
1890 // so has no ThreadID
1891 if (!IsManagedThread(pThread))
1892 hr = CORPROF_E_NOT_MANAGED_THREAD;
1894 // Only provide value if they want it
1896 *pThreadId = (ThreadID) pThread;
1901 //---------------------------------------------------------------------------------------
1903 // Internal helper function to wrap a call into the JIT manager to get information about
1904 // a managed function based on IP
1907 // ip - IP address inside managed function of interest
1908 // ppCodeInfo - [out] information about the managed function based on IP
1911 // HRESULT indicating success or failure.
1915 HRESULT GetFunctionInfoInternal(LPCBYTE ip, EECodeInfo * pCodeInfo)
1922 EE_THREAD_NOT_REQUIRED;
1928 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
1929 // host (SQL). Corners will be cut to ensure this is the case
1930 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
1934 // Before calling into the code manager, ensure the GC heap has been
1935 // initialized--else the code manager will assert trying to get info from the heap.
1936 if (!IsGarbageCollectorFullyInitialized())
1938 return CORPROF_E_NOT_YET_AVAILABLE;
1941 if (ShouldAvoidHostCalls())
1943 ExecutionManager::ReaderLockHolder rlh(NoHostCalls);
1944 if (!rlh.Acquired())
1946 // Couldn't get the info. Try again later
1947 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
1950 pCodeInfo->Init((PCODE)ip, ExecutionManager::ScanNoReaderLock);
1954 pCodeInfo->Init((PCODE)ip);
1957 if (!pCodeInfo->IsValid())
1966 HRESULT GetFunctionFromIPInternal(LPCBYTE ip, EECodeInfo * pCodeInfo, BOOL failOnNoMetadata)
1973 EE_THREAD_NOT_REQUIRED;
1979 _ASSERTE (pCodeInfo != NULL);
1981 HRESULT hr = GetFunctionInfoInternal(ip, pCodeInfo);
1987 if (failOnNoMetadata)
1989 // never return a method that the user of the profiler API cannot use
1990 if (pCodeInfo->GetMethodDesc()->IsNoMetadata())
2000 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP(LPCBYTE ip, FunctionID * pFunctionId)
2014 EE_THREAD_NOT_REQUIRED;
2016 // Querying the code manager requires a reader lock. However, see
2017 // code:#DisableLockOnAsyncCalls
2018 DISABLED(CAN_TAKE_LOCK);
2020 // Asynchronous functions can be called at arbitrary times when runtime
2021 // is holding locks that cannot be reentered without causing deadlock.
2022 // This contract detects any attempts to reenter locks held at the time
2023 // this function was called.
2028 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2029 // host (SQL). Corners will be cut to ensure this is the case
2030 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2034 // See code:#DisableLockOnAsyncCalls
2035 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2037 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2040 "**PROF: GetFunctionFromIP 0x%p.\n",
2043 // This call is allowed asynchronously, but the JIT functions take a reader lock.
2044 // So we need to ensure the current thread hasn't been hijacked by a profiler while
2045 // it was holding the writer lock. Checking the ForbidSuspendThread region is a
2046 // sufficient test for this
2047 FAIL_IF_IN_FORBID_SUSPEND_REGION();
2051 EECodeInfo codeInfo;
2053 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2061 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2068 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP2(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
2075 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2076 // which can switch us to preemptive mode and trigger GCs
2083 EE_THREAD_NOT_REQUIRED;
2085 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2092 // See code:#DisableLockOnAsyncCalls
2093 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2095 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2096 kP2EEAllowableAfterAttach | kP2EETriggers,
2099 "**PROF: GetFunctionFromIP2 0x%p.\n",
2104 EECodeInfo codeInfo;
2106 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2114 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2117 if (pReJitId != NULL)
2119 MethodDesc * pMD = codeInfo.GetMethodDesc();
2120 *pReJitId = pMD->GetReJitManager()->GetReJitId(pMD, codeInfo.GetStartAddress());
2126 //*****************************************************************************
2127 // Given a function id, retrieve the metadata token and a reader api that
2128 // can be used against the token.
2129 //*****************************************************************************
2130 HRESULT ProfToEEInterfaceImpl::GetTokenAndMetaDataFromFunction(
2131 FunctionID functionId,
2148 EE_THREAD_NOT_REQUIRED;
2150 // PEFile::GetRWImporter and GetReadablePublicMetaDataInterface take locks
2157 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2160 "**PROF: GetTokenAndMetaDataFromFunction 0x%p.\n",
2163 if (functionId == NULL)
2165 return E_INVALIDARG;
2170 MethodDesc *pMD = FunctionIdToMethodDesc(functionId);
2172 // it's not safe to examine a methoddesc that has not been restored so do not do so
2173 if (!pMD->IsRestored())
2174 return CORPROF_E_DATAINCOMPLETE;
2178 *pToken = pMD->GetMemberDef();
2181 // don't bother with any of this module fetching if the metadata access isn't requested
2184 Module * pMod = pMD->GetModule();
2185 hr = pMod->GetReadablePublicMetaDataInterface(ofRead, riid, (LPVOID *) ppOut);
2191 //---------------------------------------------------------------------------------------
2192 // What follows are the GetCodeInfo* APIs and their helpers. The two helpers factor out
2193 // some of the common code to validate parameters and then determine the code info from
2194 // the start of the code. Each individual GetCodeInfo* API differs in how it uses these
2195 // helpers, particuarly in how it determines the start of the code (GetCodeInfo3 needs
2196 // to use the rejit manager to determine the code start, whereas the others do not).
2197 // Factoring out like this allows us to have statically determined contracts that differ
2198 // based on whether we need to use the rejit manager, which requires locking and
2200 //---------------------------------------------------------------------------------------
2203 HRESULT ValidateParametersForGetCodeInfo(
2204 MethodDesc * pMethodDesc,
2206 COR_PRF_CODE_INFO codeInfos[])
2208 LIMITED_METHOD_CONTRACT;
2210 if (pMethodDesc == NULL)
2212 return E_INVALIDARG;
2215 if ((cCodeInfos != 0) && (codeInfos == NULL))
2217 return E_INVALIDARG;
2220 // it's not safe to examine a methoddesc that has not been restored so do not do so
2221 if (!pMethodDesc->IsRestored())
2222 return CORPROF_E_DATAINCOMPLETE;
2224 if (pMethodDesc->HasClassOrMethodInstantiation() && pMethodDesc->IsTypicalMethodDefinition())
2226 // In this case, we used to replace pMethodDesc with its canonical instantiation
2227 // (FindOrCreateTypicalSharedInstantiation). However, a profiler should never be able
2228 // to get to this point anyway, since any MethodDesc a profiler gets from us
2229 // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
2230 // We assert here just in case a test proves me wrong, but generally we will
2231 // disallow this code path.
2232 _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetCodeInfo2");
2233 return E_INVALIDARG;
2239 HRESULT GetCodeInfoFromCodeStart(
2242 ULONG32 * pcCodeInfos,
2243 COR_PRF_CODE_INFO codeInfos[])
2251 // We need to take the ExecutionManager reader lock to find the
2252 // appropriate jit manager.
2257 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2258 // host (SQL). Corners will be cut to ensure this is the case
2259 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2263 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2265 ///////////////////////////////////
2266 // Get the code region info for this function. This is a multi step process.
2268 // MethodDesc ==> Code Address ==> JitMananger ==>
2269 // MethodToken ==> MethodRegionInfo
2271 // (Our caller handled the first step: MethodDesc ==> Code Address.)
2275 // On WIN64 we have a choice of where to go to find out the function address range size:
2276 // GC info (which is what we're doing below on all architectures) or the OS unwind
2277 // info, stored in the RUNTIME_FUNCTION structure. The latter produces
2278 // a SMALLER size than the former, because the latter excludes some data from
2279 // the set we report to the OS for unwind info. For example, switch tables can be
2280 // separated out from the regular code and not be reported as OS unwind info, and thus
2281 // those addresses will not appear in the range reported by the RUNTIME_FUNCTION gotten via:
2283 // IJitManager* pJitMan = ExecutionManager::FindJitMan((PBYTE)codeInfos[0].startAddress);
2284 // PRUNTIME_FUNCTION pfe = pJitMan->GetUnwindInfo((PBYTE)codeInfos[0].startAddress);
2285 // *pcCodeInfos = (ULONG) (pfe->EndAddress - pfe->BeginAddress);
2287 // (Note that GCInfo & OS unwind info report the same start address--it's the size that's
2290 // The advantage of using the GC info is that it's available on all architectures,
2291 // and it gives you a more complete picture of the addresses belonging to the function.
2293 // A disadvantage of using GC info is we'll report those extra addresses (like switch
2294 // tables) that a profiler might turn back around and use in a call to
2295 // GetFunctionFromIP. A profiler may expect we'd be able to map back any address
2296 // in the function's GetCodeInfo ranges back to that function's FunctionID (methoddesc). But
2297 // querying these extra addresses will cause GetFunctionFromIP to fail, as they're not
2298 // actually valid instruction addresses that the IP register can be set to.
2300 // The advantage wins out, so we're going with GC info everywhere.
2308 return CORPROF_E_FUNCTION_NOT_COMPILED;
2311 EECodeInfo codeInfo;
2312 hr = GetFunctionInfoInternal(
2315 if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
2317 _ASSERTE(ShouldAvoidHostCalls());
2322 return CORPROF_E_FUNCTION_NOT_COMPILED;
2325 IJitManager::MethodRegionInfo methodRegionInfo;
2326 codeInfo.GetMethodRegionInfo(&methodRegionInfo);
2329 // Fill out the codeInfo structures with valuse from the
2332 // Note that we're assuming that a method will never be split into
2333 // more than two regions ... this is unlikely to change any time in
2336 if (NULL != codeInfos)
2341 // We have to return the two regions in the order that they would appear
2342 // if straight-line compiled
2344 if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2346 codeInfos[0].startAddress =
2347 (UINT_PTR)methodRegionInfo.hotStartAddress;
2348 codeInfos[0].size = methodRegionInfo.hotSize;
2352 _ASSERTE(methodRegionInfo.coldStartAddress != NULL);
2353 codeInfos[0].startAddress =
2354 (UINT_PTR)methodRegionInfo.coldStartAddress;
2355 codeInfos[0].size = methodRegionInfo.coldSize;
2358 if (NULL != methodRegionInfo.coldStartAddress)
2362 if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2364 codeInfos[1].startAddress =
2365 (UINT_PTR)methodRegionInfo.coldStartAddress;
2366 codeInfos[1].size = methodRegionInfo.coldSize;
2370 codeInfos[1].startAddress =
2371 (UINT_PTR)methodRegionInfo.hotStartAddress;
2372 codeInfos[1].size = methodRegionInfo.hotSize;
2379 if (NULL != pcCodeInfos)
2381 *pcCodeInfos = (NULL != methodRegionInfo.coldStartAddress) ? 2 : 1;
2388 //*****************************************************************************
2389 // Gets the location and size of a jitted function
2390 //*****************************************************************************
2392 HRESULT ProfToEEInterfaceImpl::GetCodeInfo(FunctionID functionId, LPCBYTE * pStart, ULONG * pcSize)
2406 EE_THREAD_NOT_REQUIRED;
2408 // (See locking contract comment in GetCodeInfoHelper.)
2409 DISABLED(CAN_TAKE_LOCK);
2411 // (See locking contract comment in GetCodeInfoHelper.)
2416 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2417 // host (SQL). Corners will be cut to ensure this is the case
2418 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2422 // See code:#DisableLockOnAsyncCalls
2423 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2425 // This is called asynchronously, but GetCodeInfoHelper() will
2426 // ensure we're not called at a dangerous time
2427 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2430 "**PROF: GetCodeInfo 0x%p.\n",
2433 // GetCodeInfo may be called asynchronously, and the JIT functions take a reader
2434 // lock. So we need to ensure the current thread hasn't been hijacked by a profiler while
2435 // it was holding the writer lock. Checking the ForbidSuspendThread region is a sufficient test for this
2436 FAIL_IF_IN_FORBID_SUSPEND_REGION();
2438 if (functionId == 0)
2440 return E_INVALIDARG;
2443 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2445 COR_PRF_CODE_INFO codeInfos[2];
2448 HRESULT hr = GetCodeInfoFromCodeStart(
2449 pMethodDesc->GetNativeCode(),
2450 _countof(codeInfos),
2454 if ((FAILED(hr)) || (0 == cCodeInfos))
2461 *pStart = reinterpret_cast< LPCBYTE >(codeInfos[0].startAddress);
2466 if (!FitsIn<ULONG>(codeInfos[0].size))
2468 return E_UNEXPECTED;
2470 *pcSize = static_cast<ULONG>(codeInfos[0].size);
2476 HRESULT ProfToEEInterfaceImpl::GetCodeInfo2(FunctionID functionId,
2478 ULONG32 * pcCodeInfos,
2479 COR_PRF_CODE_INFO codeInfos[])
2493 EE_THREAD_NOT_REQUIRED;
2495 // (See locking contract comment in GetCodeInfoHelper.)
2496 DISABLED(CAN_TAKE_LOCK);
2498 // (See locking contract comment in GetCodeInfoHelper.)
2503 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2504 // host (SQL). Corners will be cut to ensure this is the case
2505 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2507 PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2508 PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2512 // See code:#DisableLockOnAsyncCalls
2513 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2515 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2518 "**PROF: GetCodeInfo2 0x%p.\n",
2525 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2527 hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2530 hr = GetCodeInfoFromCodeStart(
2531 pMethodDesc->GetNativeCode(),
2537 EX_CATCH_HRESULT(hr);
2543 HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId,
2546 ULONG32* pcCodeInfos,
2547 COR_PRF_CODE_INFO codeInfos[])
2556 // We need to access the rejitmanager, which means taking locks, which means we
2564 EE_THREAD_NOT_REQUIRED;
2566 // We need to access the rejitmanager, which means taking locks
2571 PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2572 PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2576 // See code:#DisableLockOnAsyncCalls
2577 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2579 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2580 kP2EEAllowableAfterAttach | kP2EETriggers,
2583 "**PROF: GetCodeInfo3 0x%p 0x%p.\n",
2584 functionId, reJitId));
2590 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2592 hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2595 hr = GetCodeInfoFromCodeStart(
2596 // Note here that we must consult the rejit manager to determine the code
2598 pMethodDesc->GetReJitManager()->GetCodeStart(pMethodDesc, reJitId),
2604 EX_CATCH_HRESULT(hr);
2610 HRESULT ProfToEEInterfaceImpl::GetEventMask(DWORD * pdwEvents)
2624 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;
2672 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2675 "**PROF: GetEventMask2.\n"));
2677 if ((pdwEventsLow == NULL) || (pdwEventsHigh == NULL))
2679 return E_INVALIDARG;
2682 *pdwEventsLow = g_profControlBlock.dwEventMask;
2683 *pdwEventsHigh = g_profControlBlock.dwEventMaskHigh;
2688 void ProfToEEInterfaceImpl::MethodTableCallback(void* context, void* objectUNSAFE)
2699 // each callback identifies the address of a method table within the frozen object segment
2700 // that pointer is an object ID by definition -- object references point to the method table
2701 CDynArray< ObjectID >* objects = reinterpret_cast< CDynArray< ObjectID >* >(context);
2703 *objects->Append() = reinterpret_cast< ObjectID >(objectUNSAFE);
2707 void ProfToEEInterfaceImpl::ObjectRefCallback(void* context, void* objectUNSAFE)
2709 // we don't care about embedded object references, ignore them
2713 HRESULT ProfToEEInterfaceImpl::EnumModuleFrozenObjects(ModuleID moduleID,
2714 ICorProfilerObjectEnum** ppEnum)
2728 EE_THREAD_NOT_REQUIRED;
2737 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2740 "**PROF: EnumModuleFrozenObjects 0x%p.\n",
2745 return E_INVALIDARG;
2748 Module* pModule = reinterpret_cast< Module* >(moduleID);
2749 if (pModule == NULL || pModule->IsBeingUnloaded())
2751 return CORPROF_E_DATAINCOMPLETE;
2758 // If we don't support frozen objects at all, then just return empty
2760 *ppEnum = new ProfilerObjectEnum();
2762 EX_CATCH_HRESULT(hr);
2770 * GetArrayObjectInfo
2772 * This function returns informatin about array objects. In particular, the dimensions
2773 * and where the data buffer is stored.
2776 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfo(ObjectID objectId,
2777 ULONG32 cDimensionSizes,
2778 ULONG32 pDimensionSizes[],
2779 int pDimensionLowerBounds[],
2790 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
2800 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2803 "**PROF: GetArrayObjectInfo 0x%p.\n",
2806 if (objectId == NULL)
2808 return E_INVALIDARG;
2811 if ((pDimensionSizes == NULL) ||
2812 (pDimensionLowerBounds == NULL) ||
2815 return E_INVALIDARG;
2818 HRESULT hr = AllowObjectInspection();
2824 Object * pObj = reinterpret_cast<Object *>(objectId);
2826 // GC callbacks may come from a non-EE thread, which is considered permanently preemptive.
2827 // We are about calling some object inspection functions, which require to be in co-op mode.
2828 // Given that none managed objects can be changed by managed code until GC resumes the
2829 // runtime, it is safe to violate the mode contract and to inspect managed objects from a
2830 // non-EE thread when GetArrayObjectInfo is called within GC callbacks.
2831 if (NativeThreadInGC())
2833 CONTRACT_VIOLATION(ModeViolation);
2834 return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2837 return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2840 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfoHelper(Object * pObj,
2841 ULONG32 cDimensionSizes,
2842 __out_ecount(cDimensionSizes) ULONG32 pDimensionSizes[],
2843 __out_ecount(cDimensionSizes) int pDimensionLowerBounds[],
2854 // Because of the object pointer parameter, we must be either in CO-OP mode,
2855 // or on a non-EE thread in the process of doing a GC .
2856 if (!NativeThreadInGC()) { MODE_COOPERATIVE; }
2865 // Must have an array.
2866 MethodTable * pMT = pObj->GetTrueMethodTable();
2867 if (!pMT->IsArray())
2869 return E_INVALIDARG;
2872 ArrayBase * pArray = static_cast<ArrayBase*> (pObj);
2874 unsigned rank = pArray->GetRank();
2876 if (cDimensionSizes < rank)
2878 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2881 // Copy range for each dimension (rank)
2882 int * pBounds = pArray->GetBoundsPtr();
2883 int * pLowerBounds = pArray->GetLowerBoundsPtr();
2886 for(i = 0; i < rank; i++)
2888 pDimensionSizes[i] = pBounds[i];
2889 pDimensionLowerBounds[i] = pLowerBounds[i];
2893 *ppData = pArray->GetDataPtr();
2901 * Returns information about how a particular value type is laid out.
2904 HRESULT ProfToEEInterfaceImpl::GetBoxClassLayout(ClassID classId,
2905 ULONG32 *pBufferOffset)
2919 EE_THREAD_NOT_REQUIRED;
2928 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2931 "**PROF: GetBoxClassLayout 0x%p.\n",
2934 if (pBufferOffset == NULL)
2936 return E_INVALIDARG;
2939 if (classId == NULL)
2941 return E_INVALIDARG;
2944 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
2947 // This is the incorrect API for arrays. Use GetArrayInfo and GetArrayLayout.
2949 if (!typeHandle.IsValueType())
2951 return E_INVALIDARG;
2954 *pBufferOffset = Object::GetOffsetOfFirstField();
2960 * GetThreadAppDomain
2962 * Returns the app domain currently associated with the given thread.
2965 HRESULT ProfToEEInterfaceImpl::GetThreadAppDomain(ThreadID threadId,
2966 AppDomainID *pAppDomainId)
2981 EE_THREAD_NOT_REQUIRED;
2990 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2993 "**PROF: GetThreadAppDomain 0x%p.\n",
2996 if (pAppDomainId == NULL)
2998 return E_INVALIDARG;
3003 if (threadId == NULL)
3005 pThread = GetThreadNULLOk();
3009 pThread = (Thread *)threadId;
3013 // If pThread is null, then the thread has never run managed code and
3014 // so has no ThreadID.
3016 if (!IsManagedThread(pThread))
3018 return CORPROF_E_NOT_MANAGED_THREAD;
3021 *pAppDomainId = (AppDomainID)pThread->GetDomain();
3028 * GetRVAStaticAddress
3030 * This function returns the absolute address of the given field in the given
3031 * class. The field must be an RVA Static token.
3034 * classId - the containing class.
3035 * fieldToken - the field we are querying.
3036 * pAddress - location for storing the resulting address location.
3040 * E_INVALIDARG if not an RVA static,
3041 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3044 HRESULT ProfToEEInterfaceImpl::GetRVAStaticAddress(ClassID classId,
3045 mdFieldDef fieldToken,
3059 // FieldDesc::GetStaticAddress takes a lock
3066 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3069 "**PROF: GetRVAStaticAddress 0x%p, 0x%08x.\n",
3074 // Check for NULL parameters
3076 if ((classId == NULL) || (ppAddress == NULL))
3078 return E_INVALIDARG;
3081 if (GetThread() == NULL)
3083 return CORPROF_E_NOT_MANAGED_THREAD;
3086 if (GetAppDomain() == NULL)
3091 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3094 // If this class is not fully restored, that is all the information we can get at this time.
3096 if (!typeHandle.IsRestored())
3098 return CORPROF_E_DATAINCOMPLETE;
3102 // Get the field descriptor object
3104 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3106 if (pFieldDesc == NULL)
3108 return E_INVALIDARG;
3112 // Verify this field is of the right type
3114 if(!pFieldDesc->IsStatic() ||
3115 !pFieldDesc->IsRVA() ||
3116 pFieldDesc->IsThreadStatic() ||
3117 pFieldDesc->IsContextStatic())
3119 return E_INVALIDARG;
3122 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3123 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3124 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3127 // Check that the data is available
3129 if (!IsClassOfMethodTableInited(pMethodTable, GetAppDomain()))
3131 return CORPROF_E_DATAINCOMPLETE;
3135 // Store the result and return
3137 PTR_VOID pAddress = pFieldDesc->GetStaticAddress(NULL);
3138 if (pAddress == NULL)
3140 return CORPROF_E_DATAINCOMPLETE;
3143 *ppAddress = pAddress;
3150 * GetAppDomainStaticAddress
3152 * This function returns the absolute address of the given field in the given
3153 * class in the given app domain. The field must be an App Domain Static token.
3156 * classId - the containing class.
3157 * fieldToken - the field we are querying.
3158 * appDomainId - the app domain container.
3159 * pAddress - location for storing the resulting address location.
3163 * E_INVALIDARG if not an app domain static,
3164 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3167 HRESULT ProfToEEInterfaceImpl::GetAppDomainStaticAddress(ClassID classId,
3168 mdFieldDef fieldToken,
3169 AppDomainID appDomainId,
3184 EE_THREAD_NOT_REQUIRED;
3186 // FieldDesc::GetStaticAddress & FieldDesc::GetBaseInDomain take locks
3193 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3196 "**PROF: GetAppDomainStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3202 // Check for NULL parameters
3204 if ((classId == NULL) || (appDomainId == NULL) || (ppAddress == NULL))
3206 return E_INVALIDARG;
3209 // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3210 // statics. See if the profiler is trying to be naughty.
3211 if (!((BaseDomain*) appDomainId)->IsAppDomain())
3213 return E_INVALIDARG;
3216 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3219 // If this class is not fully restored, that is all the information we can get at this time.
3221 if (!typeHandle.IsRestored())
3223 return CORPROF_E_DATAINCOMPLETE;
3227 // Get the field descriptor object
3229 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3231 if (pFieldDesc == NULL)
3234 // Give specific error code for literals.
3237 if (FAILED(typeHandle.GetModule()->GetMDImport()->GetFieldDefProps(fieldToken, &dwFieldAttrs)))
3239 return E_INVALIDARG;
3242 if (IsFdLiteral(dwFieldAttrs))
3244 return CORPROF_E_LITERALS_HAVE_NO_ADDRESS;
3247 return E_INVALIDARG;
3251 // Verify this field is of the right type
3253 if(!pFieldDesc->IsStatic() ||
3254 pFieldDesc->IsRVA() ||
3255 pFieldDesc->IsThreadStatic() ||
3256 pFieldDesc->IsContextStatic())
3258 return E_INVALIDARG;
3261 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3262 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3263 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3264 AppDomain * pAppDomain = (AppDomain *)appDomainId;
3267 // Check that the data is available
3269 if (!IsClassOfMethodTableInited(pMethodTable, pAppDomain))
3271 return CORPROF_E_DATAINCOMPLETE;
3277 void *base = (void*)pFieldDesc->GetBaseInDomain(pAppDomain);
3281 return CORPROF_E_DATAINCOMPLETE;
3285 // Store the result and return
3287 PTR_VOID pAddress = pFieldDesc->GetStaticAddress(base);
3288 if (pAddress == NULL)
3290 return E_INVALIDARG;
3293 *ppAddress = pAddress;
3299 * GetThreadStaticAddress
3301 * This function returns the absolute address of the given field in the given
3302 * class on the given thread. The field must be an Thread Static token. threadId
3303 * must be the current thread ID or NULL, which means using curernt thread ID.
3306 * classId - the containing class.
3307 * fieldToken - the field we are querying.
3308 * threadId - the thread container, which has to be the current managed thread or
3309 * NULL, which means to use the current managed thread.
3310 * pAddress - location for storing the resulting address location.
3314 * E_INVALIDARG if not a thread static,
3315 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3318 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress(ClassID classId,
3319 mdFieldDef fieldToken,
3341 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3344 "**PROF: GetThreadStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3350 // Verify the value of threadId, which must be the current thread ID or NULL, which means using curernt thread ID.
3352 if ((threadId != NULL) && (threadId != ((ThreadID)GetThread())))
3354 return E_INVALIDARG;
3357 threadId = reinterpret_cast<ThreadID>(GetThread());
3358 AppDomainID appDomainId = reinterpret_cast<AppDomainID>(GetAppDomain());
3361 // Check for NULL parameters
3363 if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3365 return E_INVALIDARG;
3368 return GetThreadStaticAddress2(classId,
3376 * GetThreadStaticAddress2
3378 * This function returns the absolute address of the given field in the given
3379 * class on the given thread. The field must be an Thread Static token.
3382 * classId - the containing class.
3383 * fieldToken - the field we are querying.
3384 * appDomainId - the AppDomain container.
3385 * threadId - the thread container.
3386 * pAddress - location for storing the resulting address location.
3390 * E_INVALIDARG if not a thread static,
3391 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3394 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress2(ClassID classId,
3395 mdFieldDef fieldToken,
3396 AppDomainID appDomainId,
3418 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3421 "**PROF: GetThreadStaticAddress2 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3428 if (threadId == NULL)
3430 if (GetThread() == NULL)
3432 return CORPROF_E_NOT_MANAGED_THREAD;
3435 threadId = reinterpret_cast<ThreadID>(GetThread());
3439 // Check for NULL parameters
3441 if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3443 return E_INVALIDARG;
3446 // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3447 // statics. See if the profiler is trying to be naughty.
3448 if (!((BaseDomain*) appDomainId)->IsAppDomain())
3450 return E_INVALIDARG;
3453 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3456 // If this class is not fully restored, that is all the information we can get at this time.
3458 if (!typeHandle.IsRestored())
3460 return CORPROF_E_DATAINCOMPLETE;
3464 // Get the field descriptor object
3466 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3468 if (pFieldDesc == NULL)
3470 return E_INVALIDARG;
3474 // Verify this field is of the right type
3476 if(!pFieldDesc->IsStatic() ||
3477 !pFieldDesc->IsThreadStatic() ||
3478 pFieldDesc->IsRVA() ||
3479 pFieldDesc->IsContextStatic())
3481 return E_INVALIDARG;
3484 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3485 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3486 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3487 AppDomain * pAppDomain = (AppDomain *)appDomainId;
3490 // Check that the data is available
3492 if (!IsClassOfMethodTableInited(pMethodTable, pAppDomain))
3494 return CORPROF_E_DATAINCOMPLETE;
3498 // Store the result and return
3500 PTR_VOID pAddress = (void *)(((Thread *)threadId)->GetStaticFieldAddrNoCreate(pFieldDesc, pAppDomain));
3501 if (pAddress == NULL)
3503 return E_INVALIDARG;
3506 *ppAddress = pAddress;
3512 * GetContextStaticAddress
3514 * This function returns the absolute address of the given field in the given
3515 * class in the given context. The field must be an Context Static token.
3518 * classId - the containing class.
3519 * fieldToken - the field we are querying.
3520 * contextId - the context container.
3521 * pAddress - location for storing the resulting address location.
3525 * E_INVALIDARG if not a context static,
3526 * CORPROF_E_DATAINCOMPLETE if not yet initialized.
3529 HRESULT ProfToEEInterfaceImpl::GetContextStaticAddress(ClassID classId,
3530 mdFieldDef fieldToken,
3531 ContextID contextId,
3552 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3555 "**PROF: GetContextStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3560 #ifdef FEATURE_REMOTING
3563 // Check for NULL parameters
3565 if ((classId == NULL) || (contextId == NULL) || (ppAddress == NULL))
3567 return E_INVALIDARG;
3570 if (GetThread() == NULL)
3572 return CORPROF_E_NOT_MANAGED_THREAD;
3575 if (GetAppDomain() == NULL)
3580 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3583 // If this class is not fully restored, that is all the information we can get at this time.
3585 if (!typeHandle.IsRestored())
3587 return CORPROF_E_DATAINCOMPLETE;
3591 // Get the field descriptor object
3593 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3595 if (pFieldDesc == NULL)
3597 return E_INVALIDARG;
3601 // Verify this field is of the right type
3603 if(!pFieldDesc->IsStatic() ||
3604 !pFieldDesc->IsContextStatic() ||
3605 pFieldDesc->IsRVA() ||
3606 pFieldDesc->IsThreadStatic())
3608 return E_INVALIDARG;
3611 // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId
3612 // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3613 MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3616 // Check that the data is available
3618 if (!IsClassOfMethodTableInited(pMethodTable, GetAppDomain()))
3620 return CORPROF_E_DATAINCOMPLETE;
3626 Context *pContext = reinterpret_cast<Context *>(contextId);
3629 // Store the result and return
3631 PTR_VOID pAddress = pContext->GetStaticFieldAddrNoCreate(pFieldDesc);
3632 if (pAddress == NULL)
3634 return E_INVALIDARG;
3637 *ppAddress = pAddress;
3641 #else // FEATURE_REMOTING
3643 #endif // FEATURE_REMOTING
3647 * GetAppDomainsContainingModule
3649 * This function returns the AppDomains in which the given module has been loaded
3652 * moduleId - the module with static variables.
3653 * cAppDomainIds - the input size of appDomainIds array.
3654 * pcAppDomainIds - the output size of appDomainIds array.
3655 * appDomainIds - the array to be filled up with AppDomainIDs containing initialized
3656 * static variables from the moduleId's moudle.
3660 * E_INVALIDARG for invalid parameters,
3661 * CORPROF_E_DATAINCOMPLETE if moduleId's module is not yet initialized.
3664 HRESULT ProfToEEInterfaceImpl::GetAppDomainsContainingModule(ModuleID moduleId,
3665 ULONG32 cAppDomainIds,
3666 ULONG32 * pcAppDomainIds,
3667 AppDomainID appDomainIds[])
3674 // This method iterates over AppDomains, which adds, then releases, a reference on
3675 // each AppDomain iterated. This causes locking, and can cause triggering if the
3676 // AppDomain gets destroyed as a result of the release. (See code:AppDomainIterator::Next
3677 // and its call to code:AppDomain::Release.)
3683 // (See comment above GC_TRIGGERS.)
3690 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
3691 kP2EEAllowableAfterAttach | kP2EETriggers,
3694 "**PROF: GetAppDomainsContainingModule 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3702 // Check for NULL parameters
3704 if ((moduleId == NULL) || ((appDomainIds == NULL) && (cAppDomainIds != 0)) || (pcAppDomainIds == NULL))
3706 return E_INVALIDARG;
3709 Module* pModule = reinterpret_cast< Module* >(moduleId);
3710 if (pModule->IsBeingUnloaded())
3712 return CORPROF_E_DATAINCOMPLETE;
3715 // IterateAppDomainContainingModule uses AppDomainIterator, which cannot be called while the current thread
3716 // is holding the ThreadStore lock.
3717 if (ThreadStore::HoldingThreadStore())
3719 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
3722 IterateAppDomainContainingModule iterateAppDomainContainingModule(pModule, cAppDomainIds, pcAppDomainIds, appDomainIds);
3724 return iterateAppDomainContainingModule.PopulateArray();
3730 * GetStaticFieldInfo
3732 * This function returns a bit mask of the type of statics the
3736 * classId - the containing class.
3737 * fieldToken - the field we are querying.
3738 * pFieldInfo - location for storing the resulting bit mask.
3742 * E_INVALIDARG if pFieldInfo is NULL
3745 HRESULT ProfToEEInterfaceImpl::GetStaticFieldInfo(ClassID classId,
3746 mdFieldDef fieldToken,
3747 COR_PRF_STATIC_TYPE *pFieldInfo)
3761 EE_THREAD_NOT_REQUIRED;
3770 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3773 "**PROF: GetStaticFieldInfo 0x%p, 0x%08x.\n",
3778 // Check for NULL parameters
3780 if ((classId == NULL) || (pFieldInfo == NULL))
3782 return E_INVALIDARG;
3785 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3788 // If this class is not fully restored, that is all the information we can get at this time.
3790 if (!typeHandle.IsRestored())
3792 return CORPROF_E_DATAINCOMPLETE;
3796 // Get the field descriptor object
3798 FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3800 if (pFieldDesc == NULL)
3802 return E_INVALIDARG;
3805 *pFieldInfo = COR_PRF_FIELD_NOT_A_STATIC;
3807 if (pFieldDesc->IsContextStatic())
3809 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_CONTEXT_STATIC);
3812 if (pFieldDesc->IsRVA())
3814 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_RVA_STATIC);
3817 if (pFieldDesc->IsThreadStatic())
3819 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_THREAD_STATIC);
3822 if ((*pFieldInfo == COR_PRF_FIELD_NOT_A_STATIC) && pFieldDesc->IsStatic())
3824 *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_APP_DOMAIN_STATIC);
3835 * This function generalizes GetClassIDInfo for all types, both generic and non-generic. It returns
3836 * the module, type token, and an array of instantiation classIDs that were used to instantiate the
3840 * classId - The classId (TypeHandle) to query information about.
3841 * pParentClassId - The ClassID (TypeHandle) of the parent class.
3842 * pModuleId - An optional parameter for returning the module of the class.
3843 * pTypeDefToken - An optional parameter for returning the metadata token of the class.
3844 * cNumTypeArgs - The count of the size of the array typeArgs
3845 * pcNumTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
3846 * the number that would be needed.
3847 * typeArgs - An array to store generic type parameters for the class.
3850 * S_OK if successful.
3852 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo2(ClassID classId,
3853 ModuleID *pModuleId,
3854 mdTypeDef *pTypeDefToken,
3855 ClassID *pParentClassId,
3856 ULONG32 cNumTypeArgs,
3857 ULONG32 *pcNumTypeArgs,
3873 EE_THREAD_NOT_REQUIRED;
3880 PRECONDITION(CheckPointer(pParentClassId, NULL_OK));
3881 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
3882 PRECONDITION(CheckPointer(pTypeDefToken, NULL_OK));
3883 PRECONDITION(CheckPointer(pcNumTypeArgs, NULL_OK));
3884 PRECONDITION(CheckPointer(typeArgs, NULL_OK));
3888 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3891 "**PROF: GetClassIDInfo2 0x%p.\n",
3895 // Verify parameters.
3897 if (classId == NULL)
3899 return E_INVALIDARG;
3902 if ((cNumTypeArgs != 0) && (typeArgs == NULL))
3904 return E_INVALIDARG;
3907 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3910 // If this class is not fully restored, that is all the information we can get at this time.
3912 if (!typeHandle.IsRestored())
3914 return CORPROF_E_DATAINCOMPLETE;
3918 // Handle globals which don't have the instances.
3920 if (classId == PROFILER_GLOBAL_CLASS)
3922 if (pParentClassId != NULL)
3924 *pParentClassId = NULL;
3927 if (pModuleId != NULL)
3929 *pModuleId = PROFILER_GLOBAL_MODULE;
3932 if (pTypeDefToken != NULL)
3934 *pTypeDefToken = mdTokenNil;
3941 // Do not do arrays via this API
3943 ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(typeHandle);
3944 if (arrayKind == ARRAY_KIND_TYPEDESC || arrayKind == ARRAY_KIND_METHODTABLE)
3946 return CORPROF_E_CLASSID_IS_ARRAY;
3949 _ASSERTE (arrayKind == ARRAY_KIND_NOTARRAY);
3951 if (typeHandle.IsTypeDesc())
3953 // Not an array, but still a typedesc? We don't know how to
3955 return CORPROF_E_CLASSID_IS_COMPOSITE;
3959 // Fill in the basic information
3961 if (pParentClassId != NULL)
3963 TypeHandle parentTypeHandle = typeHandle.GetParent();
3964 if (!parentTypeHandle.IsNull())
3966 *pParentClassId = TypeHandleToClassID(parentTypeHandle);
3970 *pParentClassId = NULL;
3974 if (pModuleId != NULL)
3976 *pModuleId = (ModuleID) typeHandle.GetModule();
3977 _ASSERTE(*pModuleId != NULL);
3980 if (pTypeDefToken != NULL)
3982 *pTypeDefToken = typeHandle.GetCl();
3983 _ASSERTE(*pTypeDefToken != NULL);
3987 // See if they are just looking to get the buffer size.
3989 if (cNumTypeArgs == 0)
3991 if (pcNumTypeArgs != NULL)
3993 *pcNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3999 // Adjust the count for the size of the given array.
4001 if (cNumTypeArgs > typeHandle.GetMethodTable()->GetNumGenericArgs())
4003 cNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
4006 if (pcNumTypeArgs != NULL)
4008 *pcNumTypeArgs = cNumTypeArgs;
4012 // Copy over the instantiating types.
4015 Instantiation inst = typeHandle.GetMethodTable()->GetInstantiation();
4017 for (count = 0; count < cNumTypeArgs; count ++)
4019 typeArgs[count] = TypeHandleToClassID(inst[count]);
4025 HRESULT ProfToEEInterfaceImpl::GetModuleInfo(ModuleID moduleId,
4026 LPCBYTE * ppBaseLoadAddress,
4029 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
4030 AssemblyID * pAssemblyId)
4040 // See comment in code:ProfToEEInterfaceImpl::GetModuleInfo2
4047 EE_THREAD_NOT_REQUIRED;
4051 PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
4052 PRECONDITION(CheckPointer(ppBaseLoadAddress, NULL_OK));
4053 PRECONDITION(CheckPointer(pcchName, NULL_OK));
4054 PRECONDITION(CheckPointer(wszName, NULL_OK));
4055 PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
4059 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4062 "**PROF: GetModuleInfo 0x%p.\n",
4065 // Paramter validation is taken care of in GetModuleInfo2.
4067 return GetModuleInfo2(
4074 NULL); // Don't need module type
4077 //---------------------------------------------------------------------------------------
4079 // Helper used by GetModuleInfo2 to determine the bitmask of COR_PRF_MODULE_FLAGS for
4080 // the specified module.
4083 // pModule - Module to get the flags for
4086 // Bitmask of COR_PRF_MODULE_FLAGS corresponding to pModule
4089 DWORD ProfToEEInterfaceImpl::GetModuleFlags(Module * pModule)
4095 CAN_TAKE_LOCK; // IsWindowsRuntimeModule accesses metadata directly, which takes locks
4100 PEFile * pPEFile = pModule->GetFile();
4101 if (pPEFile == NULL)
4103 // Hopefully this should never happen; but just in case, don't try to determine the
4104 // flags without a PEFile.
4110 // First, set the flags that are dependent on which PEImage / layout we look at
4111 // inside the Module (disk/ngen/flat)
4113 if (pModule->HasNativeImage())
4116 dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4118 // Intentionally not checking for flat, since NGEN PEImages never have flat
4123 #ifdef FEATURE_READYTORUN
4124 // pModule->HasNativeImage() returns false for ReadyToRun images
4125 if (pModule->IsReadyToRun())
4128 dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4131 // Not NGEN or ReadyToRun.
4132 if (pPEFile->HasOpenedILimage())
4134 PEImage * pILImage = pPEFile->GetOpenedILimage();
4135 if (pILImage->IsFile())
4137 dwRet |= COR_PRF_MODULE_DISK;
4139 if (pPEFile->GetLoadedIL()->IsFlat())
4141 dwRet |= COR_PRF_MODULE_FLAT_LAYOUT;
4146 if (pModule->IsReflection())
4148 dwRet |= COR_PRF_MODULE_DYNAMIC;
4151 if (pModule->IsCollectible())
4153 dwRet |= COR_PRF_MODULE_COLLECTIBLE;
4156 if (pModule->IsResource())
4158 dwRet |= COR_PRF_MODULE_RESOURCE;
4161 if (pModule->IsWindowsRuntimeModule())
4163 dwRet |= COR_PRF_MODULE_WINDOWS_RUNTIME;
4169 HRESULT ProfToEEInterfaceImpl::GetModuleInfo2(ModuleID moduleId,
4170 LPCBYTE * ppBaseLoadAddress,
4173 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
4174 AssemblyID * pAssemblyId,
4175 DWORD * pdwModuleFlags)
4185 // The pModule->GetScopeName() call below can result in locks getting taken to
4186 // access the metadata implementation. However, these locks do not do a mode
4194 EE_THREAD_NOT_REQUIRED;
4198 PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
4199 PRECONDITION(CheckPointer(ppBaseLoadAddress, NULL_OK));
4200 PRECONDITION(CheckPointer(pcchName, NULL_OK));
4201 PRECONDITION(CheckPointer(wszName, NULL_OK));
4202 PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
4206 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4209 "**PROF: GetModuleInfo2 0x%p.\n",
4212 if (moduleId == NULL)
4214 return E_INVALIDARG;
4217 Module * pModule = (Module *) moduleId;
4218 if (pModule->IsBeingUnloaded())
4220 return CORPROF_E_DATAINCOMPLETE;
4228 PEFile * pFile = pModule->GetFile();
4230 // Pick some safe defaults to begin with.
4231 if (ppBaseLoadAddress != NULL)
4232 *ppBaseLoadAddress = 0;
4233 if (wszName != NULL)
4235 if (pcchName != NULL)
4237 if (pAssemblyId != NULL)
4238 *pAssemblyId = PROFILER_PARENT_UNKNOWN;
4240 // Module flags can be determined first without fear of error
4241 if (pdwModuleFlags != NULL)
4242 *pdwModuleFlags = GetModuleFlags(pModule);
4244 // Get the module file name
4245 LPCWSTR wszFileName = pFile->GetPath();
4246 _ASSERTE(wszFileName != NULL);
4247 PREFIX_ASSUME(wszFileName != NULL);
4249 // If there is no filename, which is the case for RefEmit modules and for SQL
4250 // modules, then rather than returning an empty string for the name, just use the
4251 // module name from metadata (a.k.a. Module.ScopeName). This is required to
4252 // support SQL F1 sampling profiling.
4253 StackSString strScopeName;
4254 LPCUTF8 szScopeName = NULL;
4255 if ((*wszFileName == W('\0')) && SUCCEEDED(pModule->GetScopeName(&szScopeName)))
4257 strScopeName.SetUTF8(szScopeName);
4258 strScopeName.Normalize();
4259 wszFileName = strScopeName.GetUnicode();
4262 ULONG trueLen = (ULONG)(wcslen(wszFileName) + 1);
4264 // Return name of module as required.
4265 if (wszName && cchName > 0)
4267 if (cchName < trueLen)
4269 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4273 wcsncpy_s(wszName, cchName, wszFileName, trueLen);
4277 // If they request the actual length of the name
4279 *pcchName = trueLen;
4281 if (ppBaseLoadAddress != NULL && !pFile->IsDynamic())
4283 if (pModule->IsProfilerNotified())
4285 // Set the base load address -- this could be null in certain error conditions
4286 *ppBaseLoadAddress = pModule->GetProfilerBase();
4290 *ppBaseLoadAddress = NULL;
4293 if (*ppBaseLoadAddress == NULL)
4295 hr = CORPROF_E_DATAINCOMPLETE;
4299 // Return the parent assembly for this module if desired.
4300 if (pAssemblyId != NULL)
4302 // Lie and say the assembly isn't avaialable until we are loaded (even though it is.)
4303 // This is for backward compatibilty - we may want to change it
4304 if (pModule->IsProfilerNotified())
4306 Assembly *pAssembly = pModule->GetAssembly();
4307 _ASSERTE(pAssembly);
4309 *pAssemblyId = (AssemblyID) pAssembly;
4313 hr = CORPROF_E_DATAINCOMPLETE;
4317 EX_CATCH_HRESULT(hr);
4324 * Get a metadata interface instance which maps to the given module.
4325 * One may ask for the metadata to be opened in read+write mode, but
4326 * this will result in slower metadata execution of the program, because
4327 * changes made to the metadata cannot be optimized as they were from
4330 HRESULT ProfToEEInterfaceImpl::GetModuleMetaData(ModuleID moduleId,
4346 // Currently, this function is technically EE_THREAD_REQUIRED because
4347 // some functions in synch.cpp assert that there is a Thread object,
4348 // but we might be able to lift that restriction and make this be
4349 // EE_THREAD_NOT_REQUIRED.
4351 // PEFile::GetRWImporter & PEFile::GetEmitter &
4352 // GetReadablePublicMetaDataInterface take locks
4359 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
4362 "**PROF: GetModuleMetaData 0x%p, 0x%08x.\n",
4366 if (moduleId == NULL)
4368 return E_INVALIDARG;
4371 // Check for unsupported bits, and return E_INVALIDARG if present
4372 if ((dwOpenFlags & ~(ofNoTransform | ofRead | ofWrite)) != 0)
4374 return E_INVALIDARG;
4380 pModule = (Module *) moduleId;
4381 _ASSERTE(pModule != NULL);
4382 if (pModule->IsBeingUnloaded())
4384 return CORPROF_E_DATAINCOMPLETE;
4387 // Make sure we can get the importer first
4388 if (pModule->IsResource())
4395 // Decide which type of open mode we are in to see which you require.
4396 if ((dwOpenFlags & ofWrite) == 0)
4398 // Readable interface
4399 return pModule->GetReadablePublicMetaDataInterface(dwOpenFlags, riid, (LPVOID *) ppOut);
4402 // Writeable interface
4403 IUnknown *pObj = NULL;
4406 pObj = pModule->GetValidatedEmitter();
4408 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
4410 // Ask for the interface the caller wanted, only if they provide a out param
4411 if (SUCCEEDED(hr) && ppOut)
4412 hr = pObj->QueryInterface(riid, (void **) ppOut);
4419 * Retrieve a pointer to the body of a method starting at it's header.
4420 * A method is scoped by the module it lives in. Because this function
4421 * is designed to give a tool access to IL before it has been loaded
4422 * by the Runtime, it uses the metadata token of the method to find
4423 * the instance desired. Note that this function has no effect on
4424 * already compiled code.
4426 HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID moduleId,
4427 mdMethodDef methodId,
4428 LPCBYTE *ppMethodHeader,
4429 ULONG *pcbMethodSize)
4442 // PEFile::CheckLoaded & Module::GetDynamicIL both take a lock
4449 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
4451 "**PROF: GetILFunctionBody 0x%p, 0x%08x.\n",
4455 Module * pModule; // Working pointer for real class.
4456 ULONG RVA; // Return RVA of the method body.
4457 DWORD dwImplFlags; // Flags for the item.
4459 if ((moduleId == NULL) ||
4460 (methodId == mdMethodDefNil) ||
4462 (TypeFromToken(methodId) != mdtMethodDef))
4464 return E_INVALIDARG;
4467 pModule = (Module *) moduleId;
4468 _ASSERTE(pModule != NULL && methodId != mdMethodDefNil);
4469 if (pModule->IsBeingUnloaded())
4471 return CORPROF_E_DATAINCOMPLETE;
4474 // Find the method body based on metadata.
4475 IMDInternalImport *pImport = pModule->GetMDImport();
4478 PEFile *pFile = pModule->GetFile();
4480 if (!pFile->CheckLoaded())
4481 return (CORPROF_E_DATAINCOMPLETE);
4483 LPCBYTE pbMethod = NULL;
4485 // Don't return rewritten IL, use the new API to get that.
4486 pbMethod = (LPCBYTE) pModule->GetDynamicIL(methodId, FALSE);
4488 // Method not overriden - get the original copy of the IL by going to metadata
4489 if (pbMethod == NULL)
4492 IfFailRet(pImport->GetMethodImplProps(methodId, &RVA, &dwImplFlags));
4494 // Check to see if the method has associated IL
4495 if ((RVA == 0 && !pFile->IsDynamic()) || !(IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags) || IsMiInternalCall(dwImplFlags)))
4497 return (CORPROF_E_FUNCTION_NOT_IL);
4502 // Get the location of the IL
4503 pbMethod = (LPCBYTE) (pModule->GetIL(RVA));
4505 EX_CATCH_HRESULT(hr);
4513 // Fill out param if provided
4515 *ppMethodHeader = pbMethod;
4517 // Calculate the size of the method itself.
4520 if (!FitsIn<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod)))
4522 return E_UNEXPECTED;
4524 *pcbMethodSize = static_cast<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod));
4529 //---------------------------------------------------------------------------------------
4530 // Retrieves an IMethodMalloc pointer around a ModuleILHeap instance that will own
4531 // allocating heap space for this module (for IL rewriting).
4534 // moduleId - ModuleID this allocator shall allocate for
4535 // ppMalloc - [out] IMethodMalloc pointer the profiler will use for allocation requests
4536 // against this module
4539 // HRESULT indicating success / failure
4542 // IL method bodies used to have the requirement that they must be referenced as
4543 // RVA's to the loaded module, which means they come after the module within
4544 // METHOD_MAX_RVA. In order to make it easier for a tool to swap out the body of
4545 // a method, this allocator will ensure memory allocated after that point.
4547 // Now that requirement is completely gone, so there's nothing terribly special
4548 // about this allocator, we just keep it around for legacy purposes.
4550 HRESULT ProfToEEInterfaceImpl::GetILFunctionBodyAllocator(ModuleID moduleId,
4551 IMethodMalloc ** ppMalloc)
4558 // ModuleILHeap::FindOrCreateHeap may take a Crst if it
4559 // needs to create a new allocator and add it to the list. Taking a crst
4560 // switches to preemptive, which is effectively a GC trigger
4567 EE_THREAD_NOT_REQUIRED;
4569 // (see GC_TRIGGERS comment)
4576 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4580 "**PROF: GetILFunctionBodyAllocator 0x%p.\n",
4583 if ((moduleId == NULL) || (ppMalloc == NULL))
4585 return E_INVALIDARG;
4588 Module * pModule = (Module *) moduleId;
4590 if (pModule->IsBeingUnloaded() ||
4591 !pModule->GetFile()->CheckLoaded())
4593 return (CORPROF_E_DATAINCOMPLETE);
4596 *ppMalloc = &ModuleILHeap::s_Heap;
4601 * Replaces the method body for a function in a module. This will replace
4602 * the RVA of the method in the metadata to point to this new method body,
4603 * and adjust any internal data structures as required. This function can
4604 * only be called on those methods which have never been compiled by a JITTER.
4605 * Please use the GetILFunctionBodyAllocator to allocate space for the new method to
4606 * ensure the buffer is compatible.
4608 HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId,
4609 mdMethodDef methodId,
4610 LPCBYTE pbNewILMethodHeader)
4614 // PEFile::GetEmitter, Module::SetDynamicIL all throw
4617 // Locks are taken (see CAN_TAKE_LOCK below), which may cause mode switch to
4618 // preemptive, which is triggers.
4624 // Module::SetDynamicIL & PEFile::CheckLoaded & PEFile::GetEmitter take locks
4631 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4635 "**PROF: SetILFunctionBody 0x%p, 0x%08x.\n",
4639 if ((moduleId == NULL) ||
4640 (methodId == mdMethodDefNil) ||
4641 (TypeFromToken(methodId) != mdtMethodDef) ||
4642 (pbNewILMethodHeader == NULL))
4644 return E_INVALIDARG;
4647 Module *pModule; // Working pointer for real class.
4650 // Cannot set the body for anything other than a method def
4651 if (TypeFromToken(methodId) != mdtMethodDef)
4652 return (E_INVALIDARG);
4654 // Cast module to appropriate type
4655 pModule = (Module *) moduleId;
4656 _ASSERTE (pModule != NULL); // Enforced in CorProfInfo::SetILFunctionBody
4657 if (pModule->IsBeingUnloaded())
4659 return CORPROF_E_DATAINCOMPLETE;
4662 // Remember the profiler is doing this, as that means we must never detach it!
4663 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
4665 // This action is not temporary!
4666 // If the profiler want to be able to revert, they need to use
4667 // the new ReJIT APIs.
4668 pModule->SetDynamicIL(methodId, (TADDR)pbNewILMethodHeader, FALSE);
4674 * Sets the codemap for the replaced IL function body
4676 HRESULT ProfToEEInterfaceImpl::SetILInstrumentedCodeMap(FunctionID functionId,
4678 ULONG cILMapEntries,
4679 COR_IL_MAP rgILMapEntries[])
4683 // Debugger::SetILInstrumentedCodeMap throws
4686 // Debugger::SetILInstrumentedCodeMap triggers
4693 EE_THREAD_NOT_REQUIRED;
4695 // Debugger::SetILInstrumentedCodeMap takes a lock when it calls Debugger::GetOrCreateMethodInfo
4702 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4706 "**PROF: SetILInstrumentedCodeMap 0x%p, %d.\n",
4710 if (functionId == NULL)
4712 return E_INVALIDARG;
4715 if (cILMapEntries >= (MAXULONG / sizeof(COR_IL_MAP)))
4717 // Too big! The allocation below would overflow when calculating the size.
4718 return E_INVALIDARG;
4722 #ifdef DEBUGGING_SUPPORTED
4724 MethodDesc *pMethodDesc = FunctionIdToMethodDesc(functionId);
4726 // it's not safe to examine a methoddesc that has not been restored so do not do so
4727 if (!pMethodDesc ->IsRestored())
4728 return CORPROF_E_DATAINCOMPLETE;
4730 if (g_pDebugInterface == NULL)
4732 return CORPROF_E_DEBUGGING_DISABLED;
4735 COR_IL_MAP * rgNewILMapEntries = new (nothrow) COR_IL_MAP[cILMapEntries];
4737 if (rgNewILMapEntries == NULL)
4738 return E_OUTOFMEMORY;
4740 memcpy_s(rgNewILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries, rgILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries);
4742 return g_pDebugInterface->SetILInstrumentedCodeMap(pMethodDesc,
4747 #else //DEBUGGING_SUPPORTED
4749 #endif //DEBUGGING_SUPPORTED
4752 HRESULT ProfToEEInterfaceImpl::ForceGC()
4756 // GC calls "new" which throws
4759 // Uh duh, look at the name of the function, dude
4766 EE_THREAD_NOT_REQUIRED;
4768 // Initiating a GC causes a runtime suspension which requires the
4769 // mother of all locks: the thread store lock.
4776 ASSERT_NO_EE_LOCKS_HELD();
4778 // We need to use IsGarbageCollectorFullyInitialized() instead of IsGCHeapInitialized() because
4779 // there are other GC initialization being done after IsGCHeapInitialized() becomes TRUE,
4780 // and before IsGarbageCollectorFullyInitialized() becomes TRUE.
4781 if (!IsGarbageCollectorFullyInitialized())
4783 return CORPROF_E_NOT_YET_AVAILABLE;
4786 // Disallow the cases where a profiler calls this off a hijacked CLR thread
4787 // or inside a profiler callback. (Allow cases where this is a native thread, or a
4788 // thread which previously successfully called ForceGC.)
4789 Thread * pThread = GetThreadNULLOk();
4790 if ((pThread != NULL) &&
4791 (!AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED)) &&
4792 (pThread->GetFrame() != FRAME_TOP
4793 || AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_INCALLBACK)))
4797 "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE "
4798 "due to illegal hijacked profiler call or call from inside another callback\n"));
4799 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
4802 // NOTE: We cannot use the standard macro PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX
4803 // here because the macro ensures that either the current thread is not an
4804 // EE thread, or, if it is, that the CALLBACK flag is set. In classic apps
4805 // a profiler-owned native thread will not get an EE thread associated with
4806 // it, however, in AppX apps, during the first call into the GC on a
4807 // profiler-owned thread, the EE will associate an EE-thread with the profiler
4808 // thread. As a consequence the second call to ForceGC on the same thread
4809 // would fail, since this is now an EE thread and this API is not called from
4812 // First part of the PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX macro:
4813 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4814 kP2EEAllowableAfterAttach | kP2EETriggers,
4817 "**PROF: ForceGC.\n"));
4819 #ifdef FEATURE_EVENT_TRACE
4820 // This helper, used by ETW and profAPI ensures a managed thread gets created for
4821 // this thread before forcing the GC (to work around Jupiter issues where it's
4822 // expected this thread is already managed before starting the GC).
4823 HRESULT hr = ETW::GCLog::ForceGCForDiagnostics();
4824 #else // !FEATURE_EVENT_TRACE
4825 HRESULT hr = E_FAIL;
4826 #endif // FEATURE_EVENT_TRACE
4828 // If a Thread object was just created for this thread, remember the fact that it
4829 // was a ForceGC() thread, so we can be more lenient when doing
4830 // COR_PRF_CALLBACKSTATE_INCALLBACK later on from other APIs
4831 pThread = GetThreadNULLOk();
4832 if (pThread != NULL)
4834 pThread->SetProfilerCallbackStateFlags(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED);
4842 * Returns the ContextID for the current thread.
4844 HRESULT ProfToEEInterfaceImpl::GetThreadContext(ThreadID threadId,
4845 ContextID *pContextId)
4859 EE_THREAD_NOT_REQUIRED;
4868 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4871 "**PROF: GetThreadContext 0x%p.\n",
4874 if (!IsManagedThread(threadId))
4876 return E_INVALIDARG;
4879 // Cast to right type
4880 Thread *pThread = reinterpret_cast<Thread *>(threadId);
4882 // Get the context for the Thread* provided
4883 Context *pContext = pThread->GetContext();
4886 // If there's no current context, return incomplete info
4888 return (CORPROF_E_DATAINCOMPLETE);
4890 // Set the result and return
4892 *pContextId = reinterpret_cast<ContextID>(pContext);
4897 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo(ClassID classId,
4898 ModuleID *pModuleId,
4899 mdTypeDef *pTypeDefToken)
4913 EE_THREAD_NOT_REQUIRED;
4922 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4925 "**PROF: GetClassIDInfo 0x%p.\n",
4928 if (classId == NULL)
4930 return E_INVALIDARG;
4933 if (pModuleId != NULL)
4938 if (pTypeDefToken != NULL)
4940 *pTypeDefToken = NULL;
4943 // Handle globals which don't have the instances.
4944 if (classId == PROFILER_GLOBAL_CLASS)
4946 if (pModuleId != NULL)
4948 *pModuleId = PROFILER_GLOBAL_MODULE;
4951 if (pTypeDefToken != NULL)
4953 *pTypeDefToken = mdTokenNil;
4956 else if (classId == NULL)
4958 return E_INVALIDARG;
4960 // Get specific data.
4963 TypeHandle th = TypeHandle::FromPtr((void *)classId);
4965 if (!th.IsTypeDesc())
4970 // If this class is not fully restored, that is all the information we can get at this time.
4972 if (!th.IsRestored())
4974 return CORPROF_E_DATAINCOMPLETE;
4977 if (pModuleId != NULL)
4979 *pModuleId = (ModuleID) th.GetModule();
4980 _ASSERTE(*pModuleId != NULL);
4983 if (pTypeDefToken != NULL)
4985 *pTypeDefToken = th.GetCl();
4986 _ASSERTE(*pTypeDefToken != NULL);
4996 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo(FunctionID functionId,
4998 ModuleID *pModuleId,
5013 EE_THREAD_NOT_REQUIRED;
5022 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
5025 "**PROF: GetFunctionInfo 0x%p.\n",
5028 if (functionId == NULL)
5030 return E_INVALIDARG;
5033 MethodDesc *pMDesc = (MethodDesc *) functionId;
5034 if (!pMDesc->IsRestored())
5036 return CORPROF_E_DATAINCOMPLETE;
5039 MethodTable *pMT = pMDesc->GetMethodTable();
5040 if (!pMT->IsRestored())
5042 return CORPROF_E_DATAINCOMPLETE;
5045 ClassID classId = PROFILER_GLOBAL_CLASS;
5049 classId = NonGenericTypeHandleToClassID(TypeHandle(pMT));
5052 if (pClassId != NULL)
5054 *pClassId = classId;
5057 if (pModuleId != NULL)
5059 *pModuleId = (ModuleID) pMDesc->GetModule();
5064 *pToken = pMDesc->GetMemberDef();
5071 * GetILToNativeMapping returns a map from IL offsets to native
5072 * offsets for this code. An array of COR_DEBUG_IL_TO_NATIVE_MAP
5073 * structs will be returned, and some of the ilOffsets in this array
5074 * may be the values specified in CorDebugIlToNativeMappingTypes.
5076 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping(FunctionID functionId,
5078 ULONG32 * pcMap, // [out]
5079 COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
5083 // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
5086 // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
5087 // called from here. Since the profiler has a valid functionId, the methoddesc for
5088 // this code will already have been created. We should be able to enforce this by
5089 // passing allowCreate=FALSE to FindOrCreateTypicalSharedInstantiation.
5090 DISABLED(GC_NOTRIGGER);
5095 // The call to g_pDebugInterface->GetILToNativeMapping() below may call
5096 // Debugger::AcquireDebuggerLock
5103 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5106 "**PROF: GetILToNativeMapping 0x%p.\n",
5109 return GetILToNativeMapping2(functionId, 0, cMap, pcMap, map);
5112 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId,
5115 ULONG32 * pcMap, // [out]
5116 COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
5120 // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
5123 // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
5124 // called from here. Since the profiler has a valid functionId, the methoddesc for
5125 // this code will already have been created. We should be able to enforce this by
5126 // passing allowCreate=FALSE to FindOrCreateTypicalSharedInstantiation.
5127 DISABLED(GC_NOTRIGGER);
5132 // The call to g_pDebugInterface->GetILToNativeMapping() below may call
5133 // Debugger::AcquireDebuggerLock
5140 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5143 "**PROF: GetILToNativeMapping2 0x%p 0x%p.\n",
5144 functionId, reJitId));
5146 if (functionId == NULL)
5148 return E_INVALIDARG;
5152 ((pcMap == NULL) || (map == NULL)))
5154 return E_INVALIDARG;
5162 #ifdef DEBUGGING_SUPPORTED
5163 // Cast to proper type
5164 MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
5166 if (pMD->HasClassOrMethodInstantiation() && pMD->IsTypicalMethodDefinition())
5168 // In this case, we used to replace pMD with its canonical instantiation
5169 // (FindOrCreateTypicalSharedInstantiation). However, a profiler should never be able
5170 // to get to this point anyway, since any MethodDesc a profiler gets from us
5171 // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
5172 // We assert here just in case a test proves me wrong, but generally we will
5173 // disallow this code path.
5174 _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetILToNativeMapping2");
5175 return E_INVALIDARG;
5178 if (g_pDebugInterface == NULL)
5180 return CORPROF_E_DEBUGGING_DISABLED;
5183 return (g_pDebugInterface->GetILToNativeMapping(pMD, cMap, pcMap, map));
5191 //*****************************************************************************
5192 // Given an ObjectID, go get the EE ClassID for it.
5193 //*****************************************************************************
5194 HRESULT ProfToEEInterfaceImpl::GetClassFromObject(ObjectID objectId,
5205 // Yay! Fail at runtime if in preemptive mode via AllowObjectInspection()
5208 // Object::GetTypeHandle takes a lock
5215 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5218 "**PROF: GetClassFromObject 0x%p.\n",
5221 if (objectId == NULL)
5223 return E_INVALIDARG;
5226 HRESULT hr = AllowObjectInspection();
5232 // Cast the ObjectID as a Object
5233 Object *pObj = reinterpret_cast<Object *>(objectId);
5235 // Set the out param and indicate success
5236 // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
5239 *pClassId = SafeGetClassIDFromObject(pObj);
5245 //*****************************************************************************
5246 // Given a module and a token for a class, go get the EE data structure for it.
5247 //*****************************************************************************
5248 HRESULT ProfToEEInterfaceImpl::GetClassFromToken(ModuleID moduleId,
5257 // ClassLoader::LoadTypeDefOrRefThrowing triggers
5263 // ClassLoader::LoadTypeDefOrRefThrowing takes a lock
5270 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5271 kP2EEAllowableAfterAttach | kP2EETriggers,
5274 "**PROF: GetClassFromToken 0x%p, 0x%08x.\n",
5278 if ((moduleId == NULL) || (typeDef == mdTypeDefNil) || (typeDef == NULL))
5280 return E_INVALIDARG;
5283 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5285 return CORPROF_E_RUNTIME_UNINITIALIZED;
5289 Module *pModule = (Module *) moduleId;
5291 // No module, or it's disassociated from metadata
5292 if ((pModule == NULL) || (pModule->IsBeingUnloaded()))
5294 return CORPROF_E_DATAINCOMPLETE;
5297 // First, check the RID map. This is important since it
5298 // works during teardown (and the below doesn't)
5300 th = pModule->LookupTypeDef(typeDef);
5306 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, typeDef,
5307 ClassLoader::ThrowIfNotFound,
5308 ClassLoader::PermitUninstDefOrRef);
5310 EX_CATCH_HRESULT(hr);
5318 if (!th.GetMethodTable())
5320 return CORPROF_E_DATAINCOMPLETE;
5324 // Check if it is generic
5326 ClassID classId = NonGenericTypeHandleToClassID(th);
5328 if (classId == NULL)
5330 return CORPROF_E_TYPE_IS_PARAMETERIZED;
5333 // Return value if necessary
5336 *pClassId = classId;
5343 HRESULT ProfToEEInterfaceImpl::GetClassFromTokenAndTypeArgs(ModuleID moduleID,
5354 // LoadGenericInstantiationThrowing may load
5360 // ClassLoader::LoadGenericInstantiationThrowing takes a lock
5367 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5368 kP2EEAllowableAfterAttach | kP2EETriggers,
5371 "**PROF: GetClassFromTokenAndTypeArgs 0x%p, 0x%08x.\n",
5375 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5377 return CORPROF_E_RUNTIME_UNINITIALIZED;
5380 Module* pModule = reinterpret_cast< Module* >(moduleID);
5382 if (pModule == NULL || pModule->IsBeingUnloaded())
5384 return CORPROF_E_DATAINCOMPLETE;
5387 // This array needs to be accessible at least until the call to
5388 // ClassLoader::LoadGenericInstantiationThrowing
5389 TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5390 NewArrayHolder< TypeHandle > holder(genericParameters);
5392 if (NULL == genericParameters)
5394 return E_OUTOFMEMORY;
5397 for (ULONG32 i = 0; i < cTypeArgs; ++i)
5399 genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5403 // nickbe 11/24/2003 10:12:56
5405 // In RTM/Everett we decided to load the class if it hadn't been loaded yet
5406 // (see ProfToEEInterfaceImpl::GetClassFromToken). For compatibility we're
5407 // going to make the same decision here. It's potentially confusing to tell
5408 // someone a type doesn't exist at one point in time, but does exist later,
5409 // and there is no good way for us to determing that a class may eventually
5410 // be loaded without going ahead and loading it
5417 // Not sure if this is a valid override or not - making this a VIOLATION
5418 // until we're sure.
5419 CONTRACT_VIOLATION(LoadsTypeViolation);
5421 if (GetThreadNULLOk() == NULL)
5423 // Type system will try to validate as part of its contract if the current
5424 // AppDomain returned by GetAppDomain can load types in specified module's
5425 // assembly. On a non-EE thread it results in an AV in a check build
5426 // since the type system tries to dereference NULL returned by GetAppDomain.
5427 // More importantly, loading a type on a non-EE thread is not allowed.
5429 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE() states that callers will not
5430 // try to load a type, so that type system will not try to test type
5431 // loadability in the current AppDomain. However,
5432 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE does not prevent callers from
5433 // loading a type. It is profiler's responsibility not to attempt to load
5434 // a type in unsupported ways (e.g. from a non-EE thread). It doesn't
5435 // impact retail builds, in which contracts are not available.
5436 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5438 // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE also defines FAULT_FORBID, which
5439 // causes Scanruntime to flag a fault violation in AssemblySpec::InitializeSpec,
5440 // which is defined as FAULTS. It only happens in a type-loading path, which
5441 // is not supported on a non-EE thread. Suppressing a contract violation in an
5442 // unsupported execution path is more preferable than causing AV when calling
5443 // GetClassFromTokenAndTypeArgs on a non-EE thread in a check build. See Dev10
5444 // 682526 for more details.
5447 th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5449 Instantiation(genericParameters, cTypeArgs),
5450 ClassLoader::LoadTypes);
5454 th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5456 Instantiation(genericParameters, cTypeArgs),
5457 ClassLoader::LoadTypes);
5460 EX_CATCH_HRESULT(hr);
5469 // Hmm, the type isn't loaded yet.
5470 return CORPROF_E_DATAINCOMPLETE;
5473 *pClassID = TypeHandleToClassID(th);
5478 //*****************************************************************************
5479 // Given the token for a method, return the fucntion id.
5480 //*****************************************************************************
5481 HRESULT ProfToEEInterfaceImpl::GetFunctionFromToken(ModuleID moduleId,
5483 FunctionID *pFunctionId)
5497 EE_THREAD_NOT_REQUIRED;
5506 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5509 "**PROF: GetFunctionFromToken 0x%p, 0x%08x.\n",
5513 if ((moduleId == NULL) || (typeDef == mdTokenNil))
5515 return E_INVALIDARG;
5518 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5520 return CORPROF_E_RUNTIME_UNINITIALIZED;
5527 Module *pModule = (Module *) moduleId;
5529 // No module, or disassociated from metadata
5530 if (pModule == NULL || pModule->IsBeingUnloaded())
5532 return CORPROF_E_DATAINCOMPLETE;
5535 // Default return value of NULL
5536 MethodDesc *pDesc = NULL;
5538 // Different lookup depending on whether it's a Def or Ref
5539 if (TypeFromToken(typeDef) == mdtMethodDef)
5541 pDesc = pModule->LookupMethodDef(typeDef);
5543 else if (TypeFromToken(typeDef) == mdtMemberRef)
5545 pDesc = pModule->LookupMemberRefAsMethod(typeDef);
5549 return E_INVALIDARG;
5554 return E_INVALIDARG;
5558 // Check that this is a non-generic method
5560 if (pDesc->HasClassOrMethodInstantiation())
5562 return CORPROF_E_FUNCTION_IS_PARAMETERIZED;
5565 if (pFunctionId && SUCCEEDED(hr))
5567 *pFunctionId = MethodDescToFunctionID(pDesc);
5573 HRESULT ProfToEEInterfaceImpl::GetFunctionFromTokenAndTypeArgs(ModuleID moduleID,
5574 mdMethodDef funcDef,
5578 FunctionID* pFunctionID)
5585 // It can trigger type loads
5591 // MethodDesc::FindOrCreateAssociatedMethodDesc enters a Crst
5598 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5599 kP2EEAllowableAfterAttach | kP2EETriggers,
5602 "**PROF: GetFunctionFromTokenAndTypeArgs 0x%p, 0x%08x, 0x%p.\n",
5607 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
5608 Module* pModule = reinterpret_cast< Module* >(moduleID);
5610 if ((pModule == NULL) || typeHandle.IsNull())
5612 return E_INVALIDARG;
5615 if (!g_profControlBlock.fBaseSystemClassesLoaded)
5617 return CORPROF_E_RUNTIME_UNINITIALIZED;
5620 if (pModule->IsBeingUnloaded())
5622 return CORPROF_E_DATAINCOMPLETE;
5625 MethodDesc* pMethodDesc = NULL;
5627 if (mdtMethodDef == TypeFromToken(funcDef))
5629 pMethodDesc = pModule->LookupMethodDef(funcDef);
5631 else if (mdtMemberRef == TypeFromToken(funcDef))
5633 pMethodDesc = pModule->LookupMemberRefAsMethod(funcDef);
5637 return E_INVALIDARG;
5640 MethodTable* pMethodTable = typeHandle.GetMethodTable();
5642 if (pMethodTable == NULL || !pMethodTable->IsRestored() ||
5643 pMethodDesc == NULL || !pMethodDesc->IsRestored())
5645 return CORPROF_E_DATAINCOMPLETE;
5648 // This array needs to be accessible at least until the call to
5649 // MethodDesc::FindOrCreateAssociatedMethodDesc
5650 TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5651 NewArrayHolder< TypeHandle > holder(genericParameters);
5653 if (NULL == genericParameters)
5655 return E_OUTOFMEMORY;
5658 for (ULONG32 i = 0; i < cTypeArgs; ++i)
5660 genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5663 MethodDesc* result = NULL;
5668 result = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethodDesc,
5671 Instantiation(genericParameters, cTypeArgs),
5674 EX_CATCH_HRESULT(hr);
5678 *pFunctionID = MethodDescToFunctionID(result);
5684 //*****************************************************************************
5685 // Retrieve information about a given application domain, which is like a
5687 //*****************************************************************************
5688 HRESULT ProfToEEInterfaceImpl::GetAppDomainInfo(AppDomainID appDomainId,
5691 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5692 ProcessID *pProcessId)
5699 // AppDomain::GetFriendlyNameForDebugger triggers
5705 // AppDomain::GetFriendlyNameForDebugger takes a lock
5712 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5713 kP2EEAllowableAfterAttach | kP2EETriggers,
5716 "**PROF: GetAppDomainInfo 0x%p.\n",
5719 if (appDomainId == NULL)
5721 return E_INVALIDARG;
5724 BaseDomain *pDomain; // Internal data structure.
5728 // Right now, this ID is not a true AppDomain, since we use the old
5729 // AppDomain/SystemDomain model in the profiling API. This means that
5730 // the profiler exposes the SharedDomain and the SystemDomain to the
5731 // outside world. It's not clear whether this is actually the right thing
5732 // to do or not. - seantrow
5737 pDomain = (BaseDomain *) appDomainId;
5739 // Make sure they've passed in a valid appDomainId
5740 if (pDomain == NULL)
5741 return (E_INVALIDARG);
5743 // Pick sensible defaults.
5751 LPCWSTR szFriendlyName;
5752 if (pDomain == SystemDomain::System())
5753 szFriendlyName = g_pwBaseLibrary;
5754 else if (pDomain == SharedDomain::GetDomain())
5755 szFriendlyName = W("EE Shared Assembly Repository");
5757 szFriendlyName = ((AppDomain*)pDomain)->GetFriendlyNameForDebugger();
5759 if (szFriendlyName != NULL)
5761 // Get the module file name
5762 ULONG trueLen = (ULONG)(wcslen(szFriendlyName) + 1);
5764 // Return name of module as required.
5765 if (szName && cchName > 0)
5767 ULONG copyLen = trueLen;
5769 if (copyLen >= cchName)
5771 copyLen = cchName - 1;
5774 wcsncpy_s(szName, cchName, szFriendlyName, copyLen);
5777 // If they request the actual length of the name
5779 *pcchName = trueLen;
5782 // If we don't have a friendly name but the call was requesting it, then return incomplete data HR
5785 if ((szName != NULL && cchName > 0) || pcchName)
5786 hr = CORPROF_E_DATAINCOMPLETE;
5790 *pProcessId = (ProcessID) GetCurrentProcessId();
5796 //*****************************************************************************
5797 // Retrieve information about an assembly, which is a collection of dll's.
5798 //*****************************************************************************
5799 HRESULT ProfToEEInterfaceImpl::GetAssemblyInfo(AssemblyID assemblyId,
5802 __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5803 AppDomainID *pAppDomainId,
5804 ModuleID *pModuleId)
5808 // SString::SString throws
5818 EE_THREAD_NOT_REQUIRED;
5820 // PEAssembly::GetSimpleName() enters a lock via use of the metadata interface
5827 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5830 "**PROF: GetAssemblyInfo 0x%p.\n",
5833 if (assemblyId == NULL)
5835 return E_INVALIDARG;
5840 Assembly *pAssembly; // Internal data structure for assembly.
5842 pAssembly = (Assembly *) assemblyId;
5843 _ASSERTE(pAssembly != NULL);
5845 if (pcchName || szName)
5847 // Get the friendly name of the assembly
5848 SString name(SString::Utf8, pAssembly->GetSimpleName());
5850 const COUNT_T nameLength = name.GetCount() + 1;
5852 if ((NULL != szName) && (cchName > 0))
5854 wcsncpy_s(szName, cchName, name.GetUnicode(), min(nameLength, cchName - 1));
5857 if (NULL != pcchName)
5859 *pcchName = nameLength;
5863 // Get the parent application domain.
5866 *pAppDomainId = (AppDomainID) pAssembly->GetDomain();
5867 _ASSERTE(*pAppDomainId != NULL);
5870 // Find the module the manifest lives in.
5873 *pModuleId = (ModuleID) pAssembly->GetManifestModule();
5875 // This is the case where the profiler has called GetAssemblyInfo
5876 // on an assembly that has been completely created yet.
5878 hr = CORPROF_E_DATAINCOMPLETE;
5884 // Setting ELT hooks is only allowed from within Initialize(). However, test-only
5885 // profilers may need to set those hooks from an attaching profiling. See
5886 // code:ProfControlBlock#TestOnlyELT
5887 #ifdef PROF_TEST_ONLY_FORCE_ELT
5888 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT(logParams) \
5891 if (g_profControlBlock.fTestOnlyForceEnterLeave) \
5893 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, logParams); \
5897 PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams); \
5900 #else // PROF_TEST_ONLY_FORCE_ELT
5901 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT \
5902 PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY
5903 #endif // PROF_TEST_ONLY_FORCE_ELT
5906 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
5907 FunctionLeave * pFuncLeave,
5908 FunctionTailcall * pFuncTailcall)
5922 EE_THREAD_NOT_REQUIRED;
5930 // The profiler must call SetEnterLeaveFunctionHooks during initialization, since
5931 // the enter/leave events are immutable and must also be set during initialization.
5932 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5934 "**PROF: SetEnterLeaveFunctionHooks 0x%p, 0x%p, 0x%p.\n",
5939 return g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall);
5943 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
5944 FunctionLeave2 * pFuncLeave,
5945 FunctionTailcall2 * pFuncTailcall)
5959 EE_THREAD_NOT_REQUIRED;
5967 // The profiler must call SetEnterLeaveFunctionHooks2 during initialization, since
5968 // the enter/leave events are immutable and must also be set during initialization.
5969 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5971 "**PROF: SetEnterLeaveFunctionHooks2 0x%p, 0x%p, 0x%p.\n",
5977 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall);
5981 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
5982 FunctionLeave3 * pFuncLeave3,
5983 FunctionTailcall3 * pFuncTailcall3)
5997 EE_THREAD_NOT_REQUIRED;
6005 // The profiler must call SetEnterLeaveFunctionHooks3 during initialization, since
6006 // the enter/leave events are immutable and must also be set during initialization.
6007 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
6009 "**PROF: SetEnterLeaveFunctionHooks3 0x%p, 0x%p, 0x%p.\n",
6015 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3,
6022 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
6023 FunctionLeave3WithInfo * pFuncLeave3WithInfo,
6024 FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
6038 EE_THREAD_NOT_REQUIRED;
6046 // The profiler must call SetEnterLeaveFunctionHooks3WithInfo during initialization, since
6047 // the enter/leave events are immutable and must also be set during initialization.
6048 PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
6050 "**PROF: SetEnterLeaveFunctionHooks3WithInfo 0x%p, 0x%p, 0x%p.\n",
6051 pFuncEnter3WithInfo,
6052 pFuncLeave3WithInfo,
6053 pFuncTailcall3WithInfo));
6056 g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo,
6057 pFuncLeave3WithInfo,
6058 pFuncTailcall3WithInfo);
6062 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper(FunctionIDMapper *pFunc)
6076 EE_THREAD_NOT_REQUIRED;
6085 PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF,
6087 "**PROF: SetFunctionIDMapper 0x%p.\n",
6090 g_profControlBlock.pProfInterface->SetFunctionIDMapper(pFunc);
6095 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper2(FunctionIDMapper2 *pFunc, void * clientData)
6109 EE_THREAD_NOT_REQUIRED;
6118 PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF,
6120 "**PROF: SetFunctionIDMapper2. pFunc: 0x%p. clientData: 0x%p.\n",
6124 g_profControlBlock.pProfInterface->SetFunctionIDMapper2(pFunc, clientData);
6132 * This function takes the frameInfo returned from a profiler callback and splays it
6133 * out into as much information as possible.
6136 * funcId - The function that is being requested.
6137 * frameInfo - Frame specific information from a callback (for resolving generics).
6138 * pClassId - An optional parameter for returning the class id of the function.
6139 * pModuleId - An optional parameter for returning the module of the function.
6140 * pToken - An optional parameter for returning the metadata token of the function.
6141 * cTypeArgs - The count of the size of the array typeArgs
6142 * pcTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
6143 * the number that would be needed.
6144 * typeArgs - An array to store generic type parameters for the function.
6147 * S_OK if successful.
6149 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo2(FunctionID funcId,
6150 COR_PRF_FRAME_INFO frameInfo,
6152 ModuleID *pModuleId,
6155 ULONG32 *pcTypeArgs,
6170 EE_THREAD_NOT_REQUIRED;
6172 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6173 // reads metadata which causes us to take a reader lock. However, see
6174 // code:#DisableLockOnAsyncCalls
6175 DISABLED(CAN_TAKE_LOCK);
6177 // Asynchronous functions can be called at arbitrary times when runtime
6178 // is holding locks that cannot be reentered without causing deadlock.
6179 // This contract detects any attempts to reenter locks held at the time
6180 // this function was called.
6185 PRECONDITION(CheckPointer(pClassId, NULL_OK));
6186 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6187 PRECONDITION(CheckPointer(pToken, NULL_OK));
6188 PRECONDITION(CheckPointer(pcTypeArgs, NULL_OK));
6189 PRECONDITION(CheckPointer(typeArgs, NULL_OK));
6193 // See code:#DisableLockOnAsyncCalls
6194 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6196 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6199 "**PROF: GetFunctionInfo2 0x%p.\n",
6203 // Verify parameters.
6205 COR_PRF_FRAME_INFO_INTERNAL *pFrameInfo = (COR_PRF_FRAME_INFO_INTERNAL *)frameInfo;
6207 if ((funcId == NULL) ||
6208 ((pFrameInfo != NULL) && (pFrameInfo->funcID != funcId)))
6210 return E_INVALIDARG;
6213 MethodDesc *pMethDesc = FunctionIdToMethodDesc(funcId);
6215 if (pMethDesc == NULL)
6217 return E_INVALIDARG;
6220 if ((cTypeArgs != 0) && (typeArgs == NULL))
6222 return E_INVALIDARG;
6225 // it's not safe to examine a methoddesc that has not been restored so do not do so
6226 if (!pMethDesc ->IsRestored())
6227 return CORPROF_E_DATAINCOMPLETE;
6230 // Find the exact instantiation of this function.
6232 TypeHandle specificClass;
6233 MethodDesc* pActualMethod;
6235 ClassID classId = NULL;
6237 if (pMethDesc->IsSharedByGenericInstantiations())
6240 OBJECTREF pThis = NULL;
6242 if (pFrameInfo != NULL)
6244 // If FunctionID represents a generic methoddesc on a struct, then pFrameInfo->thisArg
6245 // isn't an Object*. It's a pointer directly into the struct's members (i.e., it's not pointing at the
6246 // method table). That means pFrameInfo->thisArg cannot be casted to an OBJECTREF for
6247 // use by Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation. However,
6248 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation won't even need a this pointer
6249 // for the methoddesc it's processing if the methoddesc is on a value type. So we
6250 // can safely pass NULL for the methoddesc's this in such a case.
6251 if (pMethDesc->GetMethodTable()->IsValueType())
6253 _ASSERTE(!pMethDesc->AcquiresInstMethodTableFromThis());
6254 _ASSERTE(pThis == NULL);
6258 pThis = ObjectToOBJECTREF((PTR_Object)(pFrameInfo->thisArg));
6262 exactMatch = Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
6265 PTR_VOID((pFrameInfo != NULL) ? pFrameInfo->extraArg : NULL),
6271 classId = TypeHandleToClassID(specificClass);
6273 else if (!specificClass.HasInstantiation() || !specificClass.IsSharedByGenericInstantiations())
6276 // In this case we could not get the type args for the method, but if the class
6277 // is not a generic class or is instantiated with value types, this value is correct.
6279 classId = TypeHandleToClassID(specificClass);
6284 // We could not get any class information.
6291 TypeHandle typeHandle(pMethDesc->GetMethodTable());
6292 classId = TypeHandleToClassID(typeHandle);
6293 pActualMethod = pMethDesc;
6298 // Fill in the ClassId, if desired
6300 if (pClassId != NULL)
6302 *pClassId = classId;
6306 // Fill in the ModuleId, if desired.
6308 if (pModuleId != NULL)
6310 *pModuleId = (ModuleID)pMethDesc->GetModule();
6314 // Fill in the token, if desired.
6318 *pToken = (mdToken)pMethDesc->GetMemberDef();
6321 if ((cTypeArgs == 0) && (pcTypeArgs != NULL))
6324 // They are searching for the size of the array needed, we can return that now and
6325 // short-circuit all the work below.
6327 if (pcTypeArgs != NULL)
6329 *pcTypeArgs = pActualMethod->GetNumGenericMethodArgs();
6335 // If no place to store resulting count, quit now.
6337 if (pcTypeArgs == NULL)
6343 // Fill in the type args
6345 DWORD cArgsToFill = pActualMethod->GetNumGenericMethodArgs();
6347 if (cArgsToFill > cTypeArgs)
6349 cArgsToFill = cTypeArgs;
6352 *pcTypeArgs = cArgsToFill;
6354 if (cArgsToFill == 0)
6359 Instantiation inst = pActualMethod->GetMethodInstantiation();
6361 for (DWORD i = 0; i < cArgsToFill; i++)
6363 typeArgs[i] = TypeHandleToClassID(inst[i]);
6372 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6373 * or LCG method and returns true in the pHasNoMetadata if it is indeed a metadata-less
6377 * functionId - The function that is being requested.
6378 * isDynamic - An optional parameter for returning if the function has metadata or not.
6381 * S_OK if successful.
6383 HRESULT ProfToEEInterfaceImpl::IsFunctionDynamic(FunctionID functionId, BOOL *isDynamic)
6390 EE_THREAD_NOT_REQUIRED;
6392 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6393 // reads metadata which causes us to take a reader lock. However, see
6394 // code:#DisableLockOnAsyncCalls
6395 DISABLED(CAN_TAKE_LOCK);
6397 // Asynchronous functions can be called at arbitrary times when runtime
6398 // is holding locks that cannot be reentered without causing deadlock.
6399 // This contract detects any attempts to reenter locks held at the time
6400 // this function was called.
6405 PRECONDITION(CheckPointer(isDynamic, NULL_OK));
6409 // See code:#DisableLockOnAsyncCalls
6410 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6412 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6415 "**PROF: IsFunctionDynamic 0x%p.\n",
6419 // Verify parameters.
6422 if (functionId == NULL)
6424 return E_INVALIDARG;
6427 MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6429 if (pMethDesc == NULL)
6431 return E_INVALIDARG;
6434 // it's not safe to examine a methoddesc that has not been restored so do not do so
6435 if (!pMethDesc->IsRestored())
6436 return CORPROF_E_DATAINCOMPLETE;
6439 // Fill in the pHasNoMetadata, if desired.
6441 if (isDynamic != NULL)
6443 *isDynamic = pMethDesc->IsNoMetadata();
6450 * GetFunctionFromIP3
6452 * This function takes an IP and determines if it is a managed function returning its
6453 * FunctionID. This method is different from GetFunctionFromIP in that will return
6454 * FunctionIDs even if they have no associated metadata.
6457 * ip - The instruction pointer.
6458 * pFunctionId - An optional parameter for returning the FunctionID.
6459 * pReJitId - The ReJIT id.
6462 * S_OK if successful.
6464 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP3(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
6470 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6471 // which can switch us to preemptive mode and trigger GCs
6474 EE_THREAD_NOT_REQUIRED;
6476 // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6483 // See code:#DisableLockOnAsyncCalls
6484 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6486 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6487 kP2EEAllowableAfterAttach | kP2EETriggers,
6490 "**PROF: GetFunctionFromIP3 0x%p.\n",
6495 EECodeInfo codeInfo;
6497 hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ FALSE);
6505 *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
6508 if (pReJitId != NULL)
6510 MethodDesc * pMD = codeInfo.GetMethodDesc();
6511 *pReJitId = pMD->GetReJitManager()->GetReJitId(pMD, codeInfo.GetStartAddress());
6518 * GetDynamicFunctionInfo
6520 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6521 * or LCG method and gives information about it without failing like GetFunctionInfo.
6524 * functionId - The function that is being requested.
6525 * pModuleId - An optional parameter for returning the module of the function.
6526 * ppvSig - An optional parameter for returning the signature of the function.
6527 * pbSig - An optional parameter for returning the size of the signature of the function.
6528 * cchName - A parameter for indicating the size of buffer for the wszName parameter.
6529 * pcchName - An optional parameter for returning the true size of the wszName parameter.
6530 * wszName - A parameter to the caller allocated buffer of size cchName
6533 * S_OK if successful.
6535 HRESULT ProfToEEInterfaceImpl::GetDynamicFunctionInfo(FunctionID functionId,
6536 ModuleID *pModuleId,
6537 PCCOR_SIGNATURE* ppvSig,
6541 __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[])
6548 EE_THREAD_NOT_REQUIRED;
6550 // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6551 // reads metadata which causes us to take a reader lock. However, see
6552 // code:#DisableLockOnAsyncCalls
6553 DISABLED(CAN_TAKE_LOCK);
6555 // Asynchronous functions can be called at arbitrary times when runtime
6556 // is holding locks that cannot be reentered without causing deadlock.
6557 // This contract detects any attempts to reenter locks held at the time
6558 // this function was called.
6563 PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6564 PRECONDITION(CheckPointer(ppvSig, NULL_OK));
6565 PRECONDITION(CheckPointer(pbSig, NULL_OK));
6566 PRECONDITION(CheckPointer(pcchName, NULL_OK));
6570 // See code:#DisableLockOnAsyncCalls
6571 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6573 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6576 "**PROF: GetDynamicFunctionInfo 0x%p.\n",
6580 // Verify parameters.
6583 if (functionId == NULL)
6585 return E_INVALIDARG;
6588 MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6590 if (pMethDesc == NULL)
6592 return E_INVALIDARG;
6595 // it's not safe to examine a methoddesc that has not been restored so do not do so
6596 if (!pMethDesc->IsRestored())
6597 return CORPROF_E_DATAINCOMPLETE;
6600 if (!pMethDesc->IsNoMetadata())
6601 return E_INVALIDARG;
6604 // Fill in the ModuleId, if desired.
6606 if (pModuleId != NULL)
6608 *pModuleId = (ModuleID)pMethDesc->GetModule();
6612 // Fill in the ppvSig and pbSig, if desired
6614 if (ppvSig != NULL && pbSig != NULL)
6616 pMethDesc->GetSig(ppvSig, pbSig);
6623 if (wszName != NULL)
6625 if (pcchName != NULL)
6629 ss.SetUTF8(pMethDesc->GetName());
6631 LPCWSTR methodName = ss.GetUnicode();
6633 ULONG trueLen = (ULONG)(wcslen(methodName) + 1);
6635 // Return name of method as required.
6636 if (wszName && cchName > 0)
6638 if (cchName < trueLen)
6640 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6644 wcsncpy_s(wszName, cchName, methodName, trueLen);
6648 // If they request the actual length of the name
6650 *pcchName = trueLen;
6652 EX_CATCH_HRESULT(hr);
6660 * This function describes to a profiler the internal layout of a string.
6663 * pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
6664 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
6665 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
6668 * S_OK if successful.
6670 HRESULT ProfToEEInterfaceImpl::GetStringLayout(ULONG *pBufferLengthOffset,
6671 ULONG *pStringLengthOffset,
6672 ULONG *pBufferOffset)
6686 EE_THREAD_NOT_REQUIRED;
6693 PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
6694 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
6695 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
6699 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
6702 "**PROF: GetStringLayout.\n"));
6704 return this->GetStringLayoutHelper(pBufferLengthOffset, pStringLengthOffset, pBufferOffset);
6710 * This function describes to a profiler the internal layout of a string.
6713 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
6714 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
6717 * S_OK if successful.
6719 HRESULT ProfToEEInterfaceImpl::GetStringLayout2(ULONG *pStringLengthOffset,
6720 ULONG *pBufferOffset)
6734 EE_THREAD_NOT_REQUIRED;
6741 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
6742 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
6746 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
6749 "**PROF: GetStringLayout2.\n"));
6751 ULONG dummyBufferLengthOffset;
6752 return this->GetStringLayoutHelper(&dummyBufferLengthOffset, pStringLengthOffset, pBufferOffset);
6756 * GetStringLayoutHelper
6758 * This function describes to a profiler the internal layout of a string.
6761 * pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
6762 * pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
6763 * pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
6766 * S_OK if successful.
6768 HRESULT ProfToEEInterfaceImpl::GetStringLayoutHelper(ULONG *pBufferLengthOffset,
6769 ULONG *pStringLengthOffset,
6770 ULONG *pBufferOffset)
6784 EE_THREAD_NOT_REQUIRED;
6791 PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
6792 PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
6793 PRECONDITION(CheckPointer(pBufferOffset, NULL_OK));
6797 // The String class no longer has a bufferLength field in it.
6798 // We are returning the offset of the stringLength because that is the closest we can get
6799 // This is most certainly a breaking change and a new method
6800 // ICorProfilerInfo3::GetStringLayout2 has been added on the interface ICorProfilerInfo3
6801 if (pBufferLengthOffset != NULL)
6803 *pBufferLengthOffset = StringObject::GetStringLengthOffset();
6806 if (pStringLengthOffset != NULL)
6808 *pStringLengthOffset = StringObject::GetStringLengthOffset();
6811 if (pBufferOffset != NULL)
6813 *pBufferOffset = StringObject::GetBufferOffset();
6822 * This function describes to a profiler the internal layout of a class.
6825 * classID - The class that is being queried. It is really a TypeHandle.
6826 * rFieldOffset - An array to store information about each field in the class.
6827 * cFieldOffset - Count of the number of elements in rFieldOffset.
6828 * pcFieldOffset - Upon return contains the number of elements filled in, or if
6829 * cFieldOffset is zero, the number of elements needed.
6830 * pulClassSize - Optional parameter for containing the size in bytes of the underlying
6831 * internal class structure.
6834 * S_OK if successful.
6836 HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID,
6837 COR_FIELD_OFFSET rFieldOffset[],
6839 ULONG *pcFieldOffset,
6840 ULONG *pulClassSize)
6854 EE_THREAD_NOT_REQUIRED;
6861 PRECONDITION(CheckPointer(rFieldOffset, NULL_OK));
6862 PRECONDITION(CheckPointer(pcFieldOffset));
6863 PRECONDITION(CheckPointer(pulClassSize, NULL_OK));
6867 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6870 "**PROF: GetClassLayout 0x%p.\n",
6874 // Verify parameters
6876 if ((pcFieldOffset == NULL) || (classID == NULL))
6878 return E_INVALIDARG;
6881 if ((cFieldOffset != 0) && (rFieldOffset == NULL))
6883 return E_INVALIDARG;
6886 TypeHandle typeHandle = TypeHandle::FromPtr((void *)classID);
6889 // This is the incorrect API for arrays or strings. Use GetArrayObjectInfo, and GetStringLayout
6891 if (typeHandle.IsTypeDesc() || typeHandle.AsMethodTable()->IsArray())
6893 return E_INVALIDARG;
6897 // We used to have a bug where this API incorrectly succeeded for strings during startup. Profilers
6898 // took dependency on this bug. Let the API to succeed for strings during startup for backward compatibility.
6900 if (typeHandle.AsMethodTable()->IsString() && g_profControlBlock.fBaseSystemClassesLoaded)
6902 return E_INVALIDARG;
6906 // If this class is not fully restored, that is all the information we can get at this time.
6908 if (!typeHandle.IsRestored())
6910 return CORPROF_E_DATAINCOMPLETE;
6913 // Types can be pre-restored, but they still aren't expected to handle queries before
6914 // eager fixups have run. This is a targetted band-aid for a bug intellitrace was
6915 // running into - attempting to get the class layout for all types at module load time.
6916 // If we don't detect this the runtime will AV during the field iteration below. Feel
6917 // free to eliminate this check when a more complete solution is available.
6918 if (CORCOMPILE_IS_POINTER_TAGGED(*(typeHandle.AsMethodTable()->GetParentMethodTablePtr())))
6920 return CORPROF_E_DATAINCOMPLETE;
6923 // !IsValueType = IsArray || IsReferenceType Since IsArry has been ruled out above, it must
6924 // be a reference type if !IsValueType.
6925 BOOL fReferenceType = !typeHandle.IsValueType();
6928 // Fill in class size now
6930 // Move after the check for typeHandle.GetMethodTable()->IsRestored()
6931 // because an unrestored MethodTable may have a bad EE class pointer
6932 // which will be used by MethodTable::GetNumInstanceFieldBytes
6934 if (pulClassSize != NULL)
6938 // aligned size including the object header for reference types
6939 *pulClassSize = typeHandle.GetMethodTable()->GetBaseSize();
6943 // unboxed and unaligned size for value types
6944 *pulClassSize = typeHandle.GetMethodTable()->GetNumInstanceFieldBytes();
6948 ApproxFieldDescIterator fieldDescIterator(typeHandle.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
6950 ULONG cFields = fieldDescIterator.Count();
6953 // If they are looking to just get the count, return that.
6955 if ((cFieldOffset == 0) || (rFieldOffset == NULL))
6957 *pcFieldOffset = cFields;
6962 // Dont put too many in the array.
6964 if (cFields > cFieldOffset)
6966 cFields = cFieldOffset;
6969 *pcFieldOffset = cFields;
6972 // Now fill in the array
6977 for (i = 0; i < cFields; i++)
6979 pField = fieldDescIterator.Next();
6980 rFieldOffset[i].ridOfField = (ULONG)pField->GetMemberDef();
6981 rFieldOffset[i].ulOffset = (ULONG)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
6988 typedef struct _PROFILER_STACK_WALK_DATA
6990 StackSnapshotCallback *callback;
6992 ULONG32 contextFlags;
6995 #ifdef WIN64EXCEPTIONS
6996 StackFrame sfParent;
6998 } PROFILER_STACK_WALK_DATA;
7002 * ProfilerStackWalkCallback
7004 * This routine is used as the callback from the general stack walker for
7005 * doing snapshot stack walks
7008 StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_DATA *pData)
7013 NOTHROW; // throw is RIGHT out... the throw at minimum allocates the thrown object which we *must* not do
7014 GC_NOTRIGGER; // the stack is not necessarily crawlable at this state !!!) we must not induce a GC
7018 MethodDesc *pFunc = pCf->GetFunction();
7020 COR_PRF_FRAME_INFO_INTERNAL frameInfo;
7021 ULONG32 contextSize = 0;
7022 BYTE *context = NULL;
7024 UINT_PTR currentIP = 0;
7025 REGDISPLAY *pRegDisplay = pCf->GetRegisterSet();
7026 #if defined(_TARGET_X86_)
7027 CONTEXT builtContext;
7031 // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want
7032 // to return to the profiler as the context seed if it wants to walk the unmanaged
7033 // stack frame, so we report the functionId as NULL to indicate this.
7035 if (pCf->IsNativeMarker())
7041 // Skip all Lightweight reflection/emit functions
7043 if ((pFunc != NULL) && pFunc->IsNoMetadata())
7045 return SWA_CONTINUE;
7049 // If this is not a transition of any sort and not a managed
7050 // method, ignore it.
7052 if (!pCf->IsNativeMarker() && !pCf->IsFrameless())
7054 return SWA_CONTINUE;
7057 currentIP = (UINT_PTR)pRegDisplay->ControlPC;
7059 frameInfo.size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
7060 frameInfo.version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
7064 frameInfo.funcID = MethodDescToFunctionID(pFunc);
7065 frameInfo.extraArg = NULL;
7069 frameInfo.funcID = NULL;
7070 frameInfo.extraArg = NULL;
7073 frameInfo.IP = currentIP;
7074 frameInfo.thisArg = NULL;
7076 if (pData->infoFlags & COR_PRF_SNAPSHOT_REGISTER_CONTEXT)
7078 #if defined(_TARGET_X86_)
7080 // X86 stack walking does not keep the context up-to-date during the
7081 // walk. Instead it keeps the REGDISPLAY up-to-date. Thus, we need to
7082 // build a CONTEXT from the REGDISPLAY.
7085 memset(&builtContext, 0, sizeof(builtContext));
7086 builtContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
7087 CopyRegDisplay(pRegDisplay, NULL, &builtContext);
7088 context = (BYTE *)(&builtContext);
7090 context = (BYTE *)pRegDisplay->pCurrentContext;
7092 contextSize = sizeof(CONTEXT);
7095 // NOTE: We are intentionally not setting any callback state flags here (i.e., not using
7096 // SetCallbackStateFlagsHolder), as we want the DSS callback to "inherit" the
7097 // same callback state that DSS has: if DSS was called asynchronously, then consider
7098 // the DSS callback to be called asynchronously.
7099 if (pData->callback(frameInfo.funcID,
7101 (COR_PRF_FRAME_INFO)&frameInfo,
7104 pData->clientData) == S_OK)
7106 return SWA_CONTINUE;
7114 //---------------------------------------------------------------------------------------
7115 // Normally, calling GetFunction() on the frame is sufficient to ensure
7116 // HelperMethodFrames are intialized. However, sometimes we need to be able to specify
7117 // that we should not enter the host while initializing, so we need to initialize such
7118 // frames more directly. This small helper function directly forces the initialization,
7119 // and ensures we don't enter the host as a result if we're executing in an asynchronous
7120 // call (i.e., hijacked thread)
7123 // pFrame - Frame to initialize.
7126 // TRUE iff pFrame was successfully initialized (or was already initialized). If
7127 // pFrame is not a HelperMethodFrame (or derived type), this returns TRUE
7128 // immediately. FALSE indicates we tried to initialize w/out entering the host, and
7129 // had to abort as a result when a reader lock was needed but unavailable.
7132 static BOOL EnsureFrameInitialized(Frame * pFrame)
7139 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7140 // host (SQL). Corners will be cut to ensure this is the case
7141 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7147 if (pFrame->GetFrameType() != Frame::TYPE_HELPER_METHOD_FRAME)
7149 // This frame is not a HelperMethodFrame or a frame derived from
7150 // HelperMethodFrame, so HMF-specific lazy initialization is not an issue.
7154 HelperMethodFrame * pHMF = (HelperMethodFrame *) pFrame;
7156 if (pHMF->InsureInit(
7157 false, // initialInit
7158 NULL, // unwindState
7159 (ShouldAvoidHostCalls() ?
7164 // InsureInit() succeeded and found the return address
7168 // No return address was found. It must be because we asked InsureInit() to bail if
7169 // it would have entered the host
7170 _ASSERTE(ShouldAvoidHostCalls());
7174 //---------------------------------------------------------------------------------------
7176 // Implements the COR_PRF_SNAPSHOT_X86_OPTIMIZED algorithm called by DoStackSnapshot.
7177 // Does a simple EBP walk, rather than invoking all of StackWalkFramesEx.
7180 // pThreadToSnapshot - Thread whose stack should be walked
7181 // pctxSeed - Register context with which to seed the walk
7182 // callback - Function to call at each frame found during the walk
7183 // clientData - Parameter to pass through to callback
7186 // HRESULT indicating success or failure.
7189 HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
7190 Thread * pThreadToSnapshot,
7192 StackSnapshotCallback * callback,
7200 EE_THREAD_NOT_REQUIRED;
7202 // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7203 // host (SQL). Corners will be cut to ensure this is the case
7204 if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7210 // We haven't set the stackwalker thread type flag yet (see next line), so it shouldn't be set. Only
7211 // exception to this is if the current call is made by a hijacking profiler which
7212 // redirected this thread while it was previously in the middle of another stack walk
7213 _ASSERTE(IsCalledAsynchronously() || !IsStackWalkerThread());
7215 // Remember that we're walking the stack. This holder will reinstate the original
7216 // value of the stackwalker flag (from the thread type mask) in its destructor.
7217 ClrFlsValueSwitch _threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThreadToSnapshot);
7219 // This flag remembers if we reported a managed frame since the last unmanaged block
7220 // we reported. It's used to avoid reporting two unmanaged blocks in a row.
7221 BOOL fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7223 Frame * pFrameCur = pThreadToSnapshot->GetFrame();
7226 ZeroMemory(&ctxCur, sizeof(ctxCur));
7228 // Use seed if we got one. Otherwise, EE explicit Frame chain will seed the walk.
7229 if (pctxSeed != NULL)
7231 ctxCur.Ebp = pctxSeed->Ebp;
7232 ctxCur.Eip = pctxSeed->Eip;
7233 ctxCur.Esp = pctxSeed->Esp;
7238 // At each iteration of the loop:
7239 // * Analyze current frame (get managed data if it's a managed frame)
7240 // * Report current frame via callback()
7241 // * Walk down to next frame
7243 // **** Managed or unmanaged frame? ****
7245 EECodeInfo codeInfo;
7246 MethodDesc * pMethodDescCur = NULL;
7248 if (ctxCur.Eip != 0)
7250 hr = GetFunctionInfoInternal(
7251 (LPCBYTE) ctxCur.Eip,
7253 if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
7255 _ASSERTE(ShouldAvoidHostCalls());
7260 pMethodDescCur = codeInfo.GetMethodDesc();
7264 // **** Report frame to profiler ****
7267 // Make sure the frame gave us an IP
7268 (ctxCur.Eip != 0) &&
7270 // Make sure any managed frame isn't for an IL stub or LCG
7271 ((pMethodDescCur == NULL) || !pMethodDescCur->IsNoMetadata()) &&
7273 // Only report unmanaged frames if the last frame we reported was managed
7274 // (avoid reporting two unmanaged blocks in a row)
7275 ((pMethodDescCur != NULL) || fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock))
7277 // Around the call to the profiler, temporarily clear the
7278 // ThreadType_StackWalker type flag, as we have no control over what the
7279 // profiler may do inside its callback (it could theoretically attempt to
7280 // load other types, though I don't personally know of profilers that
7281 // currently do this).
7283 CLEAR_THREAD_TYPE_STACKWALKER();
7285 (FunctionID) pMethodDescCur,
7287 NULL, // COR_PRF_FRAME_INFO
7288 sizeof(ctxCur), // contextSize,
7289 (LPBYTE) &ctxCur, // context,
7291 SET_THREAD_TYPE_STACKWALKER(pThreadToSnapshot);
7297 if (pMethodDescCur == NULL)
7299 // Just reported an unmanaged block, so reset the flag
7300 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7304 // Just reported a managed block, so remember it
7305 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = TRUE;
7309 // **** Walk down to next frame ****
7311 // Is current frame managed or unmanaged?
7312 if (pMethodDescCur == NULL)
7314 // Unmanaged frame. Use explicit EE Frame chain to help
7317 ZeroMemory(&frameRD, sizeof(frameRD));
7319 while (pFrameCur != FRAME_TOP)
7321 // Frame is only useful if it will contain register context info
7322 if (!pFrameCur->NeedsUpdateRegDisplay())
7328 // This should be the first call we make to the Frame, as it will
7329 // ensure we force lazy initialize of HelperMethodFrames
7330 if (!EnsureFrameInitialized(pFrameCur))
7332 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7335 // This frame is only useful if it gives us an actual return address,
7336 // and is situated on the stack at or below our current ESP (stack
7338 if ((pFrameCur->GetReturnAddress() != NULL) &&
7339 (dac_cast<TADDR>(pFrameCur) >= dac_cast<TADDR>(ctxCur.Esp)))
7341 pFrameCur->UpdateRegDisplay(&frameRD);
7346 pFrameCur = pFrameCur->PtrNextFrame();
7349 if (pFrameCur == FRAME_TOP)
7351 // No more frames. Stackwalk is over
7355 // Update ctxCur based on frame
7356 ctxCur.Eip = pFrameCur->GetReturnAddress();
7357 ctxCur.Ebp = GetRegdisplayFP(&frameRD);
7358 ctxCur.Esp = GetRegdisplaySP(&frameRD);
7364 // GC info will assist us in determining whether this is a non-EBP frame and
7365 // info about pushed arguments.
7366 GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
7367 PTR_VOID gcInfo = gcInfoToken.Info;
7369 unsigned uiMethodSizeDummy;
7370 PTR_CBYTE table = PTR_CBYTE(gcInfo);
7371 table += decodeUnsigned(table, &uiMethodSizeDummy);
7372 table = decodeHeader(table, gcInfoToken.Version, &header);
7374 // Ok, GCInfo, can we do a simple EBP walk or what?
7376 if ((codeInfo.GetRelOffset() < header.prologSize) ||
7377 (!header.ebpFrame && !header.doubleAlign))
7379 // We're either in the prolog or we're not in an EBP frame, in which case
7380 // we'll just defer to the code manager to unwind for us. This condition
7381 // is relatively rare, but can occur if:
7383 // * The profiler did a DSS from its Enter hook, in which case we're
7384 // still inside the prolog, OR
7385 // * The seed context or explicit EE Frame chain seeded us with a
7386 // non-EBP frame function. In this case, using a naive EBP
7387 // unwinding algorithm would actually skip over the next EBP
7388 // frame, and would get SP all wrong as we try skipping over
7389 // the pushed parameters. So let's just ask the code manager for
7392 // Note that there are yet more conditions (much more rare) where the EBP
7393 // walk could get lost (e.g., we're inside an epilog). But we only care
7394 // about the most likely cases, and it's ok if the unlikely cases result
7395 // in truncated stacks, as unlikely cases will be statistically
7396 // irrelevant to CPU performance sampling profilers
7397 CodeManState codeManState;
7398 codeManState.dwIsSet = 0;
7400 ZeroMemory(&rd, sizeof(rd));
7402 rd.SetEbpLocation(&ctxCur.Ebp);
7404 rd.ControlPC = ctxCur.Eip;
7406 codeInfo.GetCodeManager()->UnwindStackFrame(
7409 SpeculativeStackwalk,
7413 ctxCur.Ebp = *rd.GetEbpLocation();
7415 ctxCur.Eip = rd.ControlPC;
7419 // We're in an actual EBP frame, so we can simplistically walk down to
7420 // the next frame using EBP.
7422 // Return address is stored just below saved EBP (stack grows up)
7423 ctxCur.Eip = *(DWORD *) (ctxCur.Ebp + sizeof(DWORD));
7426 // Stack location where current function pushed its EBP
7429 // Skip past that EBP
7432 // Skip past return address pushed by caller
7435 // Skip past arguments to current function that were pushed by caller.
7436 // (Caller will pop varargs, so don't count those.)
7437 (header.varargs ? 0 : (header.argCount * sizeof(DWORD)));
7439 // EBP for frame below us (stack grows up) has been saved onto our own
7440 // frame. Dereference it now.
7441 ctxCur.Ebp = *(DWORD *) ctxCur.Ebp;
7446 #endif // _TARGET_X86_
7448 //*****************************************************************************
7449 // The profiler stackwalk Wrapper
7450 //*****************************************************************************
7451 HRESULT ProfToEEInterfaceImpl::ProfilerStackWalkFramesWrapper(Thread * pThreadToSnapshot, PROFILER_STACK_WALK_DATA * pData, unsigned flags)
7453 STATIC_CONTRACT_WRAPPER;
7455 StackWalkAction swaRet = pThreadToSnapshot->StackWalkFrames(
7456 (PSTACKWALKFRAMESCALLBACK)ProfilerStackWalkCallback,
7464 _ASSERTE(!"Unexpected StackWalkAction returned from Thread::StackWalkFrames");
7471 return CORPROF_E_STACKSNAPSHOT_ABORTED;
7478 //---------------------------------------------------------------------------------------
7480 // DoStackSnapshot helper to call FindJitMan to determine if the specified
7481 // context is in managed code.
7484 // pCtx - Context to look at
7485 // hostCallPreference - Describes how to acquire the reader lock--either AllowHostCalls
7486 // or NoHostCalls (see code:HostCallPreference).
7489 // S_OK: The context is in managed code
7490 // S_FALSE: The context is not in managed code.
7491 // Error: Unable to determine (typically because hostCallPreference was NoHostCalls
7492 // and the reader lock was unattainable without yielding)
7495 HRESULT IsContextInManagedCode(const CONTEXT * pCtx, HostCallPreference hostCallPreference)
7497 WRAPPER_NO_CONTRACT;
7498 BOOL fFailedReaderLock = FALSE;
7500 // if there's no Jit Manager for the IP, it's not managed code.
7501 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(pCtx), hostCallPreference, &fFailedReaderLock);
7502 if (fFailedReaderLock)
7504 return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7507 return fIsManagedCode ? S_OK : S_FALSE;
7510 //*****************************************************************************
7511 // Perform a stack walk, calling back to callback at each managed frame.
7512 //*****************************************************************************
7513 HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread,
7514 StackSnapshotCallback *callback,
7518 ULONG32 contextSize)
7521 #if !defined(FEATURE_HIJACK)
7523 // DoStackSnapshot needs Thread::Suspend/ResumeThread functionality.
7524 // On platforms w/o support for these APIs return E_NOTIMPL.
7527 #else // !defined(FEATURE_HIJACK)
7531 // Yay! (Note: NOTHROW is vital. The throw at minimum allocates
7532 // the thrown object which we *must* not do.)
7535 // Yay! (Note: this is called asynchronously to view the stack at arbitrary times,
7536 // so the stack is not necessarily crawlable for GC at this state!)
7543 EE_THREAD_NOT_REQUIRED;
7545 // #DisableLockOnAsyncCalls
7546 // This call is allowed asynchronously, however it does take locks. Therefore,
7547 // we will hit contract asserts if we happen to be in a CANNOT_TAKE_LOCK zone when
7548 // a hijacking profiler hijacks this thread to run DoStackSnapshot. CANNOT_RETAKE_LOCK
7549 // is a more granular locking contract that says "I promise that if I take locks, I
7550 // won't reenter any locks that were taken before this function was called".
7551 DISABLED(CAN_TAKE_LOCK);
7553 // Asynchronous functions can be called at arbitrary times when runtime
7554 // is holding locks that cannot be reentered without causing deadlock.
7555 // This contract detects any attempts to reenter locks held at the time
7556 // this function was called.
7563 // This CONTRACT_VIOLATION is still needed because DISABLED(CAN_TAKE_LOCK) does not
7564 // turn off contract violations.
7565 PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
7567 LPCONTEXT pctxSeed = reinterpret_cast<LPCONTEXT> (pbContext);
7569 PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7572 "**PROF: DoStackSnapshot 0x%p, 0x%p, 0x%08x, 0x%p, 0x%p, 0x%08x.\n",
7580 HRESULT hr = E_UNEXPECTED;
7581 // (hr assignment is to appease the rotor compiler; we won't actually return without explicitly setting hr again)
7583 Thread *pThreadToSnapshot = NULL;
7584 Thread * pCurrentThread = GetThreadNULLOk();
7585 BOOL fResumeThread = FALSE;
7586 INDEBUG(ULONG ulForbidTypeLoad = 0;)
7587 BOOL fResetSnapshotThreadExternalCount = FALSE;
7588 int cRefsSnapshotThread = 0;
7590 // Remember whether we've already determined the current context of the target thread
7591 // is in managed (S_OK), not in managed (S_FALSE), or unknown (error).
7592 HRESULT hrCurrentContextIsManaged = E_FAIL;
7595 memset(&ctxCurrent, 0, sizeof(ctxCurrent));
7599 PROFILER_STACK_WALK_DATA data;
7603 // no managed code has run and things are likely in a very bad have loaded state
7604 // this is a bad time to try to walk the stack
7606 // Returning directly as there is nothing to cleanup yet
7607 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7610 if (!CORProfilerStackSnapshotEnabled())
7612 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7613 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
7618 pThreadToSnapshot = pCurrentThread;
7622 pThreadToSnapshot = (Thread *)thread;
7626 if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT | COR_PRF_SNAPSHOT_X86_OPTIMIZED)) != 0)
7628 if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT)) != 0)
7631 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7632 return E_INVALIDARG;
7635 if (!IsManagedThread(pThreadToSnapshot) || !IsGarbageCollectorFullyInitialized())
7638 // No managed frames, return now.
7640 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7644 // We must make sure no other thread tries to hijack the thread we're about to walk
7645 // Hijacking means Thread::HijackThread, i.e. bashing return addresses which would break the stack walk
7646 Thread::HijackLockHolder hijackLockHolder(pThreadToSnapshot);
7647 if (!hijackLockHolder.Acquired())
7649 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7650 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7653 if (pThreadToSnapshot != pCurrentThread // Walking separate thread
7654 && pCurrentThread != NULL // Walker (current) thread is a managed / VM thread
7655 && ThreadSuspend::SysIsSuspendInProgress()) // EE is trying suspend itself
7657 // Since we're walking a separate thread, we'd have to suspend it first (see below).
7658 // And since the current thread is a VM thread, that means the current thread's
7659 // m_dwForbidSuspendThread count will go up while it's trying to suspend the
7660 // target thread (see Thread::SuspendThread). THAT means no one will be able
7661 // to suspend the current thread until its m_dwForbidSuspendThread is decremented
7662 // (which happens as soon as the target thread of DoStackSnapshot has been suspended).
7663 // Since we're in the process of suspending the entire runtime, now would be a bad time to
7664 // make the walker thread un-suspendable (see VsWhidbey bug 454936). So let's just abort
7665 // now. Note that there is no synchronization around calling Thread::SysIsSuspendInProgress().
7666 // So we will get occasional false positives or false negatives. But that's benign, as the worst
7667 // that might happen is we might occasionally delay the EE suspension a little bit, or we might
7668 // too eagerly fail from ProfToEEInterfaceImpl::DoStackSnapshot sometimes. But there won't
7669 // be any corruption or AV.
7671 // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7672 return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7675 // We only allow stackwalking if:
7676 // 1) Target thread to walk == current thread OR Target thread is suspended, AND
7677 // 2) Target thread to walk is currently executing JITted / NGENd code, AND
7678 // 3) Target thread to walk is seeded OR currently NOT unwinding the stack, AND
7679 // 4) Target thread to walk != current thread OR current thread is NOT in a can't stop or forbid suspend region
7681 // If the thread is in a forbid suspend region, it's dangerous to do anything:
7682 // - The code manager datastructures accessed during the stackwalk may be in inconsistent state.
7683 // - Thread::Suspend won't be able to suspend the thread.
7684 if (pThreadToSnapshot->IsInForbidSuspendRegion())
7686 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
7690 HostCallPreference hostCallPreference;
7692 // First, check "1) Target thread to walk == current thread OR Target thread is suspended"
7693 if (pThreadToSnapshot != pCurrentThread)
7695 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7699 // Walking separate thread, so it must be suspended. First, ensure that
7700 // target thread exists.
7702 // NOTE: We're using the "dangerous" variant of this refcount function, because we
7703 // rely on the profiler to ensure it never tries to walk a thread being destroyed.
7704 // (Profiler must block in its ThreadDestroyed() callback until all uses of that thread,
7705 // such as walking its stack, are complete.)
7706 cRefsSnapshotThread = pThreadToSnapshot->IncExternalCountDANGEROUSProfilerOnly();
7707 fResetSnapshotThreadExternalCount = TRUE;
7709 if (cRefsSnapshotThread == 1 || !pThreadToSnapshot->HasValidThreadHandle())
7711 // At this point, we've modified the VM state based on bad input
7712 // (pThreadToSnapshot) from the profiler. This could cause
7713 // memory corruption and leave us vulnerable to security problems.
7714 // So destroy the process.
7715 _ASSERTE(!"Profiler trying to walk destroyed thread");
7716 EEPOLICY_HANDLE_FATAL_ERROR(CORPROF_E_STACKSNAPSHOT_INVALID_TGT_THREAD);
7719 // Thread::SuspendThread() ensures that no one else should try to suspend us
7720 // while we're suspending pThreadToSnapshot.
7722 // TRUE: OneTryOnly. Don't loop waiting for others to get out of our way in
7723 // order to suspend the thread. If it's not safe, just return an error immediately.
7724 Thread::SuspendThreadResult str = pThreadToSnapshot->SuspendThread(TRUE);
7725 if (str == Thread::STR_Success)
7727 fResumeThread = TRUE;
7731 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
7734 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7737 hostCallPreference =
7738 ShouldAvoidHostCalls() ?
7739 NoHostCalls : // Async call: Ensure this thread won't yield & re-enter host
7740 AllowHostCalls; // Synchronous calls may re-enter host just fine
7742 // If target thread is in pre-emptive mode, the profiler's seed context is unnecessary
7743 // because our frame chain is good enough: it will give us at least as accurate a
7744 // starting point as the profiler could. Also, since profiler contexts cannot be
7745 // trusted, we don't want to set the thread's profiler filter context to this, as a GC
7746 // that interrupts the profiler's stackwalk will end up using the profiler's (potentially
7747 // bogus) filter context.
7748 if (!pThreadToSnapshot->PreemptiveGCDisabledOther())
7750 // Thread to be walked is in preemptive mode. Throw out seed.
7753 else if (pThreadToSnapshot != pCurrentThread)
7755 // With cross-thread stack-walks, the target thread's context could be unreliable.
7756 // That would shed doubt on either a profiler-provided context, or a default
7757 // context we chose. So check if we're in a potentially unreliable case, and return
7760 // These heurisitics are based on an actual bug where GetThreadContext returned a
7761 // self-consistent, but stale, context for a thread suspended after being redirected by
7762 // the GC (TFS Dev 10 bug # 733263).
7764 // (Note that this whole block is skipped if pThreadToSnapshot is in preemptive mode (the IF
7765 // above), as the context is unused in such a case--the EE Frame chain is used
7766 // to seed the walk instead.)
7767 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7771 if (!pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
7773 LOG((LF_CORPROF, LL_INFO100, "**PROF: GetSafelyRedirectableThreadContext failure leads to CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
7774 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
7778 hrCurrentContextIsManaged = IsContextInManagedCode(&ctxCurrent, hostCallPreference);
7779 if (FAILED(hrCurrentContextIsManaged))
7781 // Couldn't get the info. Try again later
7782 _ASSERTE(ShouldAvoidHostCalls());
7783 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
7787 if ((hrCurrentContextIsManaged == S_OK) &&
7788 (!pThreadToSnapshot->PreemptiveGCDisabledOther()))
7790 // Thread is in preemptive mode while executing managed code?! This lie is
7791 // an early warning sign that the context is bogus. Bail.
7792 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus. Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
7793 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
7797 Frame * pFrame = pThreadToSnapshot->GetFrame();
7798 if (pFrame != FRAME_TOP)
7800 TADDR spTargetThread = GetSP(&ctxCurrent);
7801 if (dac_cast<TADDR>(pFrame) < spTargetThread)
7803 // An Explicit EE Frame is more recent on the stack than the current
7804 // stack pointer itself? This lie is an early warning sign that the
7805 // context is bogus. Bail.
7806 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus. Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
7807 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
7812 // If the profiler did not specify a seed context of its own, use the current one we
7815 // Failing to seed the walk can cause us to to "miss" functions on the stack. This is
7816 // because StackWalkFrames(), when doing an unseeded stackwalk, sets the
7817 // starting regdisplay's IP/SP to 0. This, in turn causes StackWalkFramesEx
7818 // to set cf.isFrameless = (pEEJM != NULL); (which is FALSE, since we have no
7819 // jit manager, since we have no IP). Once frameless is false, we look solely to
7820 // the Frame chain for our goodies, rather than looking at the code actually
7821 // being executed by the thread. The problem with the frame chain is that some
7822 // frames (e.g., GCFrame) don't point to any functions being executed. So
7823 // StackWalkFramesEx just skips such frames and moves to the next one. That
7824 // can cause a chunk of calls to be skipped. To prevent this from happening, we
7825 // "fake" a seed by just seeding the thread with its current context. This forces
7826 // StackWalkFramesEx() to look at the IP rather than just the frame chain.
7827 if (pctxSeed == NULL)
7829 pctxSeed = &ctxCurrent;
7831 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7834 // Second, check "2) Target thread to walk is currently executing JITted / NGENd code"
7835 // To do this, we need to find the proper context to investigate. Start with
7836 // the seeded context, if available. If not, use the target thread's current context.
7837 if (pctxSeed != NULL)
7839 BOOL fSeedIsManaged;
7841 // Short cut: If we're just using the current context as the seed, we may
7842 // already have determined whether it's in managed code. If so, just use that
7843 // result rather than calculating it again
7844 if ((pctxSeed == &ctxCurrent) && SUCCEEDED(hrCurrentContextIsManaged))
7846 fSeedIsManaged = (hrCurrentContextIsManaged == S_OK);
7850 hr = IsContextInManagedCode(pctxSeed, hostCallPreference);
7853 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
7856 fSeedIsManaged = (hr == S_OK);
7859 if (!fSeedIsManaged)
7861 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
7868 // Sanity check: If we are doing a cross-thread walk and there is no seed context, then
7869 // we better not be in managed code, otw we do not have a Frame on the stack from which to start
7870 // walking and we may miss the leaf-most chain of managed calls due to the way StackWalkFrames
7871 // is implemented. However, there is an exception when the leaf-most EE frame of pThreadToSnapshot
7872 // is an InlinedCallFrame, which has an active call, implying pThreadToShanpshot is inside an
7873 // inlined P/Invoke. In this case, the InlinedCallFrame will be used to help start off our
7874 // stackwalk at the top of the stack.
7876 if (pThreadToSnapshot != pCurrentThread)
7878 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7882 if (pctxSeed == NULL)
7884 if (pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
7886 BOOL fFailedReaderLock = FALSE;
7887 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(&ctxCurrent), hostCallPreference, &fFailedReaderLock);
7889 if (!fFailedReaderLock)
7891 // not in jitted or ngend code or inside an inlined P/Invoke (the leaf-most EE Frame is
7892 // an InlinedCallFrame with an active call)
7893 _ASSERTE(!fIsManagedCode ||
7894 (InlinedCallFrame::FrameHasActiveCall(pThreadToSnapshot->GetFrame())));
7898 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7901 // Third, verify the target thread is seeded or not in the midst of an unwind.
7902 if (pctxSeed == NULL)
7904 ThreadExceptionState* pExState = pThreadToSnapshot->GetExceptionState();
7906 // this tests to see if there is an exception in flight
7907 if (pExState->IsExceptionInProgress() && pExState->GetFlags()->UnwindHasStarted())
7909 EHClauseInfo *pCurrentEHClauseInfo = pThreadToSnapshot->GetExceptionState()->GetCurrentEHClauseInfo();
7911 // if the exception code is telling us that we have entered a managed context then all is well
7912 if (!pCurrentEHClauseInfo->IsManagedCodeEntered())
7914 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
7920 // Check if the exception state is consistent. See the comment for ThreadExceptionFlag for more information.
7921 if (pThreadToSnapshot->GetExceptionState()->HasThreadExceptionFlag(ThreadExceptionState::TEF_InconsistentExceptionState))
7923 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
7927 data.callback = callback;
7928 data.infoFlags = infoFlags;
7929 data.contextFlags = 0;
7930 data.clientData = clientData;
7931 #ifdef WIN64EXCEPTIONS
7932 data.sfParent.Clear();
7935 // workaround: The ForbidTypeLoad book keeping in the stackwalker is not robust against exceptions.
7936 // Unfortunately, it is hard to get it right in the stackwalker since it has to be exception
7937 // handling free (frame unwinding may never return). We restore the ForbidTypeLoad counter here
7938 // in case it got messed up by exception thrown during the stackwalk.
7939 INDEBUG(if (pCurrentThread) ulForbidTypeLoad = pCurrentThread->m_ulForbidTypeLoad;)
7942 // An AV during a profiler stackwalk is an isolated event and shouldn't bring
7943 // down the runtime. Need to place the holder here, outside of ProfilerStackWalkFramesWrapper
7944 // since ProfilerStackWalkFramesWrapper uses __try, which doesn't like objects
7945 // with destructors.
7946 AVInRuntimeImplOkayHolder AVOkay;
7948 hr = DoStackSnapshotHelper(
7951 HANDLESKIPPEDFRAMES |
7953 NOTIFY_ON_U2M_TRANSITIONS |
7954 ((pThreadToSnapshot == pCurrentThread) ?
7956 ALLOW_ASYNC_STACK_WALK | THREAD_IS_SUSPENDED) |
7957 THREAD_EXECUTING_MANAGED_CODE |
7958 PROFILER_DO_STACK_SNAPSHOT |
7959 ALLOW_INVALID_OBJECTS, // stack walk logic should not look at objects - we could be in the middle of a gc.
7963 INDEBUG(if (pCurrentThread) pCurrentThread->m_ulForbidTypeLoad = ulForbidTypeLoad;)
7966 #if defined(PLATFORM_SUPPORTS_SAFE_THREADSUSPEND)
7969 pThreadToSnapshot->ResumeThread();
7971 #endif // PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7972 if (fResetSnapshotThreadExternalCount)
7974 pThreadToSnapshot->DecExternalCountDANGEROUSProfilerOnly();
7979 #endif // !defined(FEATURE_HIJACK)
7983 //---------------------------------------------------------------------------------------
7985 // Exception swallowing wrapper around the profiler stackwalk
7988 // pThreadToSnapshot - Thread whose stack should be walked
7989 // pData - data for stack walker
7990 // flags - flags parameter to pass to StackWalkFramesEx, and StackFrameIterator
7991 // pctxSeed - Register context with which to seed the walk
7994 // HRESULT indicating success or failure.
7996 HRESULT ProfToEEInterfaceImpl::DoStackSnapshotHelper(Thread * pThreadToSnapshot,
7997 PROFILER_STACK_WALK_DATA * pData,
8001 STATIC_CONTRACT_NOTHROW;
8003 // We want to catch and swallow AVs here. For example, if the profiler gives
8004 // us a bogus seed context (this happens), we could AV when inspecting memory pointed to
8005 // by the (bogus) EBP register.
8007 // EX_TRY/EX_CATCH does a lot of extras that we do not need and that can go wrong for us.
8008 // E.g. It asserts in debug build for AVs in mscorwks or it synthetizes an object for the exception.
8009 // We use a plain PAL_TRY/PAL_EXCEPT since it is all we need.
8012 Thread * pThreadToSnapshot;
8013 PROFILER_STACK_WALK_DATA * pData;
8015 ProfToEEInterfaceImpl * pProfToEE;
8017 BOOL fResetProfilerFilterContext;
8021 param.hr = E_UNEXPECTED;
8022 param.pThreadToSnapshot = pThreadToSnapshot;
8023 param.pData = pData;
8024 param.flags = flags;
8025 param.pProfToEE = this;
8026 param.pctxSeed = pctxSeed;
8027 param.fResetProfilerFilterContext = FALSE;
8029 PAL_TRY(Param *, pParam, ¶m)
8031 if ((pParam->pData->infoFlags & COR_PRF_SNAPSHOT_X86_OPTIMIZED) != 0)
8033 #ifndef _TARGET_X86_
8034 // If check in the begining of DoStackSnapshot (to return E_INVALIDARG) should
8035 // make this unreachable
8036 _ASSERTE(!"COR_PRF_SNAPSHOT_X86_OPTIMIZED on non-X86 should be unreachable!");
8038 // New, simple EBP walker
8039 pParam->hr = pParam->pProfToEE->ProfilerEbpWalker(
8040 pParam->pThreadToSnapshot,
8042 pParam->pData->callback,
8043 pParam->pData->clientData);
8044 #endif // _TARGET_X86_
8048 // We're now fairly confident the stackwalk should be ok, so set
8049 // the context seed, if one was provided or cooked up.
8050 if (pParam->pctxSeed != NULL)
8052 pParam->pThreadToSnapshot->SetProfilerFilterContext(pParam->pctxSeed);
8053 pParam->fResetProfilerFilterContext = TRUE;
8056 // Whidbey-style walker, uses StackWalkFramesEx
8057 pParam->hr = pParam->pProfToEE->ProfilerStackWalkFramesWrapper(
8058 pParam->pThreadToSnapshot,
8063 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8065 param.hr = E_UNEXPECTED;
8069 // Undo the context seeding & thread suspend we did (if any)
8070 // to ensure that the thread we walked stayed suspended
8071 if (param.fResetProfilerFilterContext)
8073 pThreadToSnapshot->SetProfilerFilterContext(NULL);
8080 HRESULT ProfToEEInterfaceImpl::GetGenerationBounds(ULONG cObjectRanges,
8081 ULONG *pcObjectRanges,
8082 COR_PRF_GC_GENERATION_RANGE ranges[])
8096 EE_THREAD_NOT_REQUIRED;
8103 PRECONDITION(CheckPointer(pcObjectRanges));
8104 PRECONDITION(cObjectRanges <= 0 || ranges != NULL);
8105 PRECONDITION(s_generationTableLock >= 0);
8109 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8112 "**PROF: GetGenerationBounds.\n"));
8114 // Announce we are using the generation table now
8115 CounterHolder genTableLock(&s_generationTableLock);
8117 GenerationTable *generationTable = s_currentGenerationTable;
8119 if (generationTable == NULL)
8124 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8126 GenerationDesc *genDescTable = generationTable->genDescTable;
8127 ULONG count = min(generationTable->count, cObjectRanges);
8128 for (ULONG i = 0; i < count; i++)
8130 ranges[i].generation = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8131 ranges[i].rangeStart = (ObjectID)genDescTable[i].rangeStart;
8132 ranges[i].rangeLength = genDescTable[i].rangeEnd - genDescTable[i].rangeStart;
8133 ranges[i].rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8136 *pcObjectRanges = generationTable->count;
8142 HRESULT ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo(COR_PRF_EX_CLAUSE_INFO * pinfo)
8160 PRECONDITION(CheckPointer(pinfo));
8164 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
8166 "**PROF: GetNotifiedExceptionClauseInfo.\n"));
8170 ThreadExceptionState* pExState = NULL;
8171 EHClauseInfo* pCurrentEHClauseInfo = NULL;
8173 // notification requires that we are on a managed thread with an exception in flight
8174 Thread *pThread = GetThread();
8176 // If pThread is null, then the thread has never run managed code
8177 if (pThread == NULL)
8179 hr = CORPROF_E_NOT_MANAGED_THREAD;
8183 pExState = pThread->GetExceptionState();
8184 if (!pExState->IsExceptionInProgress())
8186 // no exception is in flight -- successful failure
8191 pCurrentEHClauseInfo = pExState->GetCurrentEHClauseInfo();
8192 if (pCurrentEHClauseInfo->GetClauseType() == COR_PRF_CLAUSE_NONE)
8194 // no exception is in flight -- successful failure
8199 pinfo->clauseType = pCurrentEHClauseInfo->GetClauseType();
8200 pinfo->programCounter = pCurrentEHClauseInfo->GetIPForEHClause();
8201 pinfo->framePointer = pCurrentEHClauseInfo->GetFramePointerForEHClause();
8202 pinfo->shadowStackPointer = 0;
8207 memset(pinfo, 0, sizeof(*pinfo));
8212 HRESULT ProfToEEInterfaceImpl::GetObjectGeneration(ObjectID objectId,
8213 COR_PRF_GC_GENERATION_RANGE *range)
8227 EE_THREAD_NOT_REQUIRED;
8234 PRECONDITION(objectId != NULL);
8235 PRECONDITION(CheckPointer(range));
8236 PRECONDITION(s_generationTableLock >= 0);
8240 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8243 "**PROF: GetObjectGeneration 0x%p.\n",
8246 BEGIN_GETTHREAD_ALLOWED;
8247 _ASSERTE((GetThread() == NULL) || (GetThread()->PreemptiveGCDisabled()));
8248 END_GETTHREAD_ALLOWED;
8250 // Announce we are using the generation table now
8251 CounterHolder genTableLock(&s_generationTableLock);
8253 GenerationTable *generationTable = s_currentGenerationTable;
8255 if (generationTable == NULL)
8260 _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8262 GenerationDesc *genDescTable = generationTable->genDescTable;
8263 ULONG count = generationTable->count;
8264 for (ULONG i = 0; i < count; i++)
8266 if (genDescTable[i].rangeStart <= (BYTE *)objectId && (BYTE *)objectId < genDescTable[i].rangeEndReserved)
8268 range->generation = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8269 range->rangeStart = (ObjectID)genDescTable[i].rangeStart;
8270 range->rangeLength = genDescTable[i].rangeEnd - genDescTable[i].rangeStart;
8271 range->rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8280 HRESULT ProfToEEInterfaceImpl::GetReJITIDs(
8281 FunctionID functionId, // in
8282 ULONG cReJitIds, // in
8283 ULONG * pcReJitIds, // out
8284 ReJITID reJitIds[]) // out
8291 // taking a lock causes a GC
8297 // The rejit tables use a lock
8302 PRECONDITION(CheckPointer(pcReJitIds, NULL_OK));
8303 PRECONDITION(CheckPointer(reJitIds, NULL_OK));
8308 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
8310 "**PROF: GetReJITIDs 0x%p.\n",
8313 if (functionId == 0)
8315 return E_INVALIDARG;
8318 if ((cReJitIds == 0) || (pcReJitIds == NULL) || (reJitIds == NULL))
8320 return E_INVALIDARG;
8323 MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
8325 return pMD->GetReJitManager()->GetReJITIDs(pMD, cReJitIds, pcReJitIds, reJitIds);
8328 HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG cFunctions, // in
8329 ModuleID moduleIds[], // in
8330 mdMethodDef methodIds[]) // in
8337 // When we suspend the runtime we drop into premptive mode
8343 // We need to suspend the runtime, this takes a lot of locks!
8348 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8349 PRECONDITION(CheckPointer(methodIds, NULL_OK));
8353 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8357 "**PROF: RequestReJIT.\n"));
8359 if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
8361 return CORPROF_E_CALLBACK4_REQUIRED;
8364 if (!CORProfilerEnableRejit())
8366 return CORPROF_E_REJIT_NOT_ENABLED;
8369 // Request at least 1 method to reJIT!
8370 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8372 return E_INVALIDARG;
8375 // Remember the profiler is doing this, as that means we must never detach it!
8376 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8379 return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds);
8382 HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG cFunctions, // in
8383 ModuleID moduleIds[], // in
8384 mdMethodDef methodIds[], // in
8385 HRESULT rgHrStatuses[]) // out
8392 // The rejit manager requires a lock to iterate through methods to revert, and
8393 // taking the lock can drop us into preemptive mode.
8399 // The rejit manager requires a lock to iterate through methods to revert
8404 PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8405 PRECONDITION(CheckPointer(methodIds, NULL_OK));
8406 PRECONDITION(CheckPointer(rgHrStatuses, NULL_OK));
8410 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8414 "**PROF: RequestRevert.\n"));
8416 if (!CORProfilerEnableRejit())
8418 return CORPROF_E_REJIT_NOT_ENABLED;
8421 // Request at least 1 method to revert!
8422 if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8424 return E_INVALIDARG;
8427 // Remember the profiler is doing this, as that means we must never detach it!
8428 g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8430 // Initialize the status array
8431 if (rgHrStatuses != NULL)
8433 memset(rgHrStatuses, 0, sizeof(HRESULT) * cFunctions);
8434 _ASSERTE(S_OK == rgHrStatuses[0]);
8438 return ReJitManager::RequestRevert(cFunctions, moduleIds, methodIds, rgHrStatuses);
8442 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions(ICorProfilerFunctionEnum ** ppEnum)
8455 // If we're in preemptive mode we need to take a read lock to safely walk
8456 // the JIT data structures.
8461 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8466 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8469 "**PROF: EnumJITedFunctions.\n"));
8473 return E_INVALIDARG;
8478 NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8479 if (pJitEnum == NULL)
8481 return E_OUTOFMEMORY;
8484 if (!pJitEnum->Init())
8486 return E_OUTOFMEMORY;
8489 // Ownership transferred to [out] param. Caller must Release() when done with this.
8490 *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8495 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions2(ICorProfilerFunctionEnum ** ppEnum)
8502 // Gathering rejitids requires taking a lock and that lock might switch to
8503 // preemptimve mode...
8509 // If we're in preemptive mode we need to take a read lock to safely walk
8510 // the JIT data structures.
8511 // Gathering RejitIDs also takes a lock.
8516 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8521 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8522 kP2EEAllowableAfterAttach | kP2EETriggers,
8525 "**PROF: EnumJITedFunctions.\n"));
8529 return E_INVALIDARG;
8534 NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8535 if (pJitEnum == NULL)
8537 return E_OUTOFMEMORY;
8540 if (!pJitEnum->Init(TRUE /* fWithReJITIDs */))
8542 // If it fails, it's because of OOM.
8543 return E_OUTOFMEMORY;
8546 // Ownership transferred to [out] param. Caller must Release() when done with this.
8547 *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8552 HRESULT ProfToEEInterfaceImpl::EnumModules(ICorProfilerModuleEnum ** ppEnum)
8559 // This method populates the enumerator, which requires iterating over
8560 // AppDomains, which adds, then releases, a reference on each AppDomain iterated.
8561 // This causes locking, and can cause triggering if the AppDomain gets destroyed
8562 // as a result of the release. (See code:AppDomainIterator::Next and its call to
8563 // code:AppDomain::Release.)
8569 // (See comment above GC_TRIGGERS.)
8574 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8579 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8580 kP2EEAllowableAfterAttach | kP2EETriggers,
8583 "**PROF: EnumModules.\n"));
8589 return E_INVALIDARG;
8594 // ProfilerModuleEnum uese AppDomainIterator, which cannot be called while the current thead
8595 // is holding the ThreadStore lock.
8596 if (ThreadStore::HoldingThreadStore())
8598 return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
8601 NewHolder<ProfilerModuleEnum> pModuleEnum(new (nothrow) ProfilerModuleEnum);
8602 if (pModuleEnum == NULL)
8604 return E_OUTOFMEMORY;
8607 hr = pModuleEnum->Init();
8613 // Ownership transferred to [out] param. Caller must Release() when done with this.
8614 *ppEnum = (ICorProfilerModuleEnum *) pModuleEnum.Extract();
8619 HRESULT ProfToEEInterfaceImpl::GetRuntimeInformation(USHORT * pClrInstanceId,
8620 COR_PRF_RUNTIME_TYPE * pRuntimeType,
8621 USHORT * pMajorVersion,
8622 USHORT * pMinorVersion,
8623 USHORT * pBuildNumber,
8624 USHORT * pQFEVersion,
8625 ULONG cchVersionString,
8626 ULONG * pcchVersionString,
8627 __out_ecount_part_opt(cchVersionString, *pcchVersionString) WCHAR szVersionString[])
8641 EE_THREAD_NOT_REQUIRED;
8650 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8653 "**PROF: GetRuntimeInformation.\n"));
8655 if ((szVersionString != NULL) && (pcchVersionString == NULL))
8657 return E_INVALIDARG;
8660 if (pcchVersionString != NULL)
8662 HRESULT hr = GetCORVersionInternal(szVersionString, (DWORD)cchVersionString, (DWORD *)pcchVersionString);
8667 if (pClrInstanceId != NULL)
8668 *pClrInstanceId = static_cast<USHORT>(GetClrInstanceId());
8670 if (pRuntimeType != NULL)
8672 *pRuntimeType = COR_PRF_CORE_CLR;
8675 if (pMajorVersion != NULL)
8676 *pMajorVersion = VER_MAJORVERSION;
8678 if (pMinorVersion != NULL)
8679 *pMinorVersion = VER_MINORVERSION;
8681 if (pBuildNumber != NULL)
8682 *pBuildNumber = VER_PRODUCTBUILD;
8684 if (pQFEVersion != NULL)
8685 *pQFEVersion = VER_PRODUCTBUILD_QFE;
8691 HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds)
8698 // Crst is used in ProfilingAPIDetach::RequestProfilerDetach so GC may be triggered
8705 EE_THREAD_NOT_REQUIRED;
8707 // Crst is used in ProfilingAPIDetach::RequestProfilerDetach
8714 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8715 kP2EEAllowableAfterAttach | kP2EETriggers,
8718 "**PROF: RequestProfilerDetach.\n"));
8720 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
8721 return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds);
8722 #else // FEATURE_PROFAPI_ATTACH_DETACH
8724 #endif // FEATURE_PROFAPI_ATTACH_DETACH
8727 typedef struct _COR_PRF_ELT_INFO_INTERNAL
8729 // Point to a platform dependent structure ASM helper push on the stack
8730 void * platformSpecificHandle;
8732 // startAddress of COR_PRF_FUNCTION_ARGUMENT_RANGE structure needs to point
8733 // TO the argument value, not BE the argument value. So, when the argument
8734 // is this, we need to point TO this. Because of the calling sequence change
8735 // in ELT3, we need to reserve the pointer here instead of using one of our
8739 // Reserve space for output parameter COR_PRF_FRAME_INFO of
8740 // GetFunctionXXXX3Info functions
8741 COR_PRF_FRAME_INFO_INTERNAL frameInfo;
8743 } COR_PRF_ELT_INFO_INTERNAL;
8745 //---------------------------------------------------------------------------------------
8747 // ProfilingGetFunctionEnter3Info provides frame information and argument infomation of
8748 // the function ELT callback is inspecting. It is called either by the profiler or the
8749 // C helper function.
8752 // * functionId - [in] FunctionId of the function being inspected by ELT3
8753 // * eltInfo - [in] The opaque pointer FunctionEnter3WithInfo callback passed to the profiler
8754 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
8756 // * pcbArgumentInfo - [in, out] Pointer to ULONG that specifies the size of structure
8757 // pointed by pArgumentInfo
8758 // * pArgumentInfo - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_INFO structure the profiler
8759 // must preserve enough space for the function it is inspecting
8762 // HRESULT indicating success or failure.
8765 HRESULT ProfilingGetFunctionEnter3Info(FunctionID functionId, // in
8766 COR_PRF_ELT_INFO eltInfo, // in
8767 COR_PRF_FRAME_INFO * pFrameInfo, // out
8768 ULONG * pcbArgumentInfo, // in, out
8769 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo) // out
8782 // ProfileArgIterator::ProfileArgIterator may take locks
8790 if ((functionId == NULL) || (eltInfo == NULL))
8792 return E_INVALIDARG;
8795 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
8796 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
8798 // The loader won't trigger a GC or throw for already loaded argument types.
8799 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
8802 // Find the method this is referring to, so we can get the signature
8804 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
8805 MetaSig metaSig(pMethodDesc);
8807 NewHolder<ProfileArgIterator> pProfileArgIterator;
8810 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
8813 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
8815 if (pProfileArgIterator == NULL)
8817 return E_UNEXPECTED;
8821 if (CORProfilerFrameInfoEnabled())
8823 if (pFrameInfo == NULL)
8825 return E_INVALIDARG;
8829 // Setup the COR_PRF_FRAME_INFO structure first.
8831 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
8833 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
8834 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
8835 pCorPrfFrameInfo->funcID = functionId;
8836 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
8837 pCorPrfFrameInfo->extraArg = pProfileArgIterator->GetHiddenArgValue();
8838 pCorPrfFrameInfo->thisArg = pProfileArgIterator->GetThis();
8840 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
8844 // Do argument processing if desired.
8846 if (CORProfilerFunctionArgsEnabled())
8848 if (pcbArgumentInfo == NULL)
8850 return E_INVALIDARG;
8853 if ((*pcbArgumentInfo != 0) && (pArgumentInfo == NULL))
8855 return E_INVALIDARG;
8858 ULONG32 count = pProfileArgIterator->GetNumArgs();
8860 if (metaSig.HasThis())
8865 ULONG ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + (count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE));
8867 if (*pcbArgumentInfo < ulArgInfoSize)
8869 *pcbArgumentInfo = ulArgInfoSize;
8870 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
8873 _ASSERTE(pArgumentInfo != NULL);
8875 pArgumentInfo->numRanges = count;
8876 pArgumentInfo->totalArgumentSize = 0;
8880 if (metaSig.HasThis())
8882 pELTInfo->pThis = pProfileArgIterator->GetThis();
8883 pArgumentInfo->ranges[count].startAddress = (UINT_PTR) (&(pELTInfo->pThis));
8885 UINT length = sizeof(pELTInfo->pThis);
8886 pArgumentInfo->ranges[count].length = length;
8887 pArgumentInfo->totalArgumentSize += length;
8891 while (count < pArgumentInfo->numRanges)
8893 pArgumentInfo->ranges[count].startAddress = (UINT_PTR)(pProfileArgIterator->GetNextArgAddr());
8895 UINT length = pProfileArgIterator->GetArgSize();
8896 pArgumentInfo->ranges[count].length = length;
8897 pArgumentInfo->totalArgumentSize += length;
8907 HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId, // in
8908 COR_PRF_ELT_INFO eltInfo, // in
8909 COR_PRF_FRAME_INFO * pFrameInfo, // out
8910 ULONG * pcbArgumentInfo, // in, out
8911 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo) // out
8924 // ProfilingGetFunctionEnter3Info may take locks
8932 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
8934 "**PROF: GetFunctionEnter3Info.\n"));
8936 _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL);
8938 if (!CORProfilerELT3SlowPathEnterEnabled())
8940 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
8943 return ProfilingGetFunctionEnter3Info(functionId, eltInfo, pFrameInfo, pcbArgumentInfo, pArgumentInfo);
8946 //---------------------------------------------------------------------------------------
8948 // ProfilingGetFunctionLeave3Info provides frame information and return value infomation
8949 // of the function ELT callback is inspecting. It is called either by the profiler or the
8950 // C helper function.
8953 // * functionId - [in] FunctionId of the function being inspected by ELT3
8954 // * eltInfo - [in] The opaque pointer FunctionLeave3WithInfo callback passed to the profiler
8955 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
8957 // * pRetvalRange - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_RANGE to store return value
8960 // HRESULT indicating success or failure.
8963 HRESULT ProfilingGetFunctionLeave3Info(FunctionID functionId, // in
8964 COR_PRF_ELT_INFO eltInfo, // in
8965 COR_PRF_FRAME_INFO * pFrameInfo, // out
8966 COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange) // out
8979 // ProfileArgIterator::ProfileArgIterator may take locks
8986 if ((pFrameInfo == NULL) || (eltInfo == NULL))
8988 return E_INVALIDARG;
8991 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
8992 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
8994 // The loader won't trigger a GC or throw for already loaded argument types.
8995 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
8998 // Find the method this is referring to, so we can get the signature
9000 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9001 MetaSig metaSig(pMethodDesc);
9003 NewHolder<ProfileArgIterator> pProfileArgIterator;
9006 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9009 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9011 if (pProfileArgIterator == NULL)
9013 return E_UNEXPECTED;
9017 if (CORProfilerFrameInfoEnabled())
9019 if (pFrameInfo == NULL)
9021 return E_INVALIDARG;
9024 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9027 // Setup the COR_PRF_FRAME_INFO structure first.
9029 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9030 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9031 pCorPrfFrameInfo->funcID = functionId;
9032 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9034 // Upon entering Leave hook, the register assigned to store this pointer on function calls may
9035 // already be reused and is likely not to contain this pointer.
9036 pCorPrfFrameInfo->extraArg = NULL;
9037 pCorPrfFrameInfo->thisArg = NULL;
9039 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9043 // Do argument processing if desired.
9045 if (CORProfilerFunctionReturnValueEnabled())
9047 if (pRetvalRange == NULL)
9049 return E_INVALIDARG;
9052 if (!metaSig.IsReturnTypeVoid())
9054 pRetvalRange->length = metaSig.GetReturnTypeSize();
9055 pRetvalRange->startAddress = (UINT_PTR)pProfileArgIterator->GetReturnBufferAddr();
9059 pRetvalRange->length = 0;
9060 pRetvalRange->startAddress = 0;
9068 HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId, // in
9069 COR_PRF_ELT_INFO eltInfo, // in
9070 COR_PRF_FRAME_INFO * pFrameInfo, // out
9071 COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange) // out
9084 // ProfilingGetFunctionLeave3Info may take locks
9092 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9094 "**PROF: GetFunctionLeave3Info.\n"));
9096 _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL);
9098 if (!CORProfilerELT3SlowPathLeaveEnabled())
9100 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9103 return ProfilingGetFunctionLeave3Info(functionId, eltInfo, pFrameInfo, pRetvalRange);
9106 //---------------------------------------------------------------------------------------
9108 // ProfilingGetFunctionTailcall3Info provides frame information of the function ELT callback
9109 // is inspecting. It is called either by the profiler or the C helper function.
9112 // * functionId - [in] FunctionId of the function being inspected by ELT3
9113 // * eltInfo - [in] The opaque pointer FunctionTailcall3WithInfo callback passed to the
9115 // * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect
9119 // HRESULT indicating success or failure.
9122 HRESULT ProfilingGetFunctionTailcall3Info(FunctionID functionId, // in
9123 COR_PRF_ELT_INFO eltInfo, // in
9124 COR_PRF_FRAME_INFO * pFrameInfo) // out
9137 // ProfileArgIterator::ProfileArgIterator may take locks
9145 if ((functionId == NULL) || (eltInfo == NULL) || (pFrameInfo == NULL))
9147 return E_INVALIDARG;
9150 COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9151 ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9153 // The loader won't trigger a GC or throw for already loaded argument types.
9154 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9157 // Find the method this is referring to, so we can get the signature
9159 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9160 MetaSig metaSig(pMethodDesc);
9162 NewHolder<ProfileArgIterator> pProfileArgIterator;
9165 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9168 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9170 if (pProfileArgIterator == NULL)
9172 return E_UNEXPECTED;
9176 COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9179 // Setup the COR_PRF_FRAME_INFO structure first.
9181 pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9182 pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9183 pCorPrfFrameInfo->funcID = functionId;
9184 pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9186 // Tailcall is designed to report the caller, not the callee. But the taillcall hook is invoked
9187 // with registers containing parameters passed to the callee before calling into the callee.
9188 // This pointer we get here is for the callee. Because of the constraints imposed on tailcall
9189 // optimization, this pointer passed to the callee accidentally happens to be the same this pointer
9190 // passed to the caller.
9192 // It is a fragile coincidence we should not depend on because JIT is free to change the
9193 // implementation details in the future.
9194 pCorPrfFrameInfo->extraArg = NULL;
9195 pCorPrfFrameInfo->thisArg = NULL;
9197 *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9203 HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId, // in
9204 COR_PRF_ELT_INFO eltInfo, // in
9205 COR_PRF_FRAME_INFO * pFrameInfo) // out
9218 // ProfilingGetFunctionTailcall3Info may take locks
9226 PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF,
9228 "**PROF: GetFunctionTailcall3Info.\n"));
9230 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL);
9232 if (!CORProfilerELT3SlowPathTailcallEnabled())
9234 return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9237 return ProfilingGetFunctionTailcall3Info(functionId, eltInfo, pFrameInfo);
9240 HRESULT ProfToEEInterfaceImpl::EnumThreads(
9241 /* out */ ICorProfilerThreadEnum ** ppEnum)
9255 // Need to acquire the thread store lock
9260 PRECONDITION(CheckPointer(ppEnum, NULL_OK));
9265 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9266 kP2EEAllowableAfterAttach,
9269 "**PROF: EnumThreads.\n"));
9275 return E_INVALIDARG;
9280 NewHolder<ProfilerThreadEnum> pThreadEnum(new (nothrow) ProfilerThreadEnum);
9281 if (pThreadEnum == NULL)
9283 return E_OUTOFMEMORY;
9286 hr = pThreadEnum->Init();
9292 // Ownership transferred to [out] param. Caller must Release() when done with this.
9293 *ppEnum = (ICorProfilerThreadEnum *) pThreadEnum.Extract();
9298 // This function needs to be called on any thread before making any ICorProfilerInfo* calls and must be
9299 // made before any thread is suspended by this profiler.
9300 // As you might have already figured out, this is done to avoid deadlocks situation when
9301 // the suspended thread holds on the loader lock / heap lock while the current thread is trying to obtain
9303 HRESULT ProfToEEInterfaceImpl::InitializeCurrentThread()
9317 // May take thread store lock and OS APIs may also take locks
9325 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9326 kP2EEAllowableAfterAttach,
9329 "**PROF: InitializeCurrentThread.\n"));
9335 CExecutionEngine::SetupTLSForThread(GetThread());
9337 EX_CATCH_HRESULT(hr);
9345 struct InternalProfilerModuleEnum : public ProfilerModuleEnum
9347 CDynArray<ModuleID> *GetRawElementsArray()
9353 HRESULT ProfToEEInterfaceImpl::EnumNgenModuleMethodsInliningThisMethod(
9354 ModuleID inlinersModuleId,
9355 ModuleID inlineeModuleId,
9356 mdMethodDef inlineeMethodId,
9357 BOOL *incompleteData,
9358 ICorProfilerMethodEnum** ppEnum)
9367 PRECONDITION(CheckPointer(ppEnum));
9371 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: EnumNgenModuleMethodsInliningThisMethod.\n"));
9375 return E_INVALIDARG;
9380 Module *inlineeOwnerModule = reinterpret_cast<Module *>(inlineeModuleId);
9381 if (inlineeOwnerModule == NULL)
9383 return E_INVALIDARG;
9385 if (inlineeOwnerModule->IsBeingUnloaded())
9387 return CORPROF_E_DATAINCOMPLETE;
9390 Module *inlinersModule = reinterpret_cast<Module *>(inlinersModuleId);
9391 if (inlinersModule == NULL)
9393 return E_INVALIDARG;
9395 if(inlinersModule->IsBeingUnloaded())
9397 return CORPROF_E_DATAINCOMPLETE;
9400 PersistentInlineTrackingMap *inliningMap = inlinersModule->GetNgenInlineTrackingMap();
9401 if (inliningMap == NULL)
9403 return CORPROF_E_DATAINCOMPLETE;
9406 CDynArray<COR_PRF_METHOD> results;
9407 const COUNT_T staticBufferSize = 10;
9408 MethodInModule staticBuffer[staticBufferSize];
9409 NewArrayHolder<MethodInModule> dynamicBuffer;
9410 MethodInModule *methodsBuffer = staticBuffer;
9413 // Trying to use static buffer
9414 COUNT_T methodsAvailable = inliningMap->GetInliners(inlineeOwnerModule, inlineeMethodId, staticBufferSize, staticBuffer, incompleteData);
9416 // If static buffer is not enough, allocate an array.
9417 if (methodsAvailable > staticBufferSize)
9419 DWORD dynamicBufferSize = methodsAvailable;
9420 dynamicBuffer = methodsBuffer = new MethodInModule[dynamicBufferSize];
9421 methodsAvailable = inliningMap->GetInliners(inlineeOwnerModule, inlineeMethodId, dynamicBufferSize, dynamicBuffer, incompleteData);
9422 if (methodsAvailable > dynamicBufferSize)
9424 _ASSERTE(!"Ngen image inlining info changed, this shouldn't be possible.");
9425 methodsAvailable = dynamicBufferSize;
9429 //Go through all inliners found in the inlinersModule and prepare them to export via results.
9430 results.AllocateBlockThrowing(methodsAvailable);
9431 for (COUNT_T j = 0; j < methodsAvailable; j++)
9433 COR_PRF_METHOD *newPrfMethod = &results[j];
9434 newPrfMethod->moduleId = reinterpret_cast<ModuleID>(methodsBuffer[j].m_module);
9435 newPrfMethod->methodId = methodsBuffer[j].m_methodDef;
9437 *ppEnum = new ProfilerMethodEnum(&results);
9439 EX_CATCH_HRESULT(hr);
9444 HRESULT ProfToEEInterfaceImpl::GetInMemorySymbolsLength(
9446 DWORD* pCountSymbolBytes)
9459 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9460 kP2EEAllowableAfterAttach,
9463 "**PROF: GetInMemorySymbolsLength.\n"));
9466 if (pCountSymbolBytes == NULL)
9468 return E_INVALIDARG;
9470 *pCountSymbolBytes = 0;
9472 Module* pModule = reinterpret_cast< Module* >(moduleId);
9473 if (pModule == NULL)
9475 return E_INVALIDARG;
9477 if (pModule->IsBeingUnloaded())
9479 return CORPROF_E_DATAINCOMPLETE;
9482 //This method would work fine on reflection.emit, but there would be no way to know
9483 //if some other thread was changing the size of the symbols before this method returned.
9484 //Adding events or locks to detect/prevent changes would make the scenario workable
9485 if (pModule->IsReflection())
9487 return COR_PRF_MODULE_DYNAMIC;
9490 CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9491 if (pStream == NULL)
9496 STATSTG SizeData = { 0 };
9497 hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9502 if (SizeData.cbSize.u.HighPart > 0)
9504 return COR_E_OVERFLOW;
9506 *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
9511 HRESULT ProfToEEInterfaceImpl::ReadInMemorySymbols(
9513 DWORD symbolsReadOffset,
9515 DWORD countSymbolBytes,
9516 DWORD* pCountSymbolBytesRead)
9527 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9528 kP2EEAllowableAfterAttach,
9531 "**PROF: ReadInMemorySymbols.\n"));
9534 if (pSymbolBytes == NULL)
9536 return E_INVALIDARG;
9538 if (pCountSymbolBytesRead == NULL)
9540 return E_INVALIDARG;
9542 *pCountSymbolBytesRead = 0;
9544 Module* pModule = reinterpret_cast< Module* >(moduleId);
9545 if (pModule == NULL)
9547 return E_INVALIDARG;
9549 if (pModule->IsBeingUnloaded())
9551 return CORPROF_E_DATAINCOMPLETE;
9554 //This method would work fine on reflection.emit, but there would be no way to know
9555 //if some other thread was changing the size of the symbols before this method returned.
9556 //Adding events or locks to detect/prevent changes would make the scenario workable
9557 if (pModule->IsReflection())
9559 return COR_PRF_MODULE_DYNAMIC;
9562 CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9563 if (pStream == NULL)
9565 return E_INVALIDARG;
9568 STATSTG SizeData = { 0 };
9569 hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9574 if (SizeData.cbSize.u.HighPart > 0)
9576 return COR_E_OVERFLOW;
9578 DWORD streamSize = SizeData.cbSize.u.LowPart;
9579 if (symbolsReadOffset >= streamSize)
9581 return E_INVALIDARG;
9584 *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
9585 memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
9590 HRESULT ProfToEEInterfaceImpl::ApplyMetaData(
9602 PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach, (LF_CORPROF, LL_INFO1000, "**PROF: ApplyMetaData.\n"));
9604 if (moduleId == NULL)
9606 return E_INVALIDARG;
9612 Module *pModule = (Module *)moduleId;
9613 _ASSERTE(pModule != NULL);
9614 if (pModule->IsBeingUnloaded())
9616 hr = CORPROF_E_DATAINCOMPLETE;
9620 pModule->ApplyMetaData();
9623 EX_CATCH_HRESULT(hr);
9627 //---------------------------------------------------------------------------------------
9629 // Simple wrapper around EEToProfInterfaceImpl::ManagedToUnmanagedTransition. This
9630 // can be called by C++ code and directly by generated stubs.
9633 // pMD - MethodDesc for the managed function involved in the transition
9634 // reason - Passed on to profiler to indicate why the transition is occurring
9637 void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD,
9638 COR_PRF_TRANSITION_REASON reason)
9649 // This function is called within the runtime, not directly from managed code.
9650 // Also, the only case MD is NULL is the calli pinvoke case, and we still
9651 // want to notify the profiler in that case.
9653 // Do not notify the profiler about QCalls
9654 if (pMD == NULL || !pMD->IsQCall())
9656 BEGIN_PIN_PROFILER(CORProfilerPresent());
9657 g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD),
9663 //---------------------------------------------------------------------------------------
9665 // Simple wrapper around EEToProfInterfaceImpl::UnmanagedToManagedTransition. This
9666 // can be called by C++ code and directly by generated stubs.
9669 // pMD - MethodDesc for the managed function involved in the transition
9670 // reason - Passed on to profiler to indicate why the transition is occurring
9673 void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD,
9674 COR_PRF_TRANSITION_REASON reason)
9685 // This function is called within the runtime, not directly from managed code.
9686 // Also, the only case MD is NULL is the calli pinvoke case, and we still
9687 // want to notify the profiler in that case.
9689 // Do not notify the profiler about QCalls
9690 if (pMD == NULL || !pMD->IsQCall())
9692 BEGIN_PIN_PROFILER(CORProfilerPresent());
9693 g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD),
9701 #endif // PROFILING_SUPPORTED
9704 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemoting)
9708 #ifdef PROFILING_SUPPORTED
9709 FC_RETURN_BOOL(CORProfilerTrackRemoting());
9710 #else // !PROFILING_SUPPORTED
9711 FC_RETURN_BOOL(FALSE);
9712 #endif // !PROFILING_SUPPORTED
9716 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingCookie)
9720 #ifdef PROFILING_SUPPORTED
9721 FC_RETURN_BOOL(CORProfilerTrackRemotingCookie());
9722 #else // !PROFILING_SUPPORTED
9723 FC_RETURN_BOOL(FALSE);
9724 #endif // !PROFILING_SUPPORTED
9728 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingAsync)
9732 #ifdef PROFILING_SUPPORTED
9733 FC_RETURN_BOOL(CORProfilerTrackRemotingAsync());
9734 #else // !PROFILING_SUPPORTED
9735 FC_RETURN_BOOL(FALSE);
9736 #endif // !PROFILING_SUPPORTED
9740 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingClientSendingMessage, GUID *pId, CLR_BOOL fIsAsync)
9744 #ifdef PROFILING_SUPPORTED
9745 // Need to erect a GC frame so that GCs can occur without a problem
9746 // within the profiler code.
9748 // Note that we don't need to worry about pId moving around since
9749 // it is a value class declared on the stack and so GC doesn't
9752 _ASSERTE (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pId)); // should be on the stack, not in the heap
9753 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
9756 BEGIN_PIN_PROFILER(CORProfilerPresent());
9758 if (CORProfilerTrackRemotingCookie())
9760 g_profControlBlock.pProfInterface->GetGUID(pId);
9761 _ASSERTE(pId->Data1);
9763 g_profControlBlock.pProfInterface->RemotingClientSendingMessage(pId, fIsAsync);
9767 g_profControlBlock.pProfInterface->RemotingClientSendingMessage(NULL, fIsAsync);
9771 HELPER_METHOD_FRAME_END_POLL();
9772 #endif // PROFILING_SUPPORTED
9777 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingClientReceivingReply, GUID id, CLR_BOOL fIsAsync)
9781 #ifdef PROFILING_SUPPORTED
9782 // Need to erect a GC frame so that GCs can occur without a problem
9783 // within the profiler code.
9785 // Note that we don't need to worry about pId moving around since
9786 // it is a value class declared on the stack and so GC doesn't
9789 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
9793 BEGIN_PIN_PROFILER(CORProfilerPresent());
9795 if (CORProfilerTrackRemotingCookie())
9797 g_profControlBlock.pProfInterface->RemotingClientReceivingReply(&id, fIsAsync);
9801 g_profControlBlock.pProfInterface->RemotingClientReceivingReply(NULL, fIsAsync);
9806 HELPER_METHOD_FRAME_END_POLL();
9807 #endif // PROFILING_SUPPORTED
9812 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingServerReceivingMessage, GUID id, CLR_BOOL fIsAsync)
9816 #ifdef PROFILING_SUPPORTED
9817 // Need to erect a GC frame so that GCs can occur without a problem
9818 // within the profiler code.
9820 // Note that we don't need to worry about pId moving around since
9821 // it is a value class declared on the stack and so GC doesn't
9824 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
9827 BEGIN_PIN_PROFILER(CORProfilerPresent());
9829 if (CORProfilerTrackRemotingCookie())
9831 g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(&id, fIsAsync);
9835 g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(NULL, fIsAsync);
9840 HELPER_METHOD_FRAME_END_POLL();
9841 #endif // PROFILING_SUPPORTED
9845 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingServerSendingReply, GUID *pId, CLR_BOOL fIsAsync)
9849 #ifdef PROFILING_SUPPORTED
9850 // Need to erect a GC frame so that GCs can occur without a problem
9851 // within the profiler code.
9853 // Note that we don't need to worry about pId moving around since
9854 // it is a value class declared on the stack and so GC doesn't
9857 HELPER_METHOD_FRAME_BEGIN_NOPOLL();
9860 BEGIN_PIN_PROFILER(CORProfilerPresent());
9862 if (CORProfilerTrackRemotingCookie())
9864 g_profControlBlock.pProfInterface->GetGUID(pId);
9865 _ASSERTE(pId->Data1);
9867 g_profControlBlock.pProfInterface->RemotingServerSendingReply(pId, fIsAsync);
9871 g_profControlBlock.pProfInterface->RemotingServerSendingReply(NULL, fIsAsync);
9876 HELPER_METHOD_FRAME_END_POLL();
9877 #endif // PROFILING_SUPPORTED
9882 //*******************************************************************************************
9883 // These do a lot of work for us, setting up Frames, gathering arg info and resolving generics.
9884 //*******************************************************************************************
9886 HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecificHandle)
9890 #ifdef PROFILING_SUPPORTED
9892 #ifdef PROF_TEST_ONLY_FORCE_ELT
9893 // If this test-only flag is set, it's possible we might not have a profiler
9894 // attached, or might not have any of the hooks set. See
9895 // code:ProfControlBlock#TestOnlyELT
9896 if (g_profControlBlock.fTestOnlyForceEnterLeave)
9898 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
9900 (g_profControlBlock.pProfInterface->GetEnterHook() == NULL) &&
9901 (g_profControlBlock.pProfInterface->GetEnter2Hook() == NULL) &&
9902 (g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL) &&
9903 (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL)
9910 #endif // PROF_TEST_ONLY_FORCE_ELT
9912 // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
9913 _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL);
9914 _ASSERTE(GetThread()->PreemptiveGCDisabled());
9915 _ASSERTE(platformSpecificHandle != NULL);
9918 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
9920 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
9921 // frame, like we're about to do.
9922 SetCallbackStateFlagsHolder csf(
9923 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
9925 COR_PRF_ELT_INFO_INTERNAL eltInfo;
9926 eltInfo.platformSpecificHandle = platformSpecificHandle;
9929 // CLR v4 Slow-Path ELT
9931 if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL)
9933 FunctionIDOrClientID functionIDOrClientID;
9934 functionIDOrClientID.clientID = clientData;
9935 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
9936 g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()(
9937 functionIDOrClientID,
9938 (COR_PRF_ELT_INFO)&eltInfo);
9942 if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL)
9944 // We have run out of heap memory, so the content of the mapping table becomes stale.
9945 // All Whidbey ETL hooks must be turned off.
9946 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
9951 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
9952 // instead of using clientID because the profiler may map several functionIDs to a clientID to
9953 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
9954 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
9955 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
9956 FunctionID functionId = clientData;
9957 _ASSERTE(functionId != NULL);
9958 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
9961 // Whidbey Fast-Path ELT
9963 if (CORProfilerELT2FastPathEnterEnabled())
9965 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
9966 g_profControlBlock.pProfInterface->GetEnter2Hook()(
9975 // Whidbey Slow-Path ELT
9977 ProfileSetFunctionIDInPlatformSpecificHandle(platformSpecificHandle, functionId);
9979 COR_PRF_FRAME_INFO frameInfo = NULL;
9980 COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo = NULL;
9981 ULONG ulArgInfoSize = 0;
9983 if (CORProfilerFunctionArgsEnabled())
9985 // The loader won't trigger a GC or throw for already loaded argument types.
9986 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9989 // Find the method this is referring to, so we can get the signature
9991 MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9992 MetaSig metaSig(pMethodDesc);
9994 NewHolder<ProfileArgIterator> pProfileArgIterator;
9997 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
10000 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, platformSpecificHandle);
10002 if (pProfileArgIterator == NULL)
10008 ULONG32 count = pProfileArgIterator->GetNumArgs();
10010 if (metaSig.HasThis())
10015 ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE);
10016 pArgumentInfo = (COR_PRF_FUNCTION_ARGUMENT_INFO *)_alloca(ulArgInfoSize);
10019 HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo);
10021 _ASSERTE(hr == S_OK);
10022 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10023 g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
10029 // We will not be here unless the jit'd or ngen'd function we're about to enter
10030 // was backpatched with this wrapper around the profiler's hook, and that
10031 // wouldn't have happened unless the profiler supplied us with a hook
10032 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10033 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10034 // its mind about where the hooks are.)
10035 _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL);
10037 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10038 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10039 // to enable the jitter to add enter/leave callouts independently of whether
10040 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10041 // the callouts quickly return and do nothing.)
10047 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10048 g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData);
10054 HELPER_METHOD_FRAME_END(); // Un-link the frame
10056 #endif // PROFILING_SUPPORTED
10060 HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecificHandle)
10064 FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
10066 #ifdef PROFILING_SUPPORTED
10068 #ifdef PROF_TEST_ONLY_FORCE_ELT
10069 // If this test-only flag is set, it's possible we might not have a profiler
10070 // attached, or might not have any of the hooks set. See
10071 // code:ProfControlBlock#TestOnlyELT
10072 if (g_profControlBlock.fTestOnlyForceEnterLeave)
10074 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10076 (g_profControlBlock.pProfInterface->GetLeaveHook() == NULL) &&
10077 (g_profControlBlock.pProfInterface->GetLeave2Hook() == NULL) &&
10078 (g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL) &&
10079 (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL)
10086 #endif // PROF_TEST_ONLY_FORCE_ELT
10088 // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10089 _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL);
10090 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10091 _ASSERTE(platformSpecificHandle != NULL);
10094 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10096 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10097 // frame, like we're about to do.
10098 SetCallbackStateFlagsHolder csf(
10099 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10101 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10102 eltInfo.platformSpecificHandle = platformSpecificHandle;
10105 // CLR v4 Slow-Path ELT
10107 if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL)
10109 FunctionIDOrClientID functionIDOrClientID;
10110 functionIDOrClientID.clientID = clientData;
10111 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10112 g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()(
10113 functionIDOrClientID,
10114 (COR_PRF_ELT_INFO)&eltInfo);
10118 if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL)
10120 // We have run out of heap memory, so the content of the mapping table becomes stale.
10121 // All Whidbey ETL hooks must be turned off.
10122 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10127 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10128 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10129 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10130 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10131 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10132 FunctionID functionId = clientData;
10133 _ASSERTE(functionId != NULL);
10134 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10137 // Whidbey Fast-Path ELT
10139 if (CORProfilerELT2FastPathLeaveEnabled())
10141 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10142 g_profControlBlock.pProfInterface->GetLeave2Hook()(
10151 // Whidbey Slow-Path ELT
10153 COR_PRF_FRAME_INFO frameInfo = NULL;
10154 COR_PRF_FUNCTION_ARGUMENT_RANGE argumentRange;
10156 HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange);
10157 _ASSERTE(hr == S_OK);
10159 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10160 g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
10164 // We will not be here unless the jit'd or ngen'd function we're about to leave
10165 // was backpatched with this wrapper around the profiler's hook, and that
10166 // wouldn't have happened unless the profiler supplied us with a hook
10167 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10168 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10169 // its mind about where the hooks are.)
10170 _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL);
10172 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10173 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10174 // to enable the jitter to add enter/leave callouts independently of whether
10175 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10176 // the callouts quickly return and do nothing.)
10182 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10183 g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData);
10190 HELPER_METHOD_FRAME_END(); // Un-link the frame
10192 #endif // PROFILING_SUPPORTED
10196 HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpecificHandle)
10200 FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
10202 #ifdef PROFILING_SUPPORTED
10204 #ifdef PROF_TEST_ONLY_FORCE_ELT
10205 // If this test-only flag is set, it's possible we might not have a profiler
10206 // attached, or might not have any of the hooks set. See
10207 // code:ProfControlBlock#TestOnlyELT
10208 if (g_profControlBlock.fTestOnlyForceEnterLeave)
10210 if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10212 (g_profControlBlock.pProfInterface->GetTailcallHook() == NULL) &&
10213 (g_profControlBlock.pProfInterface->GetTailcall2Hook() == NULL) &&
10214 (g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL) &&
10215 (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL)
10222 #endif // PROF_TEST_ONLY_FORCE_ELT
10224 // ELT3 fast-path hooks should be NULL when ELT intermediary is used.
10225 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL);
10226 _ASSERTE(GetThread()->PreemptiveGCDisabled());
10227 _ASSERTE(platformSpecificHandle != NULL);
10230 HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10232 // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10233 // frame, like we're about to do.
10234 SetCallbackStateFlagsHolder csf(
10235 COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10237 COR_PRF_ELT_INFO_INTERNAL eltInfo;
10238 eltInfo.platformSpecificHandle = platformSpecificHandle;
10241 // CLR v4 Slow-Path ELT
10243 if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL)
10245 FunctionIDOrClientID functionIDOrClientID;
10246 functionIDOrClientID.clientID = clientData;
10247 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10248 g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()(
10249 functionIDOrClientID,
10250 (COR_PRF_ELT_INFO)&eltInfo);
10254 if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL)
10256 // We have run out of heap memory, so the content of the mapping table becomes stale.
10257 // All Whidbey ETL hooks must be turned off.
10258 if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10263 // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes
10264 // instead of using clientID because the profiler may map several functionIDs to a clientID to
10265 // do things like code coverage analysis. FunctionID to clientID has the one-on-one relationship,
10266 // while the reverse may not have this one-on-one mapping. Therefore, FunctionID is used as the
10267 // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10268 FunctionID functionId = clientData;
10269 _ASSERTE(functionId != NULL);
10270 clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10273 // Whidbey Fast-Path ELT
10275 if (CORProfilerELT2FastPathTailcallEnabled())
10277 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10278 g_profControlBlock.pProfInterface->GetTailcall2Hook()(
10286 // Whidbey Slow-Path ELT
10288 COR_PRF_FRAME_INFO frameInfo = NULL;
10290 HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo);
10291 _ASSERTE(hr == S_OK);
10293 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10294 g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
10298 // We will not be here unless the jit'd or ngen'd function we're about to tailcall
10299 // was backpatched with this wrapper around the profiler's hook, and that
10300 // wouldn't have happened unless the profiler supplied us with a hook
10301 // in the first place. (Note that SetEnterLeaveFunctionHooks* will return
10302 // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10303 // its mind about where the hooks are.)
10304 _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL);
10306 // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10307 // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10308 // to enable the jitter to add enter/leave callouts independently of whether
10309 // the profiler actually has enter/leave hooks. (If the profiler has no such hooks,
10310 // the callouts quickly return and do nothing.)
10316 REMOVE_STACK_GUARD_FOR_PROFILER_CALL;
10317 g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData);
10324 HELPER_METHOD_FRAME_END(); // Un-link the frame
10326 #endif // PROFILING_SUPPORTED