Add option to only notify profiler of LOH allocations (#24291)
[platform/upstream/coreclr.git] / src / vm / proftoeeinterfaceimpl.cpp
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.
4 //
5 // FILE: ProfToEEInterfaceImpl.cpp
6 //
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.
11 //
12
13 // 
14 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
15 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! 
16 //
17 // PLEASE READ!
18 //
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.
22 //
23 // As a reminder, here is a short summary of your responsibilities.  Every PUBLIC
24 // ENTRYPOINT (from profiler to EE) must have:
25 //
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.
41 //
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):
44 //       NOTHROW
45 //       GC_NOTRIGGER
46 //       MODE_ANY
47 //       CANNOT_TAKE_LOCK
48 //       (EE_THREAD_(NOT)_REQUIRED are unenforced and are thus optional.  If you wish
49 //       to specify these, EE_THREAD_NOT_REQUIRED is preferred.)
50 //   Note that the preferred contracts in this file are DIFFERENT than the preferred
51 //   contracts for eetoprofinterfaceimpl.cpp.
52 //
53 // Private helper functions in this file do not have the same preferred contracts as
54 // public entrypoints, and they should be contracted following the same guidelines
55 // as per the rest of the EE.
56 //
57 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! 
58 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
59 //
60 //
61 // #P2CLRRestrictionsOverview
62 // 
63 // The public ICorProfilerInfo(N) functions below have different restrictions on when
64 // they're allowed to be called. Listed roughly in order from most to least restrictive:
65 //     * PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY: Functions that are only
66 //         allowed to be called while the profiler is initializing on startup, from
67 //         inside the profiler's ICorProfilerCallback::Initialize method
68 //     * PROFILER_TO_CLR_ENTRYPOINT_SYNC: Functions that may be called from within any of
69 //         the profiler's callbacks, or anytime from a thread created by the profiler.
70 //         These functions may only be called by profilers loaded on startup
71 //     * PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach): Same as above,
72 //         except these may be called by startup AND attaching profilers.
73 //     * PROFILER_TO_CLR_ENTRYPOINT_ASYNC: Functions that may be called at any time and
74 //         from any thread by a profiler loaded on startup
75 //     * PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach): Same as above,
76 //         except these may be called by startup AND attaching profilers.
77 //         
78 //  The above restrictions are lifted for certain tests that run with these environment
79 //  variables set. (These are only available on DEBUG builds--including chk--not retail
80 //  builds.)
81 //    * COMPlus_TestOnlyEnableSlowELTHooks:
82 //         * If nonzero, then on startup the runtime will act as if a profiler was loaded
83 //             on startup and requested ELT slow-path (even if no profiler is loaded on
84 //             startup). This will also allow the SetEnterLeaveFunctionHooks(2) info
85 //             functions to be called outside of Initialize(). If a profiler later
86 //             attaches and calls these functions, then the slow-path wrapper will call
87 //             into the profiler's ELT hooks.
88 //    * COMPlus_TestOnlyEnableObjectAllocatedHook:
89 //         * If nonzero, then on startup the runtime will act as if a profiler was loaded
90 //             on startup and requested ObjectAllocated callback (even if no profiler is loaded
91 //             on startup). If a profiler later attaches and calls these functions, then the 
92 //             ObjectAllocated notifications will call into the profiler's ObjectAllocated callback.
93 //    * COMPlus_TestOnlyEnableICorProfilerInfo:
94 //         * If nonzero, then attaching profilers allows to call ICorProfilerInfo inteface, 
95 //             which would otherwise be disallowed for attaching profilers
96 //    * COMPlus_TestOnlyAllowedEventMask
97 //         * If a profiler needs to work around the restrictions of either
98 //             COR_PRF_ALLOWABLE_AFTER_ATTACH or COR_PRF_MONITOR_IMMUTABLE it may set
99 //             this environment variable. Its value should be a bitmask containing all
100 //             the flags that are:
101 //             * normally immutable or disallowed after attach, AND
102 //             * that the test plans to set after startup and / or by an attaching
103 //                 profiler.
104 //     
105 //
106
107 // 
108 // ======================================================================================
109
110 #include "common.h"
111 #include <posterror.h>
112 #include "proftoeeinterfaceimpl.h"
113 #include "proftoeeinterfaceimpl.inl"
114 #include "dllimport.h"
115 #include "threads.h"
116 #include "method.hpp"
117 #include "vars.hpp"
118 #include "dbginterface.h"
119 #include "corprof.h"
120 #include "class.h"
121 #include "object.h"
122 #include "ceegen.h"
123 #include "eeconfig.h"
124 #include "generics.h"
125 #include "gcinfo.h"
126 #include "safemath.h"
127 #include "threadsuspend.h"
128 #include "inlinetracking.h"
129
130 #ifdef PROFILING_SUPPORTED
131 #include "profilinghelper.h"
132 #include "profilinghelper.inl"
133 #include "eetoprofinterfaceimpl.inl"
134 #include "profilingenumerators.h"
135 #endif
136
137 #include "profdetach.h"
138
139 #include "metadataexports.h"
140
141 //---------------------------------------------------------------------------------------
142 // Helpers
143
144 // An OR'd combination of these flags may be specified in the _EX entrypoint macros to
145 // customize the behavior.
146 enum ProfToClrEntrypointFlags
147 {
148     // Just use the default behavior (this one is used if the non-_EX entrypoint macro is
149     // specified without any flags).
150     kP2EENone                       = 0x00000000,
151     
152     // By default, Info functions are not allowed to be used by an attaching profiler. 
153     // Specify this flag to override the default.
154     kP2EEAllowableAfterAttach       = 0x00000001,
155
156     // This info method has a GC_TRIGGERS contract.  Whereas contracts are debug-only,
157     // this flag is used in retail builds as well.
158     kP2EETriggers                   = 0x00000002,
159 };
160
161 // Default versions of the entrypoint macros use kP2EENone if no
162 // ProfToClrEntrypointFlags are specified
163
164 #define PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams)             \
165     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EENone, logParams)
166
167 #define PROFILER_TO_CLR_ENTRYPOINT_SYNC(logParams)              \
168     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EENone, logParams)
169
170 // ASYNC entrypoints log and ensure an attaching profiler isn't making a call that's
171 // only supported by startup profilers.
172
173 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags)                           \
174     do                                                                                     \
175     {                                                                                      \
176         if ((((p2eeFlags) & kP2EEAllowableAfterAttach) == 0) &&                            \
177             (g_profControlBlock.pProfInterface->IsLoadedViaAttach()))                      \
178         {                                                                                  \
179             LOG((LF_CORPROF,                                                               \
180                  LL_ERROR,                                                                 \
181                  "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER "  \
182                  "due to a call illegally made by an attaching profiler \n"));             \
183             return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER;                           \
184         }                                                                                  \
185     } while(0)
186
187 #ifdef _DEBUG
188
189 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags)                           \
190     do                                                                              \
191     {                                                                               \
192         if (!((&g_profControlBlock)->fTestOnlyEnableICorProfilerInfo))              \
193         {                                                                           \
194             CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags);               \
195         }                                                                           \
196     } while(0)
197
198
199
200 #else  //_DEBUG
201
202 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags)                           \
203     do                                                                              \
204     {                                                                               \
205         CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags);                   \
206     } while(0)
207
208 #endif //_DEBUG
209
210 #define PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(p2eeFlags, logParams)                           \
211     do                                                                                      \
212     {                                                                                       \
213         INCONTRACT(AssertTriggersContract(((p2eeFlags) & kP2EETriggers)));                  \
214         _ASSERTE(g_profControlBlock.curProfStatus.Get() != kProfStatusNone);                \
215         LOG(logParams);                                                                     \
216         /* If profiler was neutered, disallow call */                                       \
217         if (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching)                 \
218         {                                                                                   \
219             LOG((LF_CORPROF,                                                                \
220                  LL_ERROR,                                                                  \
221                  "**PROF: ERROR: Returning CORPROF_E_PROFILER_DETACHING "                   \
222                  "due to a post-neutered profiler call\n"));                                \
223             return CORPROF_E_PROFILER_DETACHING;                                            \
224         }                                                                                   \
225         CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags);                                  \
226     } while(0)
227
228 // SYNC entrypoints must ensure the current EE Thread shows evidence that we're
229 // inside a callback.  If there's no EE Thread, then we automatically "pass"
230 // the check, and the SYNC call is allowed.
231 #define PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(p2eeFlags, logParams)                    \
232     do                                                                              \
233     {                                                                               \
234         PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(p2eeFlags, logParams);                  \
235         DWORD __dwExpectedCallbackState = COR_PRF_CALLBACKSTATE_INCALLBACK;         \
236         if (((p2eeFlags) & kP2EETriggers) != 0)                                     \
237         {                                                                           \
238             __dwExpectedCallbackState |= COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE;   \
239         }                                                                           \
240         if (!AreCallbackStateFlagsSet(__dwExpectedCallbackState))                   \
241         {                                                                           \
242             LOG((LF_CORPROF,                                                        \
243                  LL_ERROR,                                                          \
244                  "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE "    \
245                  "due to illegal asynchronous profiler call\n"));                   \
246             return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;                             \
247         }                                                                           \
248     } while(0)
249
250 // INIT_ONLY entrypoints must ensure we're executing inside the profiler's
251 // Initialize() implementation on startup (attach init doesn't count!).
252 #define PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams)                             \
253     do                                                                                          \
254     {                                                                                           \
255         PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams);                                            \
256         if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad &&  \
257             g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForAttachLoad)     \
258         {                                                                                       \
259             return CORPROF_E_CALL_ONLY_FROM_INIT;                                               \
260         }                                                                                       \
261     } while(0)
262
263 // This macro is used to ensure that the current thread is not in a forbid
264 // suspend region.   Some methods are allowed to be called asynchronously,
265 // but some of them call JIT functions that take a reader lock.  So we need to ensure
266 // the current thread hasn't been hijacked by a profiler while it was holding the writer lock.
267 // Checking the ForbidSuspendThread region is a sufficient test for this
268 #define FAIL_IF_IN_FORBID_SUSPEND_REGION()                                  \
269     do                                                                      \
270     {                                                                       \
271         Thread * __pThread = GetThreadNULLOk();                             \
272         if ((__pThread != NULL) && (__pThread->IsInForbidSuspendRegion()))  \
273         {                                                                   \
274         return CORPROF_E_ASYNCHRONOUS_UNSAFE;                               \
275         }                                                                   \
276     } while(0)
277     
278 //
279 // This type is an overlay onto the exported type COR_PRF_FRAME_INFO.
280 // The first four fields *must* line up with the same fields in the
281 // exported type.  After that, we can add to the end as we wish.
282 //
283 typedef struct _COR_PRF_FRAME_INFO_INTERNAL {
284     USHORT size;
285     USHORT version;
286     FunctionID funcID;
287     UINT_PTR IP;
288     void *extraArg;
289     LPVOID thisArg;
290 } COR_PRF_FRAME_INFO_INTERNAL, *PCOR_PRF_FRAME_INFO_INTERNAL;
291
292 //
293 // After we ship a product with a certain struct type for COR_PRF_FRAME_INFO_INTERNAL
294 // we have that as a version.  If we change that in a later product, we can increment
295 // the counter below and then we can properly do versioning.
296 //
297 #define COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION 1
298
299
300 //---------------------------------------------------------------------------------------
301 //
302 // Converts TypeHandle to a ClassID
303 //
304 // Arguments:
305 //      th - TypeHandle to convert
306 //
307 // Return Value:
308 //      Requested ClassID.
309 //
310
311 ClassID TypeHandleToClassID(TypeHandle th)
312 {
313     WRAPPER_NO_CONTRACT;
314     return reinterpret_cast<ClassID> (th.AsPtr());
315 }
316
317 //---------------------------------------------------------------------------------------
318 //
319 // Converts TypeHandle for a non-generic type to a ClassID
320 //
321 // Arguments:
322 //      th - TypeHandle to convert
323 //
324 // Return Value:
325 //      Requested ClassID.  NULL if th represents a generic type
326 //
327 #ifdef PROFILING_SUPPORTED
328
329 static ClassID NonGenericTypeHandleToClassID(TypeHandle th)
330 {
331     CONTRACTL
332     {
333         NOTHROW;
334         GC_NOTRIGGER;
335         MODE_ANY;
336     } CONTRACTL_END;
337     
338     if ((!th.IsNull()) && (th.HasInstantiation()))
339 {
340         return NULL;
341 }
342
343     return TypeHandleToClassID(th);
344 }
345
346 //---------------------------------------------------------------------------------------
347 //
348 // Converts MethodDesc * to FunctionID
349 //
350 // Arguments:
351 //      pMD - MethodDesc * to convert
352 //
353 // Return Value:
354 //      Requested FunctionID
355 //
356
357 static FunctionID MethodDescToFunctionID(MethodDesc * pMD)
358 {
359     LIMITED_METHOD_CONTRACT;
360     return reinterpret_cast< FunctionID > (pMD);
361 }
362
363 #endif
364
365 //---------------------------------------------------------------------------------------
366 //
367 // Converts FunctionID to MethodDesc *
368 //
369 // Arguments:
370 //      functionID - FunctionID to convert
371 //
372 // Return Value:
373 //      MethodDesc * requested
374 //
375
376 MethodDesc *FunctionIdToMethodDesc(FunctionID functionID)
377 {
378     LIMITED_METHOD_CONTRACT;
379     
380     MethodDesc *pMethodDesc;
381
382     pMethodDesc = reinterpret_cast< MethodDesc* >(functionID);
383
384     _ASSERTE(pMethodDesc != NULL);
385     return pMethodDesc;
386 }
387
388 // (See comments for ArrayKindFromTypeHandle below.)
389 typedef enum
390 {
391     ARRAY_KIND_TYPEDESC,        // Normal, garden-variety typedesc array
392     ARRAY_KIND_METHODTABLE,  // Weirdo array with its own unshared methodtable (e.g., System.Object[])
393     ARRAY_KIND_NOTARRAY,       // Not an array
394 } ARRAY_KIND;
395
396 //---------------------------------------------------------------------------------------
397 //
398 // A couple Info calls need to understand what constitutes an "array", and what
399 // kinds of arrays there are.  ArrayKindFromTypeHandle tries to put some of this
400 // knowledge in a single place
401 //
402 // Arguments:
403 //      th - TypeHandle to inspect
404 //
405 // Return Value:
406 //      ARRAY_KIND describing th
407 //
408
409 inline ARRAY_KIND ArrayKindFromTypeHandle(TypeHandle th)
410 {
411     LIMITED_METHOD_CONTRACT;
412
413     if (th.IsArray())
414     {
415         return ARRAY_KIND_TYPEDESC;
416     }
417
418     if (!th.IsTypeDesc() && th.GetMethodTable()->IsArray())
419     {
420         return ARRAY_KIND_METHODTABLE;
421     }
422
423     return ARRAY_KIND_NOTARRAY;
424 }
425
426 #ifdef PROFILING_SUPPORTED
427
428 //---------------------------------------------------------------------------------------
429 // ModuleILHeap IUnknown implementation
430 //
431 // Function headers unnecessary, as MSDN adequately documents IUnknown
432 //
433
434 ULONG ModuleILHeap::AddRef()
435 {
436     // Lifetime of this object is controlled entirely by the CLR.  This
437     // is created on first request, and is automatically destroyed when
438     // the profiler is detached.
439     return 1;
440 }
441
442
443 ULONG ModuleILHeap::Release()
444 {
445     // Lifetime of this object is controlled entirely by the CLR.  This
446     // is created on first request, and is automatically destroyed when
447     // the profiler is detached.
448     return 1;
449 }
450
451
452 HRESULT ModuleILHeap::QueryInterface(REFIID riid, void ** pp)
453 {
454     HRESULT     hr = S_OK;
455
456     if (pp == NULL)
457     {
458         return E_POINTER;
459     }
460
461     *pp = 0;
462     if (riid == IID_IUnknown)
463     {
464         *pp = static_cast<IUnknown *>(this);
465     }
466     else if (riid == IID_IMethodMalloc)
467     {
468         *pp = static_cast<IMethodMalloc *>(this);
469     }
470     else
471     {
472         hr = E_NOINTERFACE;
473     }
474
475     if (hr == S_OK)
476     {
477         // CLR manages lifetime of this object, but in case that changes (or
478         // this code gets copied/pasted elsewhere), we'll still AddRef here so
479         // QI remains a good citizen either way.
480         AddRef();
481     }
482     return hr;
483 }
484
485 //---------------------------------------------------------------------------------------
486 // Profiler entrypoint to allocate space from this module's heap.
487 //
488 // Arguments
489 //      cb - size in bytes of allocation request
490 //
491 // Return value
492 //      pointer to allocated memory, or NULL if there was an error
493
494 void * STDMETHODCALLTYPE ModuleILHeap::Alloc(ULONG cb)
495 {
496     CONTRACTL
497     {
498         // Yay!
499         NOTHROW;
500     
501         // (see GC_TRIGGERS comment below)
502         CAN_TAKE_LOCK;
503
504         // Allocations using loader heaps below enter a critsec, which switches
505         // to preemptive, which is effectively a GC trigger
506         GC_TRIGGERS;
507
508         // Yay!
509         MODE_ANY;
510
511     } 
512     CONTRACTL_END;
513
514     LOG((LF_CORPROF, LL_INFO1000, "**PROF: ModuleILHeap::Alloc 0x%08xp.\n", cb));
515
516     if (cb == 0)
517     {
518         return NULL;
519     }
520
521     return new (nothrow) BYTE[cb];
522 }
523
524 //---------------------------------------------------------------------------------------
525 // The one and only instance of the IL heap
526
527 ModuleILHeap ModuleILHeap::s_Heap;
528
529 //---------------------------------------------------------------------------------------
530 // Implementation of ProfToEEInterfaceImpl's IUnknown
531
532 //
533 // The VM controls the lifetime of ProfToEEInterfaceImpl, not the
534 // profiler.  We'll automatically take care of cleanup when profilers
535 // unload and detach.
536 //
537
538 ULONG STDMETHODCALLTYPE ProfToEEInterfaceImpl::AddRef()
539     {
540     LIMITED_METHOD_CONTRACT;
541     return 1; 
542 }
543
544 ULONG STDMETHODCALLTYPE ProfToEEInterfaceImpl::Release()
545 {
546     LIMITED_METHOD_CONTRACT;
547     return 1; 
548 }
549
550 COM_METHOD ProfToEEInterfaceImpl::QueryInterface(REFIID id, void ** pInterface)
551 {
552     if (pInterface == NULL)
553     {
554         return E_POINTER;
555     }
556
557     if (id == IID_ICorProfilerInfo)
558     {
559         *pInterface = static_cast<ICorProfilerInfo *>(this);
560     }
561     else if (id == IID_ICorProfilerInfo2)
562     {
563         *pInterface = static_cast<ICorProfilerInfo2 *>(this);
564     }
565     else if (id == IID_ICorProfilerInfo3)
566     {
567         *pInterface = static_cast<ICorProfilerInfo3 *>(this);
568     }
569     else if (id == IID_ICorProfilerInfo4)
570     {
571         *pInterface = static_cast<ICorProfilerInfo4 *>(this);
572     }
573     else if (id == IID_ICorProfilerInfo5)
574     {
575         *pInterface = static_cast<ICorProfilerInfo5 *>(this);
576     }
577     else if (id == IID_ICorProfilerInfo6)
578     {
579         *pInterface = static_cast<ICorProfilerInfo6 *>(this);
580     }
581     else if (id == IID_ICorProfilerInfo7)
582     {
583         *pInterface = static_cast<ICorProfilerInfo7 *>(this);
584     }
585     else if (id == IID_ICorProfilerInfo8)
586     {
587         *pInterface = static_cast<ICorProfilerInfo8 *>(this);
588     }
589     else if (id == IID_ICorProfilerInfo9)
590     {
591         *pInterface = static_cast<ICorProfilerInfo9 *>(this);
592     }
593     else if (id == IID_ICorProfilerInfo10)
594     {
595         *pInterface = static_cast<ICorProfilerInfo10 *>(this);
596     }
597     else if (id == IID_IUnknown)
598     {
599         *pInterface = static_cast<IUnknown *>(static_cast<ICorProfilerInfo *>(this));
600     }
601     else
602     {
603         *pInterface = NULL;
604         return E_NOINTERFACE;
605     }
606
607     // CLR manages lifetime of this object, but in case that changes (or
608     // this code gets copied/pasted elsewhere), we'll still AddRef here so
609     // QI remains a good citizen either way.
610     AddRef();
611
612     return S_OK;
613 }
614 #endif // PROFILING_SUPPORTED
615
616 //---------------------------------------------------------------------------------------
617 //
618 // GC-related helpers.  These are called from elsewhere in the EE to determine profiler
619 // state, and to update the profiling API with info from the GC.
620 //
621
622 //---------------------------------------------------------------------------------------
623 //
624 // ProfilerObjectAllocatedCallback is called if a profiler is attached, requesting
625 // ObjectAllocated callbacks.
626 //
627 // Arguments:
628 //      objref - Reference to newly-allocated object
629 //      classId - ClassID of newly-allocated object
630 //
631
632 void __stdcall ProfilerObjectAllocatedCallback(OBJECTREF objref, ClassID classId)
633 {
634     CONTRACTL 
635 {
636         THROWS;
637         GC_TRIGGERS;
638         MODE_COOPERATIVE;
639     } 
640     CONTRACTL_END;
641     
642     TypeHandle th = OBJECTREFToObject(objref)->GetTypeHandle();
643
644     // WARNING: objref can move as a result of the ObjectAllocated() call below if
645     // the profiler causes a GC, so any operations on the objref should occur above
646     // this comment (unless you're prepared to add a GCPROTECT around the objref).  
647
648 #ifdef PROFILING_SUPPORTED
649     // Notify the profiler of the allocation
650
651     {
652         BEGIN_PIN_PROFILER(CORProfilerTrackAllocations() || CORProfilerTrackLargeAllocations());
653         // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs.
654         // Thus we strip any instantiations of the ClassID (which is really a type handle) here.
655         g_profControlBlock.pProfInterface->ObjectAllocated(
656                 (ObjectID) OBJECTREFToObject(objref), 
657                 classId);
658         END_PIN_PROFILER();
659     }
660 #endif // PROFILING_SUPPORTED
661 }
662
663 //---------------------------------------------------------------------------------------
664 //
665 // Wrapper around the GC Started callback
666 //
667 // Arguments:
668 //      generation - Generation being collected
669 //      induced - Was this GC induced by GC.Collect?
670 //
671
672 void __stdcall GarbageCollectionStartedCallback(int generation, BOOL induced)
673 {
674     CONTRACTL 
675     {
676         NOTHROW;
677         GC_NOTRIGGER;
678         MODE_ANY; // can be called even on GC threads
679     } 
680     CONTRACTL_END;
681
682 #ifdef PROFILING_SUPPORTED
683     //
684     // Mark that we are starting a GC.  This will allow profilers to do limited object inspection
685     // during callbacks that occur while a GC is happening.
686     //
687     g_profControlBlock.fGCInProgress = TRUE;
688
689     // Notify the profiler of start of the collection
690     {
691         BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
692         BOOL generationCollected[COR_PRF_GC_LARGE_OBJECT_HEAP+1];
693         if (generation == COR_PRF_GC_GEN_2)
694             generation = COR_PRF_GC_LARGE_OBJECT_HEAP;
695         for (int gen = 0; gen <= COR_PRF_GC_LARGE_OBJECT_HEAP; gen++)
696             generationCollected[gen] = gen <= generation;
697
698         g_profControlBlock.pProfInterface->GarbageCollectionStarted(
699             COR_PRF_GC_LARGE_OBJECT_HEAP+1, 
700             generationCollected, 
701             induced ? COR_PRF_GC_INDUCED : COR_PRF_GC_OTHER);
702         END_PIN_PROFILER();
703     }
704 #endif // PROFILING_SUPPORTED
705 }
706
707 //---------------------------------------------------------------------------------------
708 //
709 // Wrapper around the GC Finished callback
710 //
711
712 void __stdcall GarbageCollectionFinishedCallback()
713 {
714     CONTRACTL 
715     {
716         NOTHROW;
717         GC_NOTRIGGER;
718         MODE_ANY; // can be called even on GC threads        
719     } 
720     CONTRACTL_END;
721
722 #ifdef PROFILING_SUPPORTED
723     // Notify the profiler of end of the collection
724     {
725         BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
726         g_profControlBlock.pProfInterface->GarbageCollectionFinished();
727         END_PIN_PROFILER();
728     }
729
730     // Mark that GC is finished.
731     g_profControlBlock.fGCInProgress = FALSE;
732 #endif // PROFILING_SUPPORTED
733 }
734
735 #ifdef PROFILING_SUPPORTED
736 //---------------------------------------------------------------------------------------
737 //
738 // Describes a GC generation by number and address range
739 //
740
741 struct GenerationDesc
742 {
743     int generation;
744     BYTE *rangeStart;
745     BYTE *rangeEnd;
746     BYTE *rangeEndReserved;
747 };
748
749 struct GenerationTable
750 {
751     ULONG count;
752     ULONG capacity;
753     static const ULONG defaultCapacity = 4; // that's the minimum for 3 generation plus the large object heap
754     GenerationTable *prev;
755     GenerationDesc *genDescTable;
756 #ifdef  _DEBUG
757     ULONG magic;
758 #define GENERATION_TABLE_MAGIC 0x34781256
759 #define GENERATION_TABLE_BAD_MAGIC 0x55aa55aa
760 #endif
761 };
762
763
764 //---------------------------------------------------------------------------------------
765 //
766 // This is a callback used by the GC when we call GCHeapUtilities::DiagDescrGenerations
767 // (from UpdateGenerationBounds() below).  The GC gives us generation information through
768 // this callback, which we use to update the GenerationDesc in the corresponding
769 // GenerationTable
770 //
771 // Arguments:
772 //      context - The containing GenerationTable
773 //      generation - Generation number
774 //      rangeStart - Address where generation starts
775 //      rangeEnd - Address where generation ends
776 //      rangeEndReserved - Address where generation reserved space ends
777 //
778
779 // static
780 static void GenWalkFunc(void * context,
781                         int generation, 
782                         BYTE * rangeStart, 
783                         BYTE * rangeEnd,
784                         BYTE * rangeEndReserved)
785 {
786     CONTRACT_VOID
787     {
788         NOTHROW;
789         GC_NOTRIGGER;
790         MODE_ANY; // can be called even on GC threads        
791         PRECONDITION(CheckPointer(context));
792         PRECONDITION(0 <= generation && generation <= 3);
793         PRECONDITION(CheckPointer(rangeStart));
794         PRECONDITION(CheckPointer(rangeEnd));
795         PRECONDITION(CheckPointer(rangeEndReserved));
796     } CONTRACT_END;
797
798     GenerationTable *generationTable = (GenerationTable *)context;
799
800     _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
801
802     ULONG count = generationTable->count;
803     if (count >= generationTable->capacity)
804     {
805         ULONG newCapacity = generationTable->capacity == 0 ? GenerationTable::defaultCapacity : generationTable->capacity * 2;
806         GenerationDesc *newGenDescTable = new (nothrow) GenerationDesc[newCapacity];
807         if (newGenDescTable == NULL)
808         {
809             // if we can't allocate a bigger table, we'll have to ignore this call
810             RETURN;
811         }
812         memcpy(newGenDescTable, generationTable->genDescTable, sizeof(generationTable->genDescTable[0]) * generationTable->count);
813         delete[] generationTable->genDescTable;
814         generationTable->genDescTable = newGenDescTable;
815         generationTable->capacity = newCapacity;
816     }
817     _ASSERTE(count < generationTable->capacity);
818
819     GenerationDesc *genDescTable = generationTable->genDescTable;
820
821     genDescTable[count].generation = generation;
822     genDescTable[count].rangeStart = rangeStart;
823     genDescTable[count].rangeEnd = rangeEnd;
824     genDescTable[count].rangeEndReserved = rangeEndReserved;
825
826     generationTable->count = count + 1;
827 }
828
829 // This is the table of generation bounds updated by the gc 
830 // and read by the profiler. So this is a single writer,
831 // multiple readers scenario.
832 static GenerationTable *s_currentGenerationTable;
833
834 // The generation table is updated atomically by replacing the
835 // pointer to it. The only tricky part is knowing when
836 // the old table can be deleted.
837 static Volatile<LONG> s_generationTableLock;
838
839 // This is just so we can assert there's a single writer
840 #ifdef  ENABLE_CONTRACTS
841 static Volatile<LONG> s_generationTableWriterCount;
842 #endif
843 #endif // PROFILING_SUPPORTED
844
845 //---------------------------------------------------------------------------------------
846 //
847 // This is called from the gc to push a new set of generation bounds
848 //
849
850 void __stdcall UpdateGenerationBounds()
851 {
852     CONTRACT_VOID
853     {
854         NOTHROW;
855         GC_NOTRIGGER;
856         MODE_ANY; // can be called even on GC threads        
857 #ifdef PROFILING_SUPPORTED
858         PRECONDITION(FastInterlockIncrement(&s_generationTableWriterCount) == 1);
859         POSTCONDITION(FastInterlockDecrement(&s_generationTableWriterCount) == 0);
860 #endif // PROFILING_SUPPORTED
861     } CONTRACT_END;
862
863 #ifdef PROFILING_SUPPORTED
864     // Notify the profiler of start of the collection
865     if (CORProfilerTrackGC() || CORProfilerTrackBasicGC())
866     {
867         // generate a new generation table
868         GenerationTable *newGenerationTable = new (nothrow) GenerationTable();
869         if (newGenerationTable == NULL)
870             RETURN;
871         newGenerationTable->count = 0;
872         newGenerationTable->capacity = GenerationTable::defaultCapacity;
873         // if there is already a current table, use its count as a guess for the capacity
874         if (s_currentGenerationTable != NULL)
875             newGenerationTable->capacity = s_currentGenerationTable->count;
876         newGenerationTable->prev = NULL;
877         newGenerationTable->genDescTable = new (nothrow) GenerationDesc[newGenerationTable->capacity];
878         if (newGenerationTable->genDescTable == NULL)
879             newGenerationTable->capacity = 0;
880
881 #ifdef  _DEBUG
882         newGenerationTable->magic = GENERATION_TABLE_MAGIC;
883 #endif
884         // fill in the values by calling back into the gc, which will report
885         // the ranges by calling GenWalkFunc for each one
886         IGCHeap *hp = GCHeapUtilities::GetGCHeap();
887         hp->DiagDescrGenerations(GenWalkFunc, newGenerationTable);
888
889         // remember the old table and plug in the new one
890         GenerationTable *oldGenerationTable = s_currentGenerationTable;
891         s_currentGenerationTable = newGenerationTable;
892
893         // WARNING: tricky code!
894         //
895         // We sample the generation table lock *after* plugging in the new table
896         // We do so using an interlocked operation so the cpu can't reorder
897         // the write to the s_currentGenerationTable with the increment.
898         // If the interlocked increment returns 1, we know nobody can be using
899         // the old table (readers increment the lock before using the table,
900         // and decrement it afterwards). Any new readers coming in
901         // will use the new table. So it's safe to delete the old
902         // table.
903         // On the other hand, if the interlocked increment returns
904         // something other than one, we put the old table on a list
905         // dangling off of the new one. Next time around, we'll try again
906         // deleting any old tables.
907         if (FastInterlockIncrement(&s_generationTableLock) == 1)
908         {
909             // We know nobody can be using any of the old tables
910             while (oldGenerationTable != NULL)
911             {
912                 _ASSERTE(oldGenerationTable->magic == GENERATION_TABLE_MAGIC);
913 #ifdef  _DEBUG
914                 oldGenerationTable->magic = GENERATION_TABLE_BAD_MAGIC;
915 #endif
916                 GenerationTable *temp = oldGenerationTable;
917                 oldGenerationTable = oldGenerationTable->prev;
918                 delete[] temp->genDescTable;
919                 delete temp;
920             }
921         }
922         else
923         {
924             // put the old table on a list
925             newGenerationTable->prev = oldGenerationTable;
926         }
927         FastInterlockDecrement(&s_generationTableLock);
928     }
929 #endif // PROFILING_SUPPORTED
930     RETURN;
931 }
932
933 #ifdef PROFILING_SUPPORTED
934
935 //---------------------------------------------------------------------------------------
936 //
937 // Determines whether we are in a window to allow object inspection.
938 //
939 // Return Value:
940 //      Returns S_OK if we can determine that we are in a window to allow object
941 //      inspection.  Otherwise a failure HRESULT is returned
942 //
943
944 HRESULT AllowObjectInspection()
945 {
946     CONTRACTL
947     {
948         NOTHROW;
949         GC_NOTRIGGER;
950         MODE_ANY; // tests for preemptive mode dynamically as its main function so contract enforcement is not appropriate
951     } 
952     CONTRACTL_END;
953
954     //
955     // Check first to see if we are in the process of doing a GC and presume that the profiler
956     // is making this object inspection from the same thread that notified of a valid ObjectID.
957     //
958     if (g_profControlBlock.fGCInProgress)
959     {
960         return S_OK;
961     }
962
963     //
964     // Thus we must have a managed thread, and it must be in coop mode.
965     // (That will also guarantee we're in a callback).
966     //
967     Thread * pThread = GetThreadNULLOk();
968
969     if (pThread == NULL)
970     {
971         return CORPROF_E_NOT_MANAGED_THREAD;
972     }
973
974     // Note this is why we don't enforce the contract of being in cooperative mode the whole point
975     // is that clients of this fellow want to return a robust error if not cooperative
976     // so technically they are mode_any although the only true preemptive support they offer
977     // is graceful failure in that case
978     if (!pThread->PreemptiveGCDisabled())
979     {
980         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
981     }
982
983     return S_OK;
984 }
985
986 //---------------------------------------------------------------------------------------
987 //
988 // helper functions for the GC events
989 //
990
991
992 #endif // PROFILING_SUPPORTED
993
994 #if defined(PROFILING_SUPPORTED) || defined(FEATURE_EVENT_TRACE)
995
996 //---------------------------------------------------------------------------------------
997 //
998 // It's generally unsafe for profiling API code to call Get(GCSafe)TypeHandle() on
999 // objects, since we can encounter objects on the heap whose types belong to unloading
1000 // AppDomains. In such cases, getting the type handle of the object could AV.  Use this
1001 // function instead, which will return NULL for potentially unloaded types.
1002 // 
1003 // Arguments:
1004 //      pObj - Object * whose ClassID is desired
1005 //
1006 // Return Value:
1007 //      ClassID of the object, if it's safe to look it up. Else NULL.
1008 //
1009
1010 ClassID SafeGetClassIDFromObject(Object * pObj)
1011 {
1012     CONTRACTL
1013     {
1014         NOTHROW;
1015         GC_NOTRIGGER;
1016     } 
1017     CONTRACTL_END;
1018
1019     TypeHandle th = pObj->GetGCSafeTypeHandleIfPossible();
1020     if(th == NULL)
1021     {
1022         return NULL;
1023     }
1024
1025     return TypeHandleToClassID(th);
1026 }
1027
1028 //---------------------------------------------------------------------------------------
1029 //
1030 // Callback of type walk_fn used by IGCHeap::DiagWalkObject.  Keeps a count of each
1031 // object reference found.
1032 //
1033 // Arguments:
1034 //      pBO - Object reference encountered in walk
1035 //      context - running count of object references encountered
1036 //
1037 // Return Value:
1038 //      Always returns TRUE to object walker so it walks the entire object
1039 //
1040
1041 bool CountContainedObjectRef(Object * pBO, void * context)
1042 {
1043     LIMITED_METHOD_CONTRACT;
1044     // Increase the count
1045     (*((size_t *)context))++;
1046
1047     return TRUE;
1048 }
1049
1050 //---------------------------------------------------------------------------------------
1051 //
1052 // Callback of type walk_fn used by IGCHeap::DiagWalkObject.  Stores each object reference
1053 // encountered into an array.
1054 //
1055 // Arguments:
1056 //      pBO - Object reference encountered in walk
1057 //      context - Array of locations within the walked object that point to other
1058 //                objects.  On entry, (*context) points to the next unfilled array
1059 //                entry.  On exit, that location is filled, and (*context) is incremented
1060 //                to point to the next entry.
1061 //
1062 // Return Value:
1063 //      Always returns TRUE to object walker so it walks the entire object
1064 //
1065
1066 bool SaveContainedObjectRef(Object * pBO, void * context)
1067 {
1068     LIMITED_METHOD_CONTRACT;
1069     // Assign the value
1070     **((Object ***)context) = pBO;
1071
1072     // Now increment the array pointer
1073     //
1074     // Note that HeapWalkHelper has already walked the references once to count them up,
1075     // and then allocated an array big enough to hold those references.  First time this
1076     // callback is called for a given object, (*context) points to the first entry in the
1077     // array.  So "blindly" incrementing (*context) here and using it next time around
1078     // for the next reference, over and over again, should be safe.
1079     (*((Object ***)context))++;
1080
1081     return TRUE;
1082 }
1083
1084 typedef struct _ObjectRefOffsetTuple
1085 {
1086     Object* pCurObjRef;
1087     SIZE_T* pCurObjOffset;
1088 } ObjectRefOffsetTuple;
1089
1090 //---------------------------------------------------------------------------------------
1091 //
1092 // Callback of type walk_fn used by IGCHeap::DiagWalkObject.  Stores each object reference
1093 // encountered into an array.
1094 //
1095 // Arguments:
1096 //      o - original object
1097 //      pBO - Object reference encountered in walk
1098 //      context - Array of locations within the walked object that point to other
1099 //                objects.  On entry, (*context) points to the next unfilled array
1100 //                entry.  On exit, that location is filled, and (*context) is incremented
1101 //                to point to the next entry.
1102 //
1103 // Return Value:
1104 //      Always returns TRUE to object walker so it walks the entire object
1105 //
1106
1107 bool SaveContainedObjectRef2(Object* o, uint8_t** pBO, void* context)
1108 {
1109     LIMITED_METHOD_CONTRACT;
1110
1111     auto x = (ObjectRefOffsetTuple*)context;
1112     *((Object **)(x->pCurObjRef)) = (Object *)*pBO;
1113     *((SIZE_T **)(x->pCurObjOffset)) = (SIZE_T*)((uint8_t*)pBO - (uint8_t*)o);
1114
1115     x->pCurObjRef++;
1116     x->pCurObjOffset++;
1117
1118     return TRUE;
1119 }
1120
1121 //---------------------------------------------------------------------------------------
1122 //
1123 // Callback of type walk_fn used by the GC when walking the heap, to help profapi and ETW
1124 // track objects.  This guy orchestrates the use of the above callbacks which dig
1125 // into object references contained each object encountered by this callback.
1126 // This method is defined when either GC_PROFILING is defined or FEATURE_EVENT_TRACING
1127 // is defined and can operate fully when only one of the two is defined.
1128 //
1129 // Arguments:
1130 //      pBO - Object reference encountered on the heap
1131 //      pvContext - Pointer to ProfilerWalkHeapContext, containing ETW context built up
1132 //       during this GC, and which remembers if profapi-profiler is supposed to be called.
1133 //
1134 // Return Value:
1135 //      BOOL indicating whether the heap walk should continue.
1136 //      TRUE=continue
1137 //      FALSE=stop
1138 //
1139 extern bool s_forcedGCInProgress;
1140
1141 bool HeapWalkHelper(Object * pBO, void * pvContext)
1142 {
1143     CONTRACTL
1144     {
1145         NOTHROW;
1146         GC_NOTRIGGER;
1147         MODE_ANY;
1148     }
1149     CONTRACTL_END;
1150
1151     OBJECTREF *   arrObjRef      = NULL;
1152     size_t        cNumRefs       = 0;
1153     bool          bOnStack       = false;
1154     MethodTable * pMT            = pBO->GetMethodTable();
1155
1156     ProfilerWalkHeapContext * pProfilerWalkHeapContext = (ProfilerWalkHeapContext *) pvContext;
1157
1158     if (pMT->ContainsPointersOrCollectible())
1159     {
1160         // First round through calculates the number of object refs for this class
1161         GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &CountContainedObjectRef, (void *)&cNumRefs);
1162
1163         if (cNumRefs > 0)
1164         {
1165             // Create an array to contain all of the refs for this object
1166             bOnStack = cNumRefs <= 32 ? true : false;
1167
1168             if (bOnStack)
1169             {
1170                 // It's small enough, so just allocate on the stack
1171                 arrObjRef = (OBJECTREF *)_alloca(cNumRefs * sizeof(OBJECTREF));
1172             }
1173             else
1174             {
1175                 // Otherwise, allocate from the heap
1176                 arrObjRef = new (nothrow) OBJECTREF[cNumRefs];
1177
1178                 if (!arrObjRef)
1179                 {
1180                     return FALSE;
1181                 }
1182             }
1183
1184             // Second round saves off all of the ref values
1185             OBJECTREF * pCurObjRef = arrObjRef;
1186             GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &SaveContainedObjectRef, (void *)&pCurObjRef);
1187         }
1188     }
1189
1190     HRESULT hr = E_FAIL;
1191
1192 #if defined(GC_PROFILING)
1193     if (pProfilerWalkHeapContext->fProfilerPinned)
1194     {
1195         // It is not safe and could be overflowed to downcast size_t to ULONG on WIN64.
1196         // However, we have to do this dangerous downcast here to comply with the existing Profiling COM interface.
1197         // We are currently evaluating ways to fix this potential overflow issue.
1198         hr = g_profControlBlock.pProfInterface->ObjectReference(
1199             (ObjectID) pBO, 
1200             SafeGetClassIDFromObject(pBO),
1201             (ULONG) cNumRefs, 
1202             (ObjectID *) arrObjRef);
1203     }
1204 #endif
1205
1206 #ifdef FEATURE_EVENT_TRACE
1207     if (s_forcedGCInProgress &&
1208         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
1209                                      TRACE_LEVEL_INFORMATION, 
1210                                      CLR_GCHEAPDUMP_KEYWORD))
1211     {
1212         ETW::GCLog::ObjectReference(
1213             pProfilerWalkHeapContext,
1214             pBO,
1215             (ULONGLONG) SafeGetClassIDFromObject(pBO),
1216             cNumRefs,
1217             (Object **) arrObjRef);
1218
1219     }
1220 #endif // FEATURE_EVENT_TRACE
1221
1222     // If the data was not allocated on the stack, need to clean it up.
1223     if ((arrObjRef != NULL) && !bOnStack)
1224     {
1225         delete [] arrObjRef;
1226     }
1227
1228     // Return TRUE iff we want to the heap walk to continue. The only way we'd abort the
1229     // heap walk is if we're issuing profapi callbacks, and the profapi profiler
1230     // intentionally returned a failed HR (as its request that we stop the walk). There's
1231     // a potential conflict here. If a profapi profiler and an ETW profiler are both
1232     // monitoring the heap dump, and the profapi profiler requests to abort the walk (but
1233     // the ETW profiler may not want to abort the walk), then what do we do? The profapi
1234     // profiler gets precedence. We don't want to accidentally send more callbacks to a
1235     // profapi profiler that explicitly requested an abort. The ETW profiler will just
1236     // have to deal. In theory, I could make the code more complex by remembering that a
1237     // profapi profiler requested to abort the dump but an ETW profiler is still
1238     // attached, and then intentionally inhibit the remainder of the profapi callbacks
1239     // for this GC. But that's unnecessary complexity. In practice, it should be
1240     // extremely rare that a profapi profiler is monitoring heap dumps AND an ETW
1241     // profiler is also monitoring heap dumps.
1242     return (pProfilerWalkHeapContext->fProfilerPinned) ? SUCCEEDED(hr) : TRUE;
1243 }
1244
1245 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACING)
1246
1247 #ifdef PROFILING_SUPPORTED
1248 //---------------------------------------------------------------------------------------
1249 //
1250 // Callback of type walk_fn used by the GC when walking the heap, to help profapi
1251 // track objects.  This is really just a wrapper around
1252 // EEToProfInterfaceImpl::AllocByClass, which does the real work
1253 //
1254 // Arguments:
1255 //      pBO - Object reference encountered on the heap
1256 //      pv - Structure used by EEToProfInterfaceImpl::AllocByClass to do its work.
1257 //
1258 // Return Value:
1259 //      BOOL indicating whether the heap walk should continue.
1260 //      TRUE=continue
1261 //      FALSE=stop
1262 //      Currently always returns TRUE
1263 //
1264
1265 bool AllocByClassHelper(Object * pBO, void * pv)
1266 {
1267     CONTRACTL
1268     {
1269         NOTHROW;
1270         GC_NOTRIGGER;
1271         MODE_ANY;
1272     }
1273     CONTRACTL_END;
1274     _ASSERTE(pv != NULL);
1275
1276     {
1277         BEGIN_PIN_PROFILER(CORProfilerPresent());
1278         // Pass along the call
1279         g_profControlBlock.pProfInterface->AllocByClass(
1280             (ObjectID) pBO, 
1281             SafeGetClassIDFromObject(pBO), 
1282             pv);
1283         END_PIN_PROFILER();
1284     }
1285
1286     return TRUE;
1287 }
1288
1289 #endif // PROFILING_SUPPORTED
1290 #if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1291
1292 //---------------------------------------------------------------------------------------
1293 //
1294 // Callback of type promote_func called by GC while scanning roots (in GCProfileWalkHeap,
1295 // called after the collection).  Wrapper around EEToProfInterfaceImpl::RootReference2,
1296 // which does the real work.
1297 //
1298 // Arguments:
1299 //      pObj - Object reference encountered
1300 ///     ppRoot - Address that references ppObject (can be interior pointer)
1301 //      pSC - ProfilingScanContext * containing the root kind and GCReferencesData used
1302 //            by RootReference2 
1303 //      dwFlags - Properties of the root as GC_CALL* constants (this function converts
1304 //                to COR_PRF_GC_ROOT_FLAGS.
1305 //
1306
1307 void ScanRootsHelper(Object* pObj, Object ** ppRoot, ScanContext *pSC, uint32_t dwFlags)
1308 {
1309     CONTRACTL
1310     {
1311         NOTHROW;
1312         GC_NOTRIGGER;
1313         MODE_ANY;
1314     }
1315     CONTRACTL_END;
1316
1317     // RootReference2 can return E_OUTOFMEMORY, and we're swallowing that.
1318     // Furthermore, we can't really handle it because we're callable during GC promotion.
1319     // On the other hand, this only means profiling information will be incomplete,
1320     // so it's ok to swallow E_OUTOFMEMORY.
1321     //
1322     FAULT_NOT_FATAL();
1323
1324     ProfilingScanContext *pPSC = (ProfilingScanContext *)pSC;
1325
1326     DWORD dwEtwRootFlags = 0;
1327     if (dwFlags & GC_CALL_INTERIOR)
1328         dwEtwRootFlags |= kEtwGCRootFlagsInterior;
1329     if (dwFlags & GC_CALL_PINNED)
1330         dwEtwRootFlags |= kEtwGCRootFlagsPinning;
1331
1332 #if defined(GC_PROFILING)
1333     void *rootID = NULL;
1334     switch (pPSC->dwEtwRootKind)
1335     {
1336     case    kEtwGCRootKindStack:
1337         rootID = pPSC->pMD;
1338         break;
1339
1340     case    kEtwGCRootKindHandle:
1341         _ASSERT(!"Shouldn't see handle here");
1342
1343     case    kEtwGCRootKindFinalizer:
1344     default:
1345         break;
1346     }
1347
1348     // Notify profiling API of the root
1349     if (pPSC->fProfilerPinned)
1350     {
1351         // Let the profiling code know about this root reference
1352         g_profControlBlock.pProfInterface->
1353             RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId));
1354     }
1355 #endif
1356
1357 #ifdef FEATURE_EVENT_TRACE
1358     // Notify ETW of the root
1359     if (s_forcedGCInProgress &&
1360         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
1361                                      TRACE_LEVEL_INFORMATION, 
1362                                      CLR_GCHEAPDUMP_KEYWORD))
1363     {
1364         ETW::GCLog::RootReference(
1365             NULL,           // handle is NULL, cuz this is a non-HANDLE root
1366             pObj,           // object being rooted
1367             NULL,           // pSecondaryNodeForDependentHandle is NULL, cuz this isn't a dependent handle
1368             FALSE,          // is dependent handle
1369             pPSC,
1370             dwFlags,        // dwGCFlags
1371             dwEtwRootFlags);
1372     }
1373 #endif // FEATURE_EVENT_TRACE
1374 }
1375
1376 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1377 #ifdef PROFILING_SUPPORTED
1378
1379 //---------------------------------------------------------------------------------------
1380 //
1381 // Private ProfToEEInterfaceImpl maintenance functions
1382 //
1383
1384
1385 //---------------------------------------------------------------------------------------
1386 //
1387 // Initialize ProfToEEInterfaceImpl (including ModuleILHeap statics)
1388 //
1389 // Return Value:
1390 //      HRESULT indicating success
1391 //
1392
1393 HRESULT ProfToEEInterfaceImpl::Init()
1394 {
1395     CONTRACTL
1396     {
1397         NOTHROW;
1398         CANNOT_TAKE_LOCK;
1399         GC_NOTRIGGER;
1400         MODE_ANY;
1401     } 
1402     CONTRACTL_END;
1403
1404     LOG((LF_CORPROF, LL_INFO1000, "**PROF: Init.\n"));
1405
1406 #ifdef _DEBUG
1407     if (ProfilingAPIUtility::ShouldInjectProfAPIFault(kProfAPIFault_StartupInternal))
1408     {
1409         return E_OUTOFMEMORY;
1410     }
1411 #endif //_DEBUG
1412     
1413     return S_OK;
1414 }
1415
1416
1417 //---------------------------------------------------------------------------------------
1418 //
1419 // Destroy ProfToEEInterfaceImpl (including ModuleILHeap statics)
1420 //
1421     
1422 ProfToEEInterfaceImpl::~ProfToEEInterfaceImpl()
1423 {
1424     CONTRACTL
1425     {
1426         NOTHROW;
1427         GC_NOTRIGGER;
1428         MODE_ANY;
1429     }
1430     CONTRACTL_END;
1431
1432     LOG((LF_CORPROF, LL_INFO1000, "**PROF: Terminate.\n"));
1433 }
1434
1435 //---------------------------------------------------------------------------------------
1436 //
1437 // Obsolete info functions
1438 //
1439
1440 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionInterface(IUnknown **)
1441 {
1442     LIMITED_METHOD_CONTRACT;
1443     return E_NOTIMPL; 
1444 }
1445
1446 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionIThisThread(IUnknown **)
1447 {
1448     LIMITED_METHOD_CONTRACT;
1449     return E_NOTIMPL; 
1450 }
1451
1452 HRESULT ProfToEEInterfaceImpl::BeginInprocDebugging(BOOL, DWORD *)
1453 {
1454     LIMITED_METHOD_CONTRACT;
1455     return E_NOTIMPL; 
1456 }
1457
1458 HRESULT ProfToEEInterfaceImpl::EndInprocDebugging(DWORD)
1459 {
1460     LIMITED_METHOD_CONTRACT;
1461     return E_NOTIMPL; 
1462 }
1463
1464 HRESULT ProfToEEInterfaceImpl::SetFunctionReJIT(FunctionID)
1465 {
1466     LIMITED_METHOD_CONTRACT;
1467     return E_NOTIMPL; 
1468 }
1469
1470
1471
1472
1473 //---------------------------------------------------------------------------------------
1474 //
1475 // *******************************
1476 // Public Profiler->EE entrypoints
1477 // *******************************
1478 //
1479 // ProfToEEInterfaceImpl implementation of public ICorProfilerInfo* methods
1480 //
1481 // NOTE: All ICorProfilerInfo* method implementations must follow the rules stated
1482 // at the top of this file!
1483 //
1484
1485 // See corprof.idl / MSDN for detailed comments about each of these public
1486 // functions, their parameters, return values, etc.
1487
1488 HRESULT ProfToEEInterfaceImpl::SetEventMask(DWORD dwEventMask)
1489 {
1490     CONTRACTL
1491     {
1492         // Yay!
1493         NOTHROW;
1494
1495         // Yay!
1496         GC_NOTRIGGER;
1497
1498         // Yay!
1499         MODE_ANY;
1500
1501         // Yay!
1502         EE_THREAD_NOT_REQUIRED;
1503
1504         CANNOT_TAKE_LOCK;
1505
1506     }
1507     CONTRACTL_END;
1508
1509     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1510         (LF_CORPROF, 
1511         LL_INFO1000, 
1512         "**PROF: SetEventMask 0x%08x.\n",
1513         dwEventMask));
1514
1515     _ASSERTE(CORProfilerPresentOrInitializing());
1516
1517     return g_profControlBlock.pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */);
1518 }
1519
1520 HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHigh)
1521 {
1522     CONTRACTL
1523     {
1524         // Yay!
1525         NOTHROW;
1526
1527         // Yay!
1528         GC_NOTRIGGER;
1529
1530         // Yay!
1531         MODE_ANY;
1532
1533         // Yay!
1534         EE_THREAD_NOT_REQUIRED;
1535
1536         CANNOT_TAKE_LOCK;
1537
1538     }
1539     CONTRACTL_END;
1540
1541     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1542         (LF_CORPROF, 
1543         LL_INFO1000, 
1544         "**PROF: SetEventMask2 0x%08x, 0x%08x.\n",
1545         dwEventsLow, dwEventsHigh));
1546
1547     _ASSERTE(CORProfilerPresentOrInitializing());
1548  
1549     return g_profControlBlock.pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh);
1550 }
1551
1552
1553 HRESULT ProfToEEInterfaceImpl::GetHandleFromThread(ThreadID threadId, HANDLE *phThread)
1554 {
1555     CONTRACTL
1556 {
1557         // Yay!
1558         NOTHROW;
1559
1560         // Yay!
1561         GC_NOTRIGGER;
1562     
1563         // Yay!
1564         MODE_ANY;
1565
1566         // Yay!
1567         EE_THREAD_NOT_REQUIRED;
1568
1569         // Yay!
1570         CANNOT_TAKE_LOCK;
1571     
1572     }
1573     CONTRACTL_END;
1574
1575     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1576         (LF_CORPROF, 
1577         LL_INFO1000, 
1578         "**PROF: GetHandleFromThread 0x%p.\n", 
1579         threadId));
1580
1581     if (!IsManagedThread(threadId))
1582     {
1583         return E_INVALIDARG;
1584     }
1585
1586     HRESULT hr = S_OK;
1587
1588     HANDLE hThread = ((Thread *)threadId)->GetThreadHandle();
1589
1590     if (hThread == INVALID_HANDLE_VALUE)
1591         hr = E_INVALIDARG;
1592
1593     else if (phThread)
1594         *phThread = hThread;
1595
1596     return (hr);
1597 }
1598
1599 HRESULT ProfToEEInterfaceImpl::GetObjectSize(ObjectID objectId, ULONG *pcSize)
1600 {
1601     CONTRACTL
1602     {
1603         // Yay!
1604         NOTHROW;
1605
1606         // Yay!
1607         GC_NOTRIGGER;
1608
1609         // Yay!  Fail at runtime if in preemptive mode via AllowObjectInspection()
1610         MODE_ANY;
1611
1612         // Yay!
1613         EE_THREAD_NOT_REQUIRED;
1614
1615         // Yay!
1616         CANNOT_TAKE_LOCK;
1617
1618     }
1619     CONTRACTL_END;
1620
1621     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1622         (LF_CORPROF, 
1623          LL_INFO1000, 
1624          "**PROF: GetObjectSize 0x%p.\n", 
1625          objectId));
1626     
1627     if (objectId == NULL)
1628     {
1629         return E_INVALIDARG;
1630     }
1631
1632     HRESULT hr = AllowObjectInspection();
1633     if (FAILED(hr))
1634     {
1635         return hr;
1636     }
1637     
1638     // Get the object pointer
1639     Object *pObj = reinterpret_cast<Object *>(objectId);
1640
1641     // Get the size
1642     if (pcSize)
1643     {
1644         SIZE_T size = pObj->GetSize();
1645
1646         if(size < MIN_OBJECT_SIZE)
1647         {
1648             size = PtrAlign(size);
1649         }
1650
1651         if (size > ULONG_MAX)
1652         {
1653             *pcSize = ULONG_MAX;
1654             return COR_E_OVERFLOW;
1655         }
1656         *pcSize = (ULONG)size; 
1657     }
1658
1659     // Indicate success
1660     return (S_OK);
1661 }
1662
1663 HRESULT ProfToEEInterfaceImpl::GetObjectSize2(ObjectID objectId, SIZE_T *pcSize)
1664 {
1665     CONTRACTL
1666     {
1667         // Yay!
1668         NOTHROW;
1669
1670         // Yay!
1671         GC_NOTRIGGER;
1672
1673         // Yay!  Fail at runtime if in preemptive mode via AllowObjectInspection()
1674         MODE_ANY;
1675
1676         // Yay!
1677         EE_THREAD_NOT_REQUIRED;
1678
1679         // Yay!
1680         CANNOT_TAKE_LOCK;
1681
1682     }
1683     CONTRACTL_END;
1684
1685     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1686         (LF_CORPROF, 
1687          LL_INFO1000, 
1688          "**PROF: GetObjectSize2 0x%p.\n", 
1689          objectId));
1690     
1691     if (objectId == NULL)
1692     {
1693         return E_INVALIDARG;
1694     }
1695
1696     HRESULT hr = AllowObjectInspection();
1697     if (FAILED(hr))
1698     {
1699         return hr;
1700     }
1701     
1702     // Get the object pointer
1703     Object *pObj = reinterpret_cast<Object *>(objectId);
1704
1705     // Get the size
1706     if (pcSize)
1707     {
1708         SIZE_T size = pObj->GetSize();
1709
1710         if(size < MIN_OBJECT_SIZE)
1711         {
1712             size = PtrAlign(size);
1713         }
1714
1715         *pcSize = size; 
1716     }
1717
1718     // Indicate success
1719     return (S_OK);
1720 }
1721
1722
1723 HRESULT ProfToEEInterfaceImpl::IsArrayClass(
1724     /* [in] */  ClassID classId,
1725     /* [out] */ CorElementType *pBaseElemType,
1726     /* [out] */ ClassID *pBaseClassId,
1727     /* [out] */ ULONG   *pcRank)
1728 {
1729     CONTRACTL
1730     {
1731         NOTHROW;
1732
1733         GC_NOTRIGGER;
1734         
1735         // Yay!
1736         MODE_ANY;
1737
1738         // Yay!
1739         EE_THREAD_NOT_REQUIRED;
1740
1741         // Yay!
1742         CANNOT_TAKE_LOCK;
1743
1744     }
1745     CONTRACTL_END;
1746
1747     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1748         (LF_CORPROF, 
1749          LL_INFO1000, 
1750          "**PROF: IsArrayClass 0x%p.\n",
1751          classId));
1752
1753     HRESULT hr;
1754     
1755     if (classId == NULL)
1756     {
1757         return E_INVALIDARG;
1758     }
1759
1760     TypeHandle th = TypeHandle::FromPtr((void *)classId);
1761
1762     ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(th);
1763         
1764     // If this is indeed an array class, get some info about it
1765     switch (arrayKind)
1766     {
1767         default:
1768         {
1769             _ASSERTE(!"Unexpected return from ArrayKindFromTypeHandle()");
1770             hr = E_UNEXPECTED;
1771             break;
1772         }
1773             
1774         case ARRAY_KIND_TYPEDESC:
1775         {
1776             // This is actually an array, so cast it up
1777             ArrayTypeDesc *pArr = th.AsArray();
1778
1779             // Fill in the type if they want it
1780             if (pBaseElemType != NULL)
1781             {
1782                 *pBaseElemType = pArr->GetArrayElementTypeHandle().GetVerifierCorElementType();
1783             }
1784
1785             // If this is an array of classes and they wish to have the base type
1786             // If there is no associated class with this type, then there's no problem
1787             // because GetClass returns NULL which is the default we want to return in
1788             // this case.
1789             // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
1790             if (pBaseClassId != NULL)
1791             {
1792                 *pBaseClassId = TypeHandleToClassID(pArr->GetTypeParam());
1793             }
1794
1795             // If they want the number of dimensions of the array
1796             if (pcRank != NULL)
1797             {
1798                 *pcRank = (ULONG) pArr->GetRank();
1799             }
1800
1801             // S_OK indicates that this was indeed an array
1802             hr = S_OK;
1803             break;
1804         }
1805         case ARRAY_KIND_METHODTABLE:
1806         {
1807             MethodTable *pArrMT = th.GetMethodTable();
1808
1809             // Fill in the type if they want it
1810             if (pBaseElemType != NULL)
1811             {
1812                 *pBaseElemType = pArrMT->GetArrayElementType();
1813             }
1814
1815             // If this is an array of classes and they wish to have the base type.
1816             if (pBaseClassId != NULL)
1817             {
1818                 *pBaseClassId = TypeHandleToClassID(pArrMT->GetApproxArrayElementTypeHandle());
1819             }
1820
1821             // If they want the number of dimensions of the array
1822             if (pcRank != NULL)
1823             {
1824                 *pcRank = (ULONG) pArrMT->GetRank();
1825             }
1826
1827             // S_OK indicates that this was indeed an array
1828             hr = S_OK;
1829             break;
1830         }
1831         case ARRAY_KIND_NOTARRAY:
1832         {
1833             if (pBaseClassId != NULL)
1834             {
1835                 *pBaseClassId = NULL;
1836             }
1837             
1838             // This is not an array, S_FALSE indicates so.
1839             hr = S_FALSE;
1840             break;
1841         }
1842     }
1843
1844     return hr;
1845 }
1846     
1847 HRESULT ProfToEEInterfaceImpl::GetThreadInfo(ThreadID threadId, DWORD *pdwWin32ThreadId)
1848 {
1849     CONTRACTL
1850     {
1851         // Yay!
1852         NOTHROW;
1853
1854         // Yay!
1855         GC_NOTRIGGER;
1856
1857         // Yay!
1858         MODE_ANY;
1859
1860         // Yay!
1861         EE_THREAD_NOT_REQUIRED;
1862
1863         // Yay!
1864         CANNOT_TAKE_LOCK;
1865
1866     }
1867     CONTRACTL_END;
1868
1869     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1870         (LF_CORPROF, 
1871          LL_INFO1000, 
1872          "**PROF: GetThreadInfo 0x%p.\n", 
1873          threadId));  
1874     
1875     if (!IsManagedThread(threadId))
1876     {
1877         return E_INVALIDARG;
1878     }
1879     
1880     if (pdwWin32ThreadId)
1881     {
1882         *pdwWin32ThreadId = ((Thread *)threadId)->GetOSThreadId();
1883     }
1884
1885     return S_OK;
1886 }
1887
1888 HRESULT ProfToEEInterfaceImpl::GetCurrentThreadID(ThreadID *pThreadId)
1889 {
1890     CONTRACTL
1891     {
1892         // Yay!
1893         NOTHROW;
1894
1895         // Yay!
1896         GC_NOTRIGGER;
1897
1898         // Yay!
1899         MODE_ANY;
1900
1901         // Yay!
1902         EE_THREAD_NOT_REQUIRED;
1903
1904         // Yay!
1905         CANNOT_TAKE_LOCK;
1906
1907     }
1908     CONTRACTL_END;
1909
1910     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1911         (LF_CORPROF, 
1912         LL_INFO1000, 
1913         "**PROF: GetCurrentThreadID.\n"));    
1914
1915     HRESULT hr = S_OK;
1916
1917     // No longer assert that GetThread doesn't return NULL, since callbacks
1918     // can now occur on non-managed threads (such as the GC helper threads)
1919     Thread * pThread = GetThreadNULLOk();
1920
1921     // If pThread is null, then the thread has never run managed code and
1922     // so has no ThreadID
1923     if (!IsManagedThread(pThread))
1924         hr = CORPROF_E_NOT_MANAGED_THREAD;
1925
1926     // Only provide value if they want it
1927     else if (pThreadId)
1928         *pThreadId = (ThreadID) pThread;
1929
1930     return (hr);
1931 }
1932
1933 //---------------------------------------------------------------------------------------
1934 //
1935 // Internal helper function to wrap a call into the JIT manager to get information about
1936 // a managed function based on IP
1937 //
1938 // Arguments:
1939 //      ip - IP address inside managed function of interest
1940 //      ppCodeInfo - [out] information about the managed function based on IP
1941 //
1942 // Return Value:
1943 //     HRESULT indicating success or failure.
1944 //
1945 //
1946
1947 HRESULT GetFunctionInfoInternal(LPCBYTE ip, EECodeInfo * pCodeInfo)
1948 {
1949     CONTRACTL
1950     {
1951         NOTHROW;
1952
1953         GC_NOTRIGGER;
1954         EE_THREAD_NOT_REQUIRED;
1955         CAN_TAKE_LOCK;
1956         CANNOT_RETAKE_LOCK;
1957
1958
1959         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
1960         // host (SQL).  Corners will be cut to ensure this is the case
1961         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
1962     }
1963     CONTRACTL_END;
1964
1965     // Before calling into the code manager, ensure the GC heap has been
1966     // initialized--else the code manager will assert trying to get info from the heap.
1967     if (!IsGarbageCollectorFullyInitialized())
1968     {
1969         return CORPROF_E_NOT_YET_AVAILABLE;
1970     }
1971
1972     if (ShouldAvoidHostCalls())
1973     {
1974         ExecutionManager::ReaderLockHolder rlh(NoHostCalls);
1975         if (!rlh.Acquired())
1976         {
1977             // Couldn't get the info.  Try again later
1978             return CORPROF_E_ASYNCHRONOUS_UNSAFE;
1979         }
1980
1981         pCodeInfo->Init((PCODE)ip, ExecutionManager::ScanNoReaderLock);
1982     }
1983     else
1984     {
1985         pCodeInfo->Init((PCODE)ip);
1986     }
1987
1988     if (!pCodeInfo->IsValid())
1989     {
1990         return E_FAIL;
1991     }
1992
1993     return S_OK;
1994 }
1995
1996
1997 HRESULT GetFunctionFromIPInternal(LPCBYTE ip, EECodeInfo * pCodeInfo, BOOL failOnNoMetadata)
1998 {
1999     CONTRACTL
2000     {
2001         NOTHROW;
2002         GC_NOTRIGGER;
2003         MODE_ANY;
2004         EE_THREAD_NOT_REQUIRED;
2005         CAN_TAKE_LOCK;
2006     }
2007     CONTRACTL_END;
2008
2009     _ASSERTE (pCodeInfo != NULL);
2010
2011     HRESULT hr = GetFunctionInfoInternal(ip, pCodeInfo);
2012     if (FAILED(hr))
2013     {
2014         return hr;
2015     }
2016
2017     if (failOnNoMetadata)
2018     {
2019         // never return a method that the user of the profiler API cannot use
2020         if (pCodeInfo->GetMethodDesc()->IsNoMetadata())
2021         {
2022             return E_FAIL;
2023         }
2024     }
2025
2026     return S_OK;
2027 }
2028
2029
2030 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP(LPCBYTE ip, FunctionID * pFunctionId)
2031 {
2032     CONTRACTL
2033     {
2034         // Yay!
2035         NOTHROW;
2036
2037         // Yay!
2038         GC_NOTRIGGER;
2039
2040         // Yay!
2041         MODE_ANY;
2042
2043         // Yay!
2044         EE_THREAD_NOT_REQUIRED;
2045
2046         // Querying the code manager requires a reader lock.  However, see
2047         // code:#DisableLockOnAsyncCalls
2048         DISABLED(CAN_TAKE_LOCK);
2049
2050         // Asynchronous functions can be called at arbitrary times when runtime 
2051         // is holding locks that cannot be reentered without causing deadlock.
2052         // This contract detects any attempts to reenter locks held at the time 
2053         // this function was called.  
2054         CANNOT_RETAKE_LOCK;
2055
2056
2057         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2058         // host (SQL).  Corners will be cut to ensure this is the case
2059         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2060     }
2061     CONTRACTL_END;
2062
2063     // See code:#DisableLockOnAsyncCalls
2064     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2065
2066     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2067         (LF_CORPROF, 
2068         LL_INFO1000, 
2069         "**PROF: GetFunctionFromIP 0x%p.\n", 
2070         ip));  
2071
2072     // This call is allowed asynchronously, but the JIT functions take a reader lock.  
2073     // So we need to ensure the current thread hasn't been hijacked by a profiler while
2074     // it was holding the writer lock.  Checking the ForbidSuspendThread region is a
2075     // sufficient test for this
2076     FAIL_IF_IN_FORBID_SUSPEND_REGION();
2077
2078     HRESULT hr = S_OK;
2079
2080     EECodeInfo codeInfo;
2081
2082     hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2083     if (FAILED(hr))
2084     {
2085         return hr;
2086     }
2087
2088     if (pFunctionId)
2089     {
2090         *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2091     }
2092
2093     return S_OK;
2094 }
2095
2096
2097 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP2(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
2098 {
2099     CONTRACTL
2100     {
2101         // Yay!
2102         NOTHROW;
2103
2104         // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2105         // which can switch us to preemptive mode and trigger GCs
2106         GC_TRIGGERS;
2107
2108         // Yay!
2109         MODE_ANY;
2110     
2111         // Yay!
2112         EE_THREAD_NOT_REQUIRED;
2113
2114         // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2115         CAN_TAKE_LOCK;
2116
2117     }
2118     CONTRACTL_END;
2119
2120     // See code:#DisableLockOnAsyncCalls
2121     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2122
2123     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2124         kP2EEAllowableAfterAttach | kP2EETriggers,
2125         (LF_CORPROF, 
2126         LL_INFO1000, 
2127         "**PROF: GetFunctionFromIP2 0x%p.\n", 
2128         ip));  
2129
2130     HRESULT hr = S_OK;
2131
2132     EECodeInfo codeInfo;
2133
2134     hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2135     if (FAILED(hr))
2136     {
2137         return hr;
2138     }
2139
2140     if (pFunctionId)
2141     {
2142         *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2143     }
2144
2145     if (pReJitId != NULL)
2146     {
2147         MethodDesc * pMD = codeInfo.GetMethodDesc();
2148         *pReJitId = ReJitManager::GetReJitId(pMD, codeInfo.GetStartAddress());
2149     }
2150
2151     return S_OK;
2152 }
2153
2154 //*****************************************************************************
2155 // Given a function id, retrieve the metadata token and a reader api that
2156 // can be used against the token.
2157 //*****************************************************************************
2158 HRESULT ProfToEEInterfaceImpl::GetTokenAndMetaDataFromFunction(
2159     FunctionID  functionId,
2160     REFIID      riid,
2161     IUnknown    **ppOut,
2162     mdToken     *pToken)
2163 {
2164     CONTRACTL
2165     {
2166         // Yay!
2167         NOTHROW;
2168
2169         // Yay!
2170         GC_NOTRIGGER;
2171
2172         // Yay!
2173         MODE_ANY;
2174
2175         // Yay!
2176         EE_THREAD_NOT_REQUIRED;
2177
2178         // PEFile::GetRWImporter and GetReadablePublicMetaDataInterface take locks
2179         CAN_TAKE_LOCK;
2180
2181     }
2182     CONTRACTL_END;
2183
2184     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2185         (LF_CORPROF, 
2186          LL_INFO1000, 
2187          "**PROF: GetTokenAndMetaDataFromFunction 0x%p.\n", 
2188          functionId));  
2189     
2190     if (functionId == NULL)
2191     {
2192         return E_INVALIDARG;
2193     }
2194     
2195     HRESULT     hr = S_OK;
2196
2197     MethodDesc *pMD = FunctionIdToMethodDesc(functionId);
2198
2199     // it's not safe to examine a methoddesc that has not been restored so do not do so
2200     if (!pMD->IsRestored())
2201         return CORPROF_E_DATAINCOMPLETE;
2202     
2203     if (pToken)
2204     {
2205         *pToken = pMD->GetMemberDef();
2206     }
2207
2208     // don't bother with any of this module fetching if the metadata access isn't requested
2209     if (ppOut)
2210     {
2211         Module * pMod = pMD->GetModule();
2212         hr = pMod->GetReadablePublicMetaDataInterface(ofRead, riid, (LPVOID *) ppOut);
2213     }
2214
2215     return hr;
2216 }
2217
2218 //---------------------------------------------------------------------------------------
2219 // What follows are the GetCodeInfo* APIs and their helpers.  The two helpers factor out
2220 // some of the common code to validate parameters and then determine the code info from
2221 // the start of the code.  Each individual GetCodeInfo* API differs in how it uses these
2222 // helpers, particuarly in how it determines the start of the code (GetCodeInfo3 needs
2223 // to use the rejit manager to determine the code start, whereas the others do not). 
2224 // Factoring out like this allows us to have statically determined contracts that differ
2225 // based on whether we need to use the rejit manager, which requires locking and
2226 // may trigger GCs.
2227 //---------------------------------------------------------------------------------------
2228
2229
2230 HRESULT ValidateParametersForGetCodeInfo(
2231     MethodDesc * pMethodDesc,
2232     ULONG32  cCodeInfos,
2233     COR_PRF_CODE_INFO codeInfos[])
2234 {
2235     LIMITED_METHOD_CONTRACT;
2236
2237     if (pMethodDesc == NULL)
2238     {
2239         return E_INVALIDARG;
2240     }
2241
2242     if ((cCodeInfos != 0) && (codeInfos == NULL))
2243     {
2244         return E_INVALIDARG;
2245     }
2246
2247     // it's not safe to examine a methoddesc that has not been restored so do not do so
2248     if (!pMethodDesc->IsRestored())
2249         return CORPROF_E_DATAINCOMPLETE;
2250
2251     if (pMethodDesc->HasClassOrMethodInstantiation() && pMethodDesc->IsTypicalMethodDefinition())
2252     {
2253         // In this case, we used to replace pMethodDesc with its canonical instantiation
2254         // (FindOrCreateTypicalSharedInstantiation).  However, a profiler should never be able
2255         // to get to this point anyway, since any MethodDesc a profiler gets from us
2256         // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
2257         // We assert here just in case a test proves me wrong, but generally we will
2258         // disallow this code path.
2259         _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetCodeInfo2");
2260         return E_INVALIDARG;
2261     }
2262
2263     return S_OK;
2264 }
2265
2266 HRESULT GetCodeInfoFromCodeStart(
2267     PCODE start,
2268     ULONG32  cCodeInfos,
2269     ULONG32 * pcCodeInfos,
2270     COR_PRF_CODE_INFO codeInfos[])
2271 {
2272     CONTRACTL
2273     {
2274         NOTHROW;
2275         GC_NOTRIGGER;
2276         MODE_ANY;
2277
2278         // We need to take the ExecutionManager reader lock to find the
2279         // appropriate jit manager.
2280         CAN_TAKE_LOCK;
2281
2282
2283         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2284         // host (SQL).  Corners will be cut to ensure this is the case
2285         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2286     }
2287     CONTRACTL_END;
2288
2289     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2290
2291     ///////////////////////////////////
2292     // Get the code region info for this function. This is a multi step process.
2293     //
2294     // MethodDesc ==> Code Address ==> JitMananger ==>
2295     // MethodToken ==> MethodRegionInfo
2296     // 
2297     // (Our caller handled the first step: MethodDesc ==> Code Address.)
2298     //
2299     // <WIN64-ONLY>
2300     //
2301     // On WIN64 we have a choice of where to go to find out the function address range size:
2302     // GC info (which is what we're doing below on all architectures) or the OS unwind
2303     // info, stored in the RUNTIME_FUNCTION structure.  The latter produces
2304     // a SMALLER size than the former, because the latter excludes some data from
2305     // the set we report to the OS for unwind info.  For example, switch tables can be
2306     // separated out from the regular code and not be reported as OS unwind info, and thus
2307     // those addresses will not appear in the range reported by the RUNTIME_FUNCTION gotten via:
2308     //
2309     //      IJitManager* pJitMan = ExecutionManager::FindJitMan((PBYTE)codeInfos[0].startAddress);
2310     //      PRUNTIME_FUNCTION pfe = pJitMan->GetUnwindInfo((PBYTE)codeInfos[0].startAddress);
2311     //      *pcCodeInfos = (ULONG) (pfe->EndAddress - pfe->BeginAddress);
2312     //
2313     // (Note that GCInfo & OS unwind info report the same start address--it's the size that's
2314     // different.)
2315     //
2316     // The advantage of using the GC info is that it's available on all architectures,
2317     // and it gives you a more complete picture of the addresses belonging to the function.
2318     //
2319     // A disadvantage of using GC info is we'll report those extra addresses (like switch
2320     // tables) that a profiler might turn back around and use in a call to
2321     // GetFunctionFromIP.  A profiler may expect we'd be able to map back any address
2322     // in the function's GetCodeInfo ranges back to that function's FunctionID (methoddesc).  But
2323     // querying these extra addresses will cause GetFunctionFromIP to fail, as they're not
2324     // actually valid instruction addresses that the IP register can be set to.
2325     // 
2326     // The advantage wins out, so we're going with GC info everywhere.
2327     //
2328     // </WIN64-ONLY>
2329
2330     HRESULT hr;
2331
2332     if (start == NULL)
2333     {
2334         return CORPROF_E_FUNCTION_NOT_COMPILED;
2335     }
2336
2337     EECodeInfo codeInfo;
2338     hr = GetFunctionInfoInternal(
2339         (LPCBYTE) start,
2340         &codeInfo);
2341     if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
2342     {
2343         _ASSERTE(ShouldAvoidHostCalls());
2344         return hr;
2345     }
2346     if (FAILED(hr))
2347     {
2348         return CORPROF_E_FUNCTION_NOT_COMPILED;
2349     }
2350
2351     IJitManager::MethodRegionInfo methodRegionInfo;
2352     codeInfo.GetMethodRegionInfo(&methodRegionInfo);
2353
2354     //
2355     // Fill out the codeInfo structures with valuse from the
2356     // methodRegion
2357     //
2358     // Note that we're assuming that a method will never be split into
2359     // more than two regions ... this is unlikely to change any time in
2360     // the near future.
2361     //
2362     if (NULL != codeInfos)
2363     {
2364         if (cCodeInfos > 0)
2365         {
2366             //
2367             // We have to return the two regions in the order that they would appear
2368             // if straight-line compiled
2369             //
2370             if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2371             {
2372                 codeInfos[0].startAddress =
2373                     (UINT_PTR)methodRegionInfo.hotStartAddress;
2374                 codeInfos[0].size = methodRegionInfo.hotSize;
2375             }
2376             else
2377             {
2378                 _ASSERTE(methodRegionInfo.coldStartAddress != NULL);
2379                 codeInfos[0].startAddress =
2380                     (UINT_PTR)methodRegionInfo.coldStartAddress;
2381                 codeInfos[0].size = methodRegionInfo.coldSize;
2382             }
2383
2384             if (NULL != methodRegionInfo.coldStartAddress)
2385             {
2386                 if (cCodeInfos > 1)
2387                 {
2388                     if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2389                     {
2390                         codeInfos[1].startAddress =
2391                             (UINT_PTR)methodRegionInfo.coldStartAddress;
2392                         codeInfos[1].size = methodRegionInfo.coldSize;
2393                     }
2394                     else
2395                     {
2396                         codeInfos[1].startAddress =
2397                             (UINT_PTR)methodRegionInfo.hotStartAddress;
2398                         codeInfos[1].size = methodRegionInfo.hotSize;
2399                     }
2400                 }
2401             }
2402         }
2403     }
2404
2405     if (NULL != pcCodeInfos)
2406     {
2407         *pcCodeInfos = (NULL != methodRegionInfo.coldStartAddress) ? 2 : 1;
2408     }
2409
2410
2411     return S_OK;
2412 }
2413
2414 //*****************************************************************************
2415 // Gets the location and size of a jitted function
2416 //*****************************************************************************
2417
2418 HRESULT ProfToEEInterfaceImpl::GetCodeInfo(FunctionID functionId, LPCBYTE * pStart, ULONG * pcSize)
2419 {
2420     CONTRACTL
2421     {
2422         // Yay!
2423         NOTHROW;
2424
2425         // Yay!
2426         GC_NOTRIGGER;
2427
2428         // Yay!
2429         MODE_ANY;
2430
2431         // Yay!
2432         EE_THREAD_NOT_REQUIRED;
2433
2434         // (See locking contract comment in GetCodeInfoHelper.)
2435         DISABLED(CAN_TAKE_LOCK);
2436         
2437         // (See locking contract comment in GetCodeInfoHelper.)
2438         CANNOT_RETAKE_LOCK;
2439
2440
2441         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2442         // host (SQL).  Corners will be cut to ensure this is the case
2443         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2444     }
2445     CONTRACTL_END;
2446
2447     // See code:#DisableLockOnAsyncCalls
2448     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2449
2450     // This is called asynchronously, but GetCodeInfoHelper() will
2451     // ensure we're not called at a dangerous time
2452     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2453         (LF_CORPROF, 
2454         LL_INFO1000, 
2455         "**PROF: GetCodeInfo 0x%p.\n", 
2456         functionId));
2457
2458     // GetCodeInfo may be called asynchronously, and the JIT functions take a reader
2459     // lock.  So we need to ensure the current thread hasn't been hijacked by a profiler while
2460     // it was holding the writer lock.  Checking the ForbidSuspendThread region is a sufficient test for this
2461     FAIL_IF_IN_FORBID_SUSPEND_REGION();
2462     
2463     if (functionId == 0)
2464     {
2465         return E_INVALIDARG;
2466     }
2467
2468     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2469
2470     COR_PRF_CODE_INFO codeInfos[2];
2471     ULONG32 cCodeInfos;
2472
2473     HRESULT hr = GetCodeInfoFromCodeStart(
2474         pMethodDesc->GetNativeCode(),
2475         _countof(codeInfos),
2476         &cCodeInfos, 
2477         codeInfos);
2478
2479     if ((FAILED(hr)) || (0 == cCodeInfos))
2480     {
2481         return hr;
2482     }
2483
2484     if (NULL != pStart)
2485     {
2486         *pStart = reinterpret_cast< LPCBYTE >(codeInfos[0].startAddress);
2487     }
2488
2489     if (NULL != pcSize)
2490     {
2491         if (!FitsIn<ULONG>(codeInfos[0].size))
2492         {
2493             return E_UNEXPECTED;
2494         }
2495         *pcSize = static_cast<ULONG>(codeInfos[0].size);
2496     }
2497
2498     return hr;
2499 }
2500
2501 HRESULT ProfToEEInterfaceImpl::GetCodeInfo2(FunctionID functionId,
2502                                             ULONG32  cCodeInfos,
2503                                             ULONG32 * pcCodeInfos,
2504                                             COR_PRF_CODE_INFO codeInfos[])
2505 {
2506     CONTRACTL
2507     {
2508         // Yay!
2509         NOTHROW;
2510
2511         // Yay!
2512         GC_NOTRIGGER;
2513
2514         // Yay!
2515         MODE_ANY;
2516
2517         // Yay!
2518         EE_THREAD_NOT_REQUIRED;
2519
2520         // (See locking contract comment in GetCodeInfoHelper.)
2521         DISABLED(CAN_TAKE_LOCK);
2522
2523         // (See locking contract comment in GetCodeInfoHelper.)
2524         CANNOT_RETAKE_LOCK;
2525
2526         
2527         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2528         // host (SQL).  Corners will be cut to ensure this is the case
2529         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2530
2531         PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2532         PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2533     }
2534     CONTRACTL_END;
2535
2536     // See code:#DisableLockOnAsyncCalls
2537     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2538
2539     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2540         (LF_CORPROF, 
2541         LL_INFO1000, 
2542         "**PROF: GetCodeInfo2 0x%p.\n", 
2543         functionId));         
2544
2545     HRESULT hr = S_OK; 
2546
2547     EX_TRY
2548     {
2549         MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2550
2551         hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2552         if (SUCCEEDED(hr))
2553         {
2554             hr = GetCodeInfoFromCodeStart(
2555                 pMethodDesc->GetNativeCode(),
2556                 cCodeInfos,
2557                 pcCodeInfos,
2558                 codeInfos);
2559         }
2560     }
2561     EX_CATCH_HRESULT(hr);
2562
2563     return hr;
2564 }
2565
2566
2567 HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId,
2568                                             ReJITID  reJitId,
2569                                             ULONG32  cCodeInfos,
2570                                             ULONG32* pcCodeInfos,
2571                                             COR_PRF_CODE_INFO codeInfos[])
2572
2573
2574 {
2575     CONTRACTL
2576     {
2577         // Yay!
2578         NOTHROW;
2579
2580         // We need to access the rejitmanager, which means taking locks, which means we
2581         // may trigger a GC
2582         GC_TRIGGERS;
2583
2584         // Yay!
2585         MODE_ANY;
2586
2587         // Yay!
2588         EE_THREAD_NOT_REQUIRED;
2589
2590         // We need to access the rejitmanager, which means taking locks
2591         CAN_TAKE_LOCK;
2592         
2593
2594         PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2595         PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2596     }
2597     CONTRACTL_END;
2598
2599     // See code:#DisableLockOnAsyncCalls
2600     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2601
2602     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2603         kP2EEAllowableAfterAttach | kP2EETriggers,
2604         (LF_CORPROF, 
2605         LL_INFO1000, 
2606         "**PROF: GetCodeInfo3 0x%p 0x%p.\n", 
2607         functionId, reJitId));         
2608
2609     HRESULT hr = S_OK; 
2610
2611     EX_TRY
2612     {
2613         MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2614
2615         hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2616         if (SUCCEEDED(hr))
2617         {
2618             PCODE pCodeStart = NULL;
2619             CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
2620             {
2621                 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
2622                 
2623                 ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMethodDesc, reJitId);
2624
2625                 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMethodDesc);
2626                 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
2627                 {
2628                     // Now that tiered compilation can create more than one jitted code version for the same rejit id
2629                     // we are arbitrarily choosing the first one to return.  To address a specific version of native code
2630                     // use GetCodeInfo4.
2631                     pCodeStart = iter->GetNativeCode();
2632                     break;
2633                 }
2634             }
2635             
2636             hr = GetCodeInfoFromCodeStart(pCodeStart,
2637                                           cCodeInfos,
2638                                           pcCodeInfos,
2639                                           codeInfos);
2640         }
2641     }
2642     EX_CATCH_HRESULT(hr);
2643
2644     return hr;
2645 }
2646
2647
2648 HRESULT ProfToEEInterfaceImpl::GetEventMask(DWORD * pdwEvents)
2649 {
2650     CONTRACTL
2651     {
2652         // Yay!
2653         NOTHROW;
2654
2655         // Yay!
2656         GC_NOTRIGGER;
2657
2658         // Yay!
2659         MODE_ANY;
2660
2661         // Yay!
2662         EE_THREAD_NOT_REQUIRED;
2663
2664         // Yay!
2665         CANNOT_TAKE_LOCK;
2666
2667     }
2668     CONTRACTL_END;
2669
2670
2671     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, 
2672         (LF_CORPROF, 
2673         LL_INFO10, 
2674         "**PROF: GetEventMask.\n"));
2675     
2676     if (pdwEvents == NULL)
2677     {
2678         return E_INVALIDARG;
2679     }
2680
2681     *pdwEvents = g_profControlBlock.dwEventMask;
2682     return S_OK;
2683 }
2684
2685 HRESULT ProfToEEInterfaceImpl::GetEventMask2(DWORD *pdwEventsLow, DWORD *pdwEventsHigh)
2686 {
2687     CONTRACTL
2688     {
2689         // Yay!
2690         NOTHROW;
2691
2692         // Yay!
2693         GC_NOTRIGGER;
2694
2695         // Yay!
2696         MODE_ANY;
2697
2698         // Yay!
2699         EE_THREAD_NOT_REQUIRED;
2700
2701         // Yay!
2702         CANNOT_TAKE_LOCK;
2703
2704     }
2705     CONTRACTL_END;
2706
2707
2708     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, 
2709         (LF_CORPROF, 
2710         LL_INFO10, 
2711         "**PROF: GetEventMask2.\n"));
2712     
2713     if ((pdwEventsLow == NULL) || (pdwEventsHigh == NULL))
2714     {
2715         return E_INVALIDARG;
2716     }
2717
2718     *pdwEventsLow = g_profControlBlock.dwEventMask;
2719     *pdwEventsHigh = g_profControlBlock.dwEventMaskHigh;
2720     return S_OK;
2721 }
2722
2723 // static
2724 void ProfToEEInterfaceImpl::MethodTableCallback(void* context, void* objectUNSAFE)
2725 {
2726     CONTRACTL
2727     {
2728         NOTHROW;
2729         GC_NOTRIGGER;
2730         MODE_ANY;
2731     } 
2732     CONTRACTL_END;
2733
2734     // each callback identifies the address of a method table within the frozen object segment
2735     // that pointer is an object ID by definition -- object references point to the method table
2736     CDynArray< ObjectID >* objects = reinterpret_cast< CDynArray< ObjectID >* >(context);
2737
2738     *objects->Append() = reinterpret_cast< ObjectID >(objectUNSAFE);
2739 }
2740
2741 // static
2742 void ProfToEEInterfaceImpl::ObjectRefCallback(void* context, void* objectUNSAFE)
2743 {
2744     // we don't care about embedded object references, ignore them
2745 }
2746
2747
2748 HRESULT ProfToEEInterfaceImpl::EnumModuleFrozenObjects(ModuleID moduleID,
2749                                                        ICorProfilerObjectEnum** ppEnum)
2750 {
2751     CONTRACTL
2752     {
2753         // Yay!
2754         NOTHROW;
2755
2756         // Yay!
2757         GC_NOTRIGGER;
2758
2759         // Yay!
2760         MODE_ANY;
2761
2762         // Yay!
2763         EE_THREAD_NOT_REQUIRED;
2764
2765         // Yay!
2766         CANNOT_TAKE_LOCK;
2767
2768     }
2769     CONTRACTL_END;
2770
2771     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2772         (LF_CORPROF, 
2773          LL_INFO1000, 
2774          "**PROF: EnumModuleFrozenObjects 0x%p.\n", 
2775          moduleID));             
2776     
2777     if (NULL == ppEnum)
2778     {
2779         return E_INVALIDARG;
2780     }
2781
2782     Module* pModule = reinterpret_cast< Module* >(moduleID);
2783     if (pModule == NULL || pModule->IsBeingUnloaded())
2784     {
2785         return CORPROF_E_DATAINCOMPLETE;
2786     }
2787     
2788     HRESULT hr = S_OK;
2789
2790     EX_TRY
2791     {
2792         // If we don't support frozen objects at all, then just return empty
2793         // enumerator.
2794         *ppEnum = new ProfilerObjectEnum();
2795     }
2796     EX_CATCH_HRESULT(hr);
2797
2798     return hr;
2799 }
2800
2801
2802
2803 /*
2804  * GetArrayObjectInfo
2805  *
2806  * This function returns informatin about array objects.  In particular, the dimensions
2807  * and where the data buffer is stored.
2808  *
2809  */
2810 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfo(ObjectID objectId,
2811                     ULONG32 cDimensionSizes,
2812                     ULONG32 pDimensionSizes[],
2813                     int pDimensionLowerBounds[],
2814                     BYTE    **ppData)
2815 {
2816     CONTRACTL
2817     {
2818         // Yay!
2819         NOTHROW;
2820
2821         // Yay!
2822         GC_NOTRIGGER;
2823
2824         // Yay!  Fail at runtime if in preemptive mode via AllowObjectInspection()
2825         MODE_ANY;
2826
2827         // Yay!
2828         CANNOT_TAKE_LOCK;
2829
2830     }
2831     CONTRACTL_END;
2832
2833     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2834         (LF_CORPROF, 
2835          LL_INFO1000, 
2836          "**PROF: GetArrayObjectInfo 0x%p.\n", 
2837          objectId));
2838     
2839     if (objectId == NULL)
2840     {
2841         return E_INVALIDARG;
2842     }
2843
2844     if ((pDimensionSizes == NULL) ||
2845         (pDimensionLowerBounds == NULL) ||
2846         (ppData == NULL))
2847     {
2848         return E_INVALIDARG;
2849     }
2850
2851     HRESULT hr = AllowObjectInspection();
2852     if (FAILED(hr))
2853     {
2854         return hr;
2855     }
2856
2857     Object * pObj = reinterpret_cast<Object *>(objectId);
2858
2859     // GC callbacks may come from a non-EE thread, which is considered permanently preemptive.
2860     // We are about calling some object inspection functions, which require to be in co-op mode.
2861     // Given that none managed objects can be changed by managed code until GC resumes the 
2862     // runtime, it is safe to violate the mode contract and to inspect managed objects from a 
2863     // non-EE thread when GetArrayObjectInfo is called within GC callbacks.
2864     if (NativeThreadInGC())
2865     {
2866         CONTRACT_VIOLATION(ModeViolation);
2867         return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2868     }
2869
2870     return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2871 }
2872
2873 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfoHelper(Object * pObj,
2874                     ULONG32 cDimensionSizes,
2875                     __out_ecount(cDimensionSizes) ULONG32 pDimensionSizes[],
2876                     __out_ecount(cDimensionSizes) int pDimensionLowerBounds[],
2877                     BYTE    **ppData)
2878 {
2879     CONTRACTL
2880     {
2881         // Yay!
2882         NOTHROW;
2883
2884         // Yay!
2885         GC_NOTRIGGER;
2886
2887         // Because of the object pointer parameter, we must be either in CO-OP mode, 
2888         // or on a non-EE thread in the process of doing a GC .
2889         if (!NativeThreadInGC()) { MODE_COOPERATIVE; }
2890
2891         // Yay!
2892         CANNOT_TAKE_LOCK;
2893
2894     }
2895     CONTRACTL_END;
2896
2897     // Must have an array.
2898     MethodTable * pMT = pObj->GetMethodTable();
2899     if (!pMT->IsArray())
2900     {
2901         return E_INVALIDARG;
2902     }
2903
2904     ArrayBase * pArray = static_cast<ArrayBase*> (pObj);
2905
2906     unsigned rank = pArray->GetRank();
2907
2908     if (cDimensionSizes < rank)
2909     {
2910         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2911     }
2912
2913     // Copy range for each dimension (rank)
2914     int * pBounds      = pArray->GetBoundsPtr();
2915     int * pLowerBounds = pArray->GetLowerBoundsPtr();
2916
2917     unsigned i;
2918     for(i = 0; i < rank; i++)
2919     {
2920         pDimensionSizes[i]       = pBounds[i];
2921         pDimensionLowerBounds[i] = pLowerBounds[i];
2922     }
2923
2924     // Pointer to data.
2925     *ppData = pArray->GetDataPtr();
2926
2927     return S_OK;
2928 }
2929
2930 /*
2931  * GetBoxClassLayout
2932  *
2933  * Returns information about how a particular value type is laid out.
2934  *
2935  */
2936 HRESULT ProfToEEInterfaceImpl::GetBoxClassLayout(ClassID classId,
2937                                                 ULONG32 *pBufferOffset)
2938 {
2939     CONTRACTL
2940     {
2941         // Yay!
2942         NOTHROW;
2943
2944         // Yay!
2945         GC_NOTRIGGER;
2946
2947         // Yay!
2948         MODE_ANY;
2949
2950         // Yay!
2951         EE_THREAD_NOT_REQUIRED;
2952
2953         // Yay!
2954         CANNOT_TAKE_LOCK;
2955
2956     }
2957     CONTRACTL_END;
2958
2959     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2960         (LF_CORPROF, 
2961          LL_INFO1000, 
2962          "**PROF: GetBoxClassLayout 0x%p.\n", 
2963          classId));             
2964     
2965     if (pBufferOffset == NULL)
2966     {
2967         return E_INVALIDARG;
2968     }
2969
2970     if (classId == NULL)
2971     {
2972         return E_INVALIDARG;
2973     }
2974
2975     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
2976
2977     //
2978     // This is the incorrect API for arrays.  Use GetArrayInfo and GetArrayLayout.
2979     //
2980     if (!typeHandle.IsValueType())
2981     {
2982         return E_INVALIDARG;
2983     }
2984
2985     *pBufferOffset = Object::GetOffsetOfFirstField();
2986
2987     return S_OK;
2988 }
2989
2990 /*
2991  * GetThreadAppDomain
2992  *
2993  * Returns the app domain currently associated with the given thread.
2994  *
2995  */
2996 HRESULT ProfToEEInterfaceImpl::GetThreadAppDomain(ThreadID threadId,
2997                                                   AppDomainID *pAppDomainId)
2998
2999 {
3000     CONTRACTL
3001     {
3002         // Yay!
3003         NOTHROW;
3004
3005         // Yay!
3006         GC_NOTRIGGER;
3007
3008         // Yay!
3009         MODE_ANY;
3010
3011         // Yay!
3012         EE_THREAD_NOT_REQUIRED;
3013
3014         // Yay!
3015         CANNOT_TAKE_LOCK;
3016
3017     }
3018     CONTRACTL_END;
3019
3020     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3021         (LF_CORPROF,
3022          LL_INFO1000, 
3023          "**PROF: GetThreadAppDomain 0x%p.\n", 
3024          threadId));
3025
3026     if (pAppDomainId == NULL)
3027     {
3028         return E_INVALIDARG;
3029     }
3030
3031     Thread *pThread;
3032
3033     if (threadId == NULL)
3034     {
3035         pThread = GetThreadNULLOk();
3036     }
3037     else
3038     {
3039         pThread = (Thread *)threadId;
3040     }
3041
3042     //
3043     // If pThread is null, then the thread has never run managed code and
3044     // so has no ThreadID.
3045     //
3046     if (!IsManagedThread(pThread))
3047     {
3048         return CORPROF_E_NOT_MANAGED_THREAD;
3049     }
3050
3051     *pAppDomainId = (AppDomainID)pThread->GetDomain();
3052
3053     return S_OK;
3054 }
3055
3056
3057 /*
3058  * GetRVAStaticAddress
3059  *
3060  * This function returns the absolute address of the given field in the given
3061  * class.  The field must be an RVA Static token.
3062  *
3063  * Parameters:
3064  *    classId - the containing class.
3065  *    fieldToken - the field we are querying.
3066  *    pAddress - location for storing the resulting address location.
3067  *
3068  * Returns:
3069  *    S_OK on success,
3070  *    E_INVALIDARG if not an RVA static,
3071  *    CORPROF_E_DATAINCOMPLETE if not yet initialized.
3072  *
3073  */
3074 HRESULT ProfToEEInterfaceImpl::GetRVAStaticAddress(ClassID classId,
3075                                                    mdFieldDef fieldToken,
3076                                                    void **ppAddress)
3077 {
3078     CONTRACTL
3079     {
3080         // Yay!
3081         NOTHROW;
3082
3083         // Yay!
3084         GC_NOTRIGGER;
3085
3086         // Yay!
3087         MODE_ANY;
3088
3089         // FieldDesc::GetStaticAddress takes a lock
3090         CAN_TAKE_LOCK;
3091
3092     }
3093     CONTRACTL_END;
3094
3095     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3096         (LF_CORPROF, 
3097          LL_INFO1000, 
3098          "**PROF: GetRVAStaticAddress 0x%p, 0x%08x.\n", 
3099          classId, 
3100          fieldToken));
3101     
3102     //
3103     // Check for NULL parameters
3104     //
3105     if ((classId == NULL) || (ppAddress == NULL))
3106     {
3107         return E_INVALIDARG;
3108     }
3109
3110     if (GetThread() == NULL)
3111     {
3112         return CORPROF_E_NOT_MANAGED_THREAD;
3113     }
3114
3115     if (GetAppDomain() == NULL)
3116     {
3117         return E_FAIL;
3118     }
3119
3120     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3121
3122     //
3123     // If this class is not fully restored, that is all the information we can get at this time.
3124     //
3125     if (!typeHandle.IsRestored())
3126     {
3127         return CORPROF_E_DATAINCOMPLETE;
3128     }
3129
3130     //
3131     // Get the field descriptor object
3132     //
3133     FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3134
3135     if (pFieldDesc == NULL)
3136     {
3137         return E_INVALIDARG;
3138     }
3139
3140     //
3141     // Verify this field is of the right type
3142     //
3143     if(!pFieldDesc->IsStatic() ||
3144        !pFieldDesc->IsRVA() ||
3145        pFieldDesc->IsThreadStatic())
3146     {
3147         return E_INVALIDARG;
3148     }
3149
3150     // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId 
3151     // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3152     MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3153
3154     //
3155     // Check that the data is available
3156     //
3157     if (!IsClassOfMethodTableInited(pMethodTable))
3158     {
3159         return CORPROF_E_DATAINCOMPLETE;
3160     }
3161
3162     //
3163     // Store the result and return
3164     //
3165     PTR_VOID pAddress = pFieldDesc->GetStaticAddress(NULL);
3166     if (pAddress == NULL)
3167     {
3168         return CORPROF_E_DATAINCOMPLETE;
3169     }
3170
3171     *ppAddress = pAddress;
3172
3173     return S_OK;
3174 }
3175
3176
3177 /*
3178  * GetAppDomainStaticAddress
3179  *
3180  * This function returns the absolute address of the given field in the given
3181  * class in the given app domain.  The field must be an App Domain Static token.
3182  *
3183  * Parameters:
3184  *    classId - the containing class.
3185  *    fieldToken - the field we are querying.
3186  *    appDomainId - the app domain container.
3187  *    pAddress - location for storing the resulting address location.
3188  *
3189  * Returns:
3190  *    S_OK on success,
3191  *    E_INVALIDARG if not an app domain static,
3192  *    CORPROF_E_DATAINCOMPLETE if not yet initialized.
3193  *
3194  */
3195 HRESULT ProfToEEInterfaceImpl::GetAppDomainStaticAddress(ClassID classId,
3196                                                          mdFieldDef fieldToken,
3197                                                          AppDomainID appDomainId,
3198                                                          void **ppAddress)
3199 {
3200     CONTRACTL
3201     {
3202         // Yay!
3203         NOTHROW;
3204
3205         // Yay!
3206         GC_NOTRIGGER;
3207
3208         // Yay!
3209         MODE_ANY;
3210
3211         // Yay!
3212         EE_THREAD_NOT_REQUIRED;
3213
3214         // FieldDesc::GetStaticAddress & FieldDesc::GetBase take locks
3215         CAN_TAKE_LOCK;
3216
3217     }
3218     CONTRACTL_END;
3219
3220     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3221         (LF_CORPROF, 
3222          LL_INFO1000, 
3223          "**PROF: GetAppDomainStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3224          classId, 
3225          fieldToken, 
3226          appDomainId));
3227     
3228     //
3229     // Check for NULL parameters
3230     //
3231     if ((classId == NULL) || (appDomainId == NULL) || (ppAddress == NULL))
3232     {
3233         return E_INVALIDARG;
3234     }
3235
3236     // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3237     // statics.  See if the profiler is trying to be naughty.
3238     if (!((BaseDomain*) appDomainId)->IsAppDomain())
3239     {
3240         return E_INVALIDARG;
3241     }
3242
3243     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3244
3245     //
3246     // If this class is not fully restored, that is all the information we can get at this time.
3247     //
3248     if (!typeHandle.IsRestored())
3249     {
3250         return CORPROF_E_DATAINCOMPLETE;
3251     }
3252
3253     //
3254     // Get the field descriptor object
3255     //
3256     FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3257
3258     if (pFieldDesc == NULL)
3259     {
3260         //
3261         // Give specific error code for literals.
3262         //
3263         DWORD dwFieldAttrs;
3264         if (FAILED(typeHandle.GetModule()->GetMDImport()->GetFieldDefProps(fieldToken, &dwFieldAttrs)))
3265         {
3266             return E_INVALIDARG;
3267         }
3268         
3269         if (IsFdLiteral(dwFieldAttrs))
3270         {
3271             return CORPROF_E_LITERALS_HAVE_NO_ADDRESS;
3272         }
3273
3274         return E_INVALIDARG;
3275     }
3276
3277     //
3278     // Verify this field is of the right type
3279     //
3280     if(!pFieldDesc->IsStatic() ||
3281        pFieldDesc->IsRVA() ||
3282        pFieldDesc->IsThreadStatic())
3283     {
3284         return E_INVALIDARG;
3285     }
3286
3287     // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId 
3288     // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3289     MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3290     AppDomain * pAppDomain = (AppDomain *)appDomainId;
3291
3292     //
3293     // Check that the data is available
3294     //
3295     if (!IsClassOfMethodTableInited(pMethodTable))
3296     {
3297         return CORPROF_E_DATAINCOMPLETE;
3298     }
3299
3300     //
3301     // Get the address
3302     //
3303     void *base = (void*)pFieldDesc->GetBase();
3304
3305     if (base == NULL)
3306     {
3307         return CORPROF_E_DATAINCOMPLETE;
3308     }
3309
3310     //
3311     // Store the result and return
3312     //
3313     PTR_VOID pAddress = pFieldDesc->GetStaticAddress(base);
3314     if (pAddress == NULL)
3315     {
3316         return E_INVALIDARG;
3317     }
3318
3319     *ppAddress = pAddress;
3320
3321     return S_OK;
3322 }
3323
3324 /*
3325  * GetThreadStaticAddress
3326  *
3327  * This function returns the absolute address of the given field in the given
3328  * class on the given thread.  The field must be an Thread Static token. threadId 
3329  * must be the current thread ID or NULL, which means using curernt thread ID.
3330  *
3331  * Parameters:
3332  *    classId - the containing class.
3333  *    fieldToken - the field we are querying.
3334  *    threadId - the thread container, which has to be the current managed thread or 
3335  *               NULL, which means to use the current managed thread.
3336  *    pAddress - location for storing the resulting address location.
3337  *
3338  * Returns:
3339  *    S_OK on success,
3340  *    E_INVALIDARG if not a thread static,
3341  *    CORPROF_E_DATAINCOMPLETE if not yet initialized.
3342  *
3343  */
3344 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress(ClassID classId,
3345                                                       mdFieldDef fieldToken,
3346                                                       ThreadID threadId,
3347                                                       void **ppAddress)
3348 {
3349     CONTRACTL
3350     {
3351         // Yay!
3352         NOTHROW;
3353
3354         // Yay!
3355         GC_NOTRIGGER;
3356
3357         // Yay!
3358         MODE_ANY;
3359
3360         // Yay!
3361         CANNOT_TAKE_LOCK;
3362
3363     }
3364     CONTRACTL_END;
3365
3366     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3367         (LF_CORPROF, 
3368          LL_INFO1000, 
3369          "**PROF: GetThreadStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3370          classId, 
3371          fieldToken, 
3372          threadId));
3373
3374     //
3375     // Verify the value of threadId, which must be the current thread ID or NULL, which means using curernt thread ID.
3376     //
3377     if ((threadId != NULL) && (threadId != ((ThreadID)GetThread())))
3378     {
3379         return E_INVALIDARG;
3380     }
3381
3382     threadId = reinterpret_cast<ThreadID>(GetThread());
3383     AppDomainID appDomainId = reinterpret_cast<AppDomainID>(GetAppDomain());
3384
3385     //
3386     // Check for NULL parameters
3387     //
3388     if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3389     {
3390         return E_INVALIDARG;
3391     }
3392
3393     return GetThreadStaticAddress2(classId,
3394                                    fieldToken,
3395                                    appDomainId,
3396                                    threadId,
3397                                    ppAddress);
3398 }
3399
3400 /*
3401  * GetThreadStaticAddress2
3402  *
3403  * This function returns the absolute address of the given field in the given
3404  * class on the given thread.  The field must be an Thread Static token.
3405  *
3406  * Parameters:
3407  *    classId - the containing class.
3408  *    fieldToken - the field we are querying.
3409  *    appDomainId - the AppDomain container.
3410  *    threadId - the thread container.
3411  *    pAddress - location for storing the resulting address location.
3412  *
3413  * Returns:
3414  *    S_OK on success,
3415  *    E_INVALIDARG if not a thread static,
3416  *    CORPROF_E_DATAINCOMPLETE if not yet initialized.
3417  *
3418  */
3419 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress2(ClassID classId,
3420                                                        mdFieldDef fieldToken,
3421                                                        AppDomainID appDomainId,
3422                                                        ThreadID threadId,
3423                                                        void **ppAddress)
3424 {
3425     CONTRACTL
3426     {
3427         // Yay!
3428         NOTHROW;
3429
3430         // Yay!
3431         GC_NOTRIGGER;
3432
3433         // Yay!
3434         MODE_ANY;
3435
3436         // Yay!
3437         CANNOT_TAKE_LOCK;
3438
3439     }
3440     CONTRACTL_END;
3441
3442     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3443         (LF_CORPROF, 
3444          LL_INFO1000, 
3445          "**PROF: GetThreadStaticAddress2 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3446          classId,
3447          fieldToken,
3448          appDomainId,
3449          threadId));
3450
3451
3452     if (threadId == NULL)
3453     {
3454         if (GetThread() == NULL)
3455         {
3456             return CORPROF_E_NOT_MANAGED_THREAD;
3457         }
3458
3459         threadId = reinterpret_cast<ThreadID>(GetThread());
3460     }
3461
3462     //
3463     // Check for NULL parameters
3464     //
3465     if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3466     {
3467         return E_INVALIDARG;
3468     }
3469
3470     // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3471     // statics.  See if the profiler is trying to be naughty.
3472     if (!((BaseDomain*) appDomainId)->IsAppDomain())
3473     {
3474         return E_INVALIDARG;
3475     }
3476
3477     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3478
3479     //
3480     // If this class is not fully restored, that is all the information we can get at this time.
3481     //
3482     if (!typeHandle.IsRestored())
3483     {
3484         return CORPROF_E_DATAINCOMPLETE;
3485     }
3486
3487     //
3488     // Get the field descriptor object
3489     //
3490     FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3491
3492     if (pFieldDesc == NULL)
3493     {
3494         return E_INVALIDARG;
3495     }
3496
3497     //
3498     // Verify this field is of the right type
3499     //
3500     if(!pFieldDesc->IsStatic() ||
3501        !pFieldDesc->IsThreadStatic() ||
3502        pFieldDesc->IsRVA())
3503     {
3504         return E_INVALIDARG;
3505     }
3506
3507     // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId 
3508     // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3509     MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3510
3511     //
3512     // Check that the data is available
3513     //
3514     if (!IsClassOfMethodTableInited(pMethodTable))
3515     {
3516         return CORPROF_E_DATAINCOMPLETE;
3517     }
3518
3519     //
3520     // Store the result and return
3521     //
3522     PTR_VOID pAddress = (void *)(((Thread *)threadId)->GetStaticFieldAddrNoCreate(pFieldDesc));
3523     if (pAddress == NULL)
3524     {
3525         return E_INVALIDARG;
3526     }
3527
3528     *ppAddress = pAddress;
3529
3530     return S_OK;
3531 }
3532
3533 /*
3534  * GetContextStaticAddress
3535  *
3536  * This function returns the absolute address of the given field in the given
3537  * class in the given context.  The field must be an Context Static token.
3538  *
3539  * Parameters:
3540  *    classId - the containing class.
3541  *    fieldToken - the field we are querying.
3542  *    contextId - the context container.
3543  *    pAddress - location for storing the resulting address location.
3544  *
3545  * Returns:
3546  *    E_NOTIMPL
3547  *
3548  */
3549 HRESULT ProfToEEInterfaceImpl::GetContextStaticAddress(ClassID classId,
3550                                                        mdFieldDef fieldToken,
3551                                                        ContextID contextId,
3552                                                        void **ppAddress)
3553 {
3554     CONTRACTL
3555     {
3556         // Yay!
3557         NOTHROW;
3558
3559         // Yay!
3560         GC_NOTRIGGER;
3561
3562         // Yay!
3563         MODE_ANY;
3564
3565         // Yay!
3566         CANNOT_TAKE_LOCK;
3567
3568     }
3569     CONTRACTL_END;
3570
3571     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3572         (LF_CORPROF, 
3573          LL_INFO1000, 
3574          "**PROF: GetContextStaticAddress 0x%p, 0x%08x, 0x%p.\n", 
3575          classId, 
3576          fieldToken, 
3577          contextId));
3578     
3579     return E_NOTIMPL;
3580 }
3581
3582 /*
3583  * GetAppDomainsContainingModule
3584  *
3585  * This function returns the AppDomains in which the given module has been loaded    
3586  *
3587  * Parameters:
3588  *    moduleId - the module with static variables.
3589  *    cAppDomainIds - the input size of appDomainIds array.
3590  *    pcAppDomainIds - the output size of appDomainIds array.
3591  *    appDomainIds - the array to be filled up with AppDomainIDs containing initialized 
3592  *                   static variables from the moduleId's moudle.
3593  *
3594  * Returns:
3595  *    S_OK on success,
3596  *    E_INVALIDARG for invalid parameters,
3597  *    CORPROF_E_DATAINCOMPLETE if moduleId's module is not yet initialized.
3598  *
3599  */
3600 HRESULT ProfToEEInterfaceImpl::GetAppDomainsContainingModule(ModuleID moduleId,
3601                                                              ULONG32 cAppDomainIds,
3602                                                              ULONG32 * pcAppDomainIds, 
3603                                                              AppDomainID appDomainIds[])
3604 {
3605     CONTRACTL
3606     {
3607         // Yay!
3608         NOTHROW;
3609
3610         // This method iterates over AppDomains, which adds, then releases, a reference on 
3611         // each AppDomain iterated.  This causes locking, and can cause triggering if the 
3612         // AppDomain gets destroyed as a result of the release. (See code:AppDomainIterator::Next 
3613         // and its call to code:AppDomain::Release.)
3614         GC_TRIGGERS;
3615
3616         // Yay!
3617         MODE_ANY;
3618
3619         // (See comment above GC_TRIGGERS.)
3620         CAN_TAKE_LOCK;
3621
3622     }
3623     CONTRACTL_END;
3624
3625     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
3626         kP2EEAllowableAfterAttach | kP2EETriggers,
3627         (LF_CORPROF, 
3628          LL_INFO1000, 
3629          "**PROF: GetAppDomainsContainingModule 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3630          moduleId,
3631          cAppDomainIds,
3632          pcAppDomainIds,
3633          appDomainIds));
3634
3635
3636     //
3637     // Check for NULL parameters
3638     //
3639     if ((moduleId == NULL) || ((appDomainIds == NULL) && (cAppDomainIds != 0)) || (pcAppDomainIds == NULL))
3640     {
3641         return E_INVALIDARG;
3642     }
3643    
3644     Module* pModule = reinterpret_cast< Module* >(moduleId);
3645     if (pModule->IsBeingUnloaded())
3646     {
3647         return CORPROF_E_DATAINCOMPLETE;
3648     }
3649
3650     // IterateAppDomainContainingModule uses AppDomainIterator, which cannot be called while the current thread
3651     // is holding the ThreadStore lock.
3652     if (ThreadStore::HoldingThreadStore())
3653     {
3654         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
3655     }
3656
3657     IterateAppDomainContainingModule iterateAppDomainContainingModule(pModule, cAppDomainIds, pcAppDomainIds, appDomainIds);
3658
3659     return iterateAppDomainContainingModule.PopulateArray();
3660 }
3661
3662
3663
3664 /*
3665  * GetStaticFieldInfo
3666  *
3667  * This function returns a bit mask of the type of statics the
3668  * given field is.
3669  *
3670  * Parameters:
3671  *    classId - the containing class.
3672  *    fieldToken - the field we are querying.
3673  *    pFieldInfo - location for storing the resulting bit mask.
3674  *
3675  * Returns:
3676  *    S_OK on success,
3677  *    E_INVALIDARG if pFieldInfo is NULL
3678  *
3679  */
3680 HRESULT ProfToEEInterfaceImpl::GetStaticFieldInfo(ClassID classId,
3681                                                   mdFieldDef fieldToken,
3682                                                   COR_PRF_STATIC_TYPE *pFieldInfo)
3683 {
3684     CONTRACTL
3685     {
3686         // Yay!
3687         NOTHROW;
3688
3689         // Yay!
3690         GC_NOTRIGGER;
3691
3692         // Yay!
3693         MODE_ANY;
3694
3695         // Yay!
3696         EE_THREAD_NOT_REQUIRED;
3697
3698         // Yay!
3699         CANNOT_TAKE_LOCK;
3700
3701     }
3702     CONTRACTL_END;
3703
3704     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3705         (LF_CORPROF, 
3706          LL_INFO1000, 
3707          "**PROF: GetStaticFieldInfo 0x%p, 0x%08x.\n", 
3708          classId, 
3709          fieldToken));
3710     
3711     //
3712     // Check for NULL parameters
3713     //
3714     if ((classId == NULL) || (pFieldInfo == NULL))
3715     {
3716         return E_INVALIDARG;
3717     }
3718
3719     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3720
3721     //
3722     // If this class is not fully restored, that is all the information we can get at this time.
3723     //
3724     if (!typeHandle.IsRestored())
3725     {
3726         return CORPROF_E_DATAINCOMPLETE;
3727     }
3728
3729     //
3730     // Get the field descriptor object
3731     //
3732     FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3733
3734     if (pFieldDesc == NULL)
3735     {
3736         return E_INVALIDARG;
3737     }
3738
3739     *pFieldInfo = COR_PRF_FIELD_NOT_A_STATIC;
3740
3741     if (pFieldDesc->IsRVA())
3742     {
3743         *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_RVA_STATIC);
3744     }
3745
3746     if (pFieldDesc->IsThreadStatic())
3747     {
3748         *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_THREAD_STATIC);
3749     }
3750
3751     if ((*pFieldInfo == COR_PRF_FIELD_NOT_A_STATIC) && pFieldDesc->IsStatic())
3752     {
3753         *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_APP_DOMAIN_STATIC);
3754     }
3755
3756     return S_OK;
3757 }
3758
3759
3760
3761 /*
3762  * GetClassIDInfo2
3763  *
3764  * This function generalizes GetClassIDInfo for all types, both generic and non-generic.  It returns
3765  * the module, type token, and an array of instantiation classIDs that were used to instantiate the
3766  * given classId.
3767  *
3768  * Parameters:
3769  *   classId - The classId (TypeHandle) to query information about.
3770  *   pParentClassId - The ClassID (TypeHandle) of the parent class.
3771  *   pModuleId - An optional parameter for returning the module of the class.
3772  *   pTypeDefToken - An optional parameter for returning the metadata token of the class.
3773  *   cNumTypeArgs - The count of the size of the array typeArgs
3774  *   pcNumTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
3775  *         the number that would be needed.
3776  *   typeArgs - An array to store generic type parameters for the class.
3777  *
3778  * Returns:
3779  *   S_OK if successful.
3780  */
3781 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo2(ClassID classId,
3782                                             ModuleID *pModuleId,
3783                                             mdTypeDef *pTypeDefToken,
3784                                             ClassID *pParentClassId,
3785                                             ULONG32 cNumTypeArgs,
3786                                             ULONG32 *pcNumTypeArgs,
3787                                             ClassID typeArgs[])
3788 {
3789
3790     CONTRACTL
3791     {
3792         // Yay!
3793         NOTHROW;
3794
3795         // Yay!
3796         GC_NOTRIGGER;
3797
3798         // Yay!
3799         MODE_ANY;
3800
3801         // Yay!
3802         EE_THREAD_NOT_REQUIRED;
3803
3804         // Yay!
3805         CANNOT_TAKE_LOCK;
3806
3807
3808         PRECONDITION(CheckPointer(pParentClassId, NULL_OK));
3809         PRECONDITION(CheckPointer(pModuleId, NULL_OK));
3810         PRECONDITION(CheckPointer(pTypeDefToken,  NULL_OK));
3811         PRECONDITION(CheckPointer(pcNumTypeArgs, NULL_OK));
3812         PRECONDITION(CheckPointer(typeArgs, NULL_OK));
3813     }
3814     CONTRACTL_END;
3815
3816     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3817         (LF_CORPROF, 
3818         LL_INFO1000, 
3819         "**PROF: GetClassIDInfo2 0x%p.\n", 
3820         classId));
3821     
3822     //
3823     // Verify parameters.
3824     //
3825     if (classId == NULL)
3826     {
3827         return E_INVALIDARG;
3828     }
3829
3830     if ((cNumTypeArgs != 0) && (typeArgs == NULL))
3831     {
3832         return E_INVALIDARG;
3833     }
3834
3835     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3836
3837     //
3838     // If this class is not fully restored, that is all the information we can get at this time.
3839     //
3840     if (!typeHandle.IsRestored())
3841     {
3842         return CORPROF_E_DATAINCOMPLETE;
3843     }
3844
3845     //
3846     // Handle globals which don't have the instances.
3847     //
3848     if (classId == PROFILER_GLOBAL_CLASS)
3849     {
3850         if (pParentClassId != NULL)
3851         {
3852             *pParentClassId = NULL;
3853         }
3854
3855         if (pModuleId != NULL)
3856         {
3857             *pModuleId = PROFILER_GLOBAL_MODULE;
3858         }
3859
3860         if (pTypeDefToken != NULL)
3861         {
3862             *pTypeDefToken = mdTokenNil;
3863         }
3864
3865         return S_OK;
3866     }
3867
3868     //
3869     // Do not do arrays via this API
3870     //
3871     ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(typeHandle); 
3872     if (arrayKind == ARRAY_KIND_TYPEDESC || arrayKind == ARRAY_KIND_METHODTABLE)
3873     {
3874         return CORPROF_E_CLASSID_IS_ARRAY;
3875     }
3876
3877     _ASSERTE (arrayKind == ARRAY_KIND_NOTARRAY);
3878     
3879     if (typeHandle.IsTypeDesc())
3880     {
3881         // Not an array, but still a typedesc?  We don't know how to
3882         // deal with those.
3883         return CORPROF_E_CLASSID_IS_COMPOSITE;
3884     }
3885
3886     //
3887     // Fill in the basic information
3888     //
3889     if (pParentClassId != NULL)
3890     {
3891         TypeHandle parentTypeHandle = typeHandle.GetParent();
3892         if (!parentTypeHandle.IsNull())
3893         {
3894             *pParentClassId = TypeHandleToClassID(parentTypeHandle);
3895         }
3896         else
3897         {
3898             *pParentClassId = NULL;
3899         }
3900     }
3901
3902     if (pModuleId != NULL)
3903     {
3904         *pModuleId = (ModuleID) typeHandle.GetModule();
3905         _ASSERTE(*pModuleId != NULL);
3906     }
3907
3908     if (pTypeDefToken != NULL)
3909     {
3910         *pTypeDefToken = typeHandle.GetCl();
3911         _ASSERTE(*pTypeDefToken != NULL);
3912     }
3913
3914     //
3915     // See if they are just looking to get the buffer size.
3916     //
3917     if (cNumTypeArgs == 0)
3918     {
3919         if (pcNumTypeArgs != NULL)
3920         {
3921             *pcNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3922         }
3923         return S_OK;
3924     }
3925
3926     //
3927     // Adjust the count for the size of the given array.
3928     //
3929     if (cNumTypeArgs > typeHandle.GetMethodTable()->GetNumGenericArgs())
3930     {
3931         cNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3932     }
3933
3934     if (pcNumTypeArgs != NULL)
3935     {
3936         *pcNumTypeArgs = cNumTypeArgs;
3937     }
3938
3939     //
3940     // Copy over the instantiating types.
3941     //
3942     ULONG32 count;
3943     Instantiation inst = typeHandle.GetMethodTable()->GetInstantiation();
3944
3945     for (count = 0; count < cNumTypeArgs; count ++)
3946     {
3947         typeArgs[count] = TypeHandleToClassID(inst[count]);
3948     }
3949
3950     return S_OK;
3951 }
3952
3953 HRESULT ProfToEEInterfaceImpl::GetModuleInfo(ModuleID     moduleId,
3954     LPCBYTE *    ppBaseLoadAddress,
3955     ULONG        cchName,
3956     ULONG *      pcchName,
3957     __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
3958     AssemblyID * pAssemblyId)
3959 {
3960     CONTRACTL
3961     {
3962         // Yay!
3963         NOTHROW;
3964         
3965         // Yay!
3966         GC_NOTRIGGER; 
3967
3968         // See comment in code:ProfToEEInterfaceImpl::GetModuleInfo2
3969         CAN_TAKE_LOCK;
3970
3971         // Yay!
3972         MODE_ANY;
3973
3974         // Yay!
3975         EE_THREAD_NOT_REQUIRED;
3976
3977
3978         PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
3979         PRECONDITION(CheckPointer(ppBaseLoadAddress,  NULL_OK));
3980         PRECONDITION(CheckPointer(pcchName, NULL_OK));
3981         PRECONDITION(CheckPointer(wszName, NULL_OK));
3982         PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
3983     }
3984     CONTRACTL_END;
3985
3986     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3987         (LF_CORPROF, 
3988         LL_INFO1000, 
3989         "**PROF: GetModuleInfo 0x%p.\n", 
3990         moduleId));    
3991
3992     // Paramter validation is taken care of in GetModuleInfo2.
3993
3994     return GetModuleInfo2(
3995         moduleId,
3996         ppBaseLoadAddress,
3997         cchName,
3998         pcchName,
3999         wszName,
4000         pAssemblyId,
4001         NULL);          // Don't need module type
4002 }
4003
4004 //---------------------------------------------------------------------------------------
4005 //
4006 // Helper used by GetModuleInfo2 to determine the bitmask of COR_PRF_MODULE_FLAGS for
4007 // the specified module. 
4008 //
4009 // Arguments:
4010 //      pModule - Module to get the flags for
4011 //
4012 // Return Value:
4013 //      Bitmask of COR_PRF_MODULE_FLAGS corresponding to pModule
4014 //
4015
4016 DWORD ProfToEEInterfaceImpl::GetModuleFlags(Module * pModule)
4017 {
4018     CONTRACTL
4019     {
4020         NOTHROW;
4021         GC_NOTRIGGER; 
4022         CAN_TAKE_LOCK;     // IsWindowsRuntimeModule accesses metadata directly, which takes locks
4023         MODE_ANY;
4024     }
4025     CONTRACTL_END;
4026
4027     PEFile * pPEFile = pModule->GetFile();
4028     if (pPEFile == NULL)
4029     {
4030         // Hopefully this should never happen; but just in case, don't try to determine the
4031         // flags without a PEFile.
4032         return 0;
4033     }
4034
4035     DWORD dwRet = 0;
4036
4037     // First, set the flags that are dependent on which PEImage / layout we look at
4038     // inside the Module (disk/ngen/flat)
4039     
4040     if (pModule->HasNativeImage())
4041     {
4042         // NGEN
4043         dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4044
4045         // Intentionally not checking for flat, since NGEN PEImages never have flat
4046         // layouts.
4047     }
4048     else
4049     {
4050 #ifdef FEATURE_READYTORUN 
4051         // pModule->HasNativeImage() returns false for ReadyToRun images
4052         if (pModule->IsReadyToRun())
4053         {
4054             // Ready To Run
4055             dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4056         }
4057 #endif
4058         // Not NGEN or ReadyToRun.
4059         if (pPEFile->HasOpenedILimage())
4060         {
4061             PEImage * pILImage = pPEFile->GetOpenedILimage();
4062             if (pILImage->IsFile())
4063             {
4064                 dwRet |= COR_PRF_MODULE_DISK;
4065             }           
4066             if (pPEFile->GetLoadedIL()->IsFlat())
4067             {
4068                 dwRet |= COR_PRF_MODULE_FLAT_LAYOUT;
4069             }
4070         }
4071     }
4072
4073     if (pModule->IsReflection())
4074     {
4075         dwRet |= COR_PRF_MODULE_DYNAMIC;
4076     }
4077
4078     if (pModule->IsCollectible())
4079     {
4080         dwRet |= COR_PRF_MODULE_COLLECTIBLE;
4081     }
4082
4083     if (pModule->IsResource())
4084     {
4085         dwRet |= COR_PRF_MODULE_RESOURCE;
4086     }
4087
4088     if (pModule->IsWindowsRuntimeModule())
4089     {
4090         dwRet |= COR_PRF_MODULE_WINDOWS_RUNTIME;
4091     }
4092     
4093     return dwRet;
4094 }
4095
4096 HRESULT ProfToEEInterfaceImpl::GetModuleInfo2(ModuleID     moduleId,
4097     LPCBYTE *    ppBaseLoadAddress,
4098     ULONG        cchName,
4099     ULONG *      pcchName,
4100     __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
4101     AssemblyID * pAssemblyId,
4102     DWORD *      pdwModuleFlags)
4103 {
4104     CONTRACTL
4105     {
4106         // Yay!
4107         NOTHROW;
4108         
4109         // Yay!
4110         GC_NOTRIGGER; 
4111
4112         // The pModule->GetScopeName() call below can result in locks getting taken to
4113         // access the metadata implementation.  However, these locks do not do a mode
4114         // change.
4115         CAN_TAKE_LOCK;
4116
4117         // Yay!
4118         MODE_ANY;
4119
4120         // Yay!
4121         EE_THREAD_NOT_REQUIRED;
4122
4123
4124         PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
4125         PRECONDITION(CheckPointer(ppBaseLoadAddress,  NULL_OK));
4126         PRECONDITION(CheckPointer(pcchName, NULL_OK));
4127         PRECONDITION(CheckPointer(wszName, NULL_OK));
4128         PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
4129     }
4130     CONTRACTL_END;
4131
4132     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4133         (LF_CORPROF, 
4134         LL_INFO1000, 
4135         "**PROF: GetModuleInfo2 0x%p.\n", 
4136         moduleId));    
4137
4138     if (moduleId == NULL)
4139     {
4140         return E_INVALIDARG;
4141     }
4142     
4143     Module * pModule = (Module *) moduleId;
4144     if (pModule->IsBeingUnloaded())
4145     {
4146         return CORPROF_E_DATAINCOMPLETE;
4147     }
4148     
4149     HRESULT     hr = S_OK;
4150
4151     EX_TRY
4152     {
4153         
4154         PEFile * pFile = pModule->GetFile();
4155
4156         // Pick some safe defaults to begin with.
4157         if (ppBaseLoadAddress != NULL)
4158             *ppBaseLoadAddress = 0;
4159         if (wszName != NULL)
4160             *wszName = 0;
4161         if (pcchName != NULL)
4162             *pcchName = 0;
4163         if (pAssemblyId != NULL)
4164             *pAssemblyId = PROFILER_PARENT_UNKNOWN;
4165
4166         // Module flags can be determined first without fear of error
4167         if (pdwModuleFlags != NULL)
4168             *pdwModuleFlags = GetModuleFlags(pModule);
4169
4170         // Get the module file name
4171         LPCWSTR wszFileName = pFile->GetPath();
4172         _ASSERTE(wszFileName != NULL);
4173         PREFIX_ASSUME(wszFileName != NULL);
4174
4175         // If there is no filename, which is the case for RefEmit modules and for SQL
4176         // modules, then rather than returning an empty string for the name, just use the
4177         // module name from metadata (a.k.a. Module.ScopeName). This is required to
4178         // support SQL F1 sampling profiling.
4179         StackSString strScopeName;
4180         LPCUTF8 szScopeName = NULL;
4181         if ((*wszFileName == W('\0')) && SUCCEEDED(pModule->GetScopeName(&szScopeName)))
4182         {
4183             strScopeName.SetUTF8(szScopeName);
4184             strScopeName.Normalize();
4185             wszFileName = strScopeName.GetUnicode();
4186         }
4187
4188         ULONG trueLen = (ULONG)(wcslen(wszFileName) + 1);
4189
4190         // Return name of module as required.
4191         if (wszName && cchName > 0)
4192         {
4193             if (cchName < trueLen)
4194             {
4195                 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4196             }
4197             else
4198             {
4199                 wcsncpy_s(wszName, cchName, wszFileName, trueLen);
4200             }
4201         }
4202
4203         // If they request the actual length of the name
4204         if (pcchName)
4205             *pcchName = trueLen;
4206
4207         if (ppBaseLoadAddress != NULL && !pFile->IsDynamic())
4208         {
4209             if (pModule->IsProfilerNotified())
4210             {
4211                 // Set the base load address -- this could be null in certain error conditions
4212                 *ppBaseLoadAddress = pModule->GetProfilerBase();
4213             }
4214             else
4215             {
4216                 *ppBaseLoadAddress = NULL;
4217             }
4218
4219             if (*ppBaseLoadAddress == NULL)
4220             {
4221                 hr = CORPROF_E_DATAINCOMPLETE;
4222             }
4223         }
4224
4225         // Return the parent assembly for this module if desired.
4226         if (pAssemblyId != NULL)
4227         {
4228             // Lie and say the assembly isn't avaialable until we are loaded (even though it is.)
4229             // This is for backward compatibilty - we may want to change it
4230             if (pModule->IsProfilerNotified())
4231             {
4232                 Assembly *pAssembly = pModule->GetAssembly();
4233                 _ASSERTE(pAssembly);
4234
4235                 *pAssemblyId = (AssemblyID) pAssembly;
4236             }
4237             else
4238             {
4239                 hr = CORPROF_E_DATAINCOMPLETE;
4240             }
4241         }
4242     }
4243     EX_CATCH_HRESULT(hr);
4244
4245     return (hr);
4246 }
4247
4248
4249 /*
4250  * Get a metadata interface instance which maps to the given module.
4251  * One may ask for the metadata to be opened in read+write mode, but
4252  * this will result in slower metadata execution of the program, because
4253  * changes made to the metadata cannot be optimized as they were from
4254  * the compiler.
4255  */
4256 HRESULT ProfToEEInterfaceImpl::GetModuleMetaData(ModuleID    moduleId,
4257     DWORD       dwOpenFlags,
4258     REFIID      riid,
4259     IUnknown    **ppOut)
4260 {
4261     CONTRACTL
4262     {
4263         // Yay!
4264         NOTHROW;
4265
4266         // Yay!
4267         GC_NOTRIGGER;
4268
4269         // Yay!
4270         MODE_ANY;
4271
4272         // Currently, this function is technically EE_THREAD_REQUIRED because
4273         // some functions in synch.cpp assert that there is a Thread object,
4274         // but we might be able to lift that restriction and make this be
4275         // EE_THREAD_NOT_REQUIRED.
4276
4277         // PEFile::GetRWImporter & PEFile::GetEmitter &
4278         // GetReadablePublicMetaDataInterface take locks
4279         CAN_TAKE_LOCK;
4280
4281     }
4282     CONTRACTL_END;
4283
4284     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
4285         (LF_CORPROF, 
4286         LL_INFO1000, 
4287         "**PROF: GetModuleMetaData 0x%p, 0x%08x.\n", 
4288         moduleId, 
4289         dwOpenFlags));
4290
4291     if (moduleId == NULL)
4292     {
4293         return E_INVALIDARG;
4294     }
4295
4296     // Check for unsupported bits, and return E_INVALIDARG if present
4297     if ((dwOpenFlags & ~(ofNoTransform | ofRead | ofWrite)) != 0)
4298     {
4299         return E_INVALIDARG;
4300     }
4301
4302     Module * pModule;
4303     HRESULT hr = S_OK;
4304
4305     pModule = (Module *) moduleId;
4306     _ASSERTE(pModule != NULL);
4307     if (pModule->IsBeingUnloaded())
4308     {
4309         return CORPROF_E_DATAINCOMPLETE;
4310     }
4311
4312     // Make sure we can get the importer first
4313     if (pModule->IsResource())
4314     {
4315         if (ppOut)
4316             *ppOut = NULL;
4317         return S_FALSE;
4318     }
4319
4320     // Decide which type of open mode we are in to see which you require.
4321     if ((dwOpenFlags & ofWrite) == 0)
4322     {
4323         // Readable interface
4324         return pModule->GetReadablePublicMetaDataInterface(dwOpenFlags, riid, (LPVOID *) ppOut);
4325     }
4326
4327     // Writeable interface
4328     IUnknown *pObj = NULL;
4329     EX_TRY
4330     {
4331         pObj = pModule->GetValidatedEmitter();
4332     }
4333     EX_CATCH_HRESULT_NO_ERRORINFO(hr);
4334
4335     // Ask for the interface the caller wanted, only if they provide a out param
4336     if (SUCCEEDED(hr) && ppOut)
4337         hr = pObj->QueryInterface(riid, (void **) ppOut);
4338
4339     return (hr);
4340 }
4341
4342
4343 /*
4344  * Retrieve a pointer to the body of a method starting at it's header.
4345  * A method is scoped by the module it lives in.  Because this function
4346  * is designed to give a tool access to IL before it has been loaded
4347  * by the Runtime, it uses the metadata token of the method to find
4348  * the instance desired.  Note that this function has no effect on
4349  * already compiled code.
4350  */
4351 HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID    moduleId,
4352     mdMethodDef methodId,
4353     LPCBYTE     *ppMethodHeader,
4354     ULONG       *pcbMethodSize)
4355 {
4356     CONTRACTL
4357     {
4358         // Yay!
4359         NOTHROW;
4360
4361         // Yay!
4362         GC_NOTRIGGER;
4363
4364         // Yay!
4365         MODE_ANY;
4366
4367         // PEFile::CheckLoaded & Module::GetDynamicIL both take a lock
4368         CAN_TAKE_LOCK;
4369
4370     }
4371     CONTRACTL_END;
4372
4373     
4374     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4375         kP2EEAllowableAfterAttach,
4376         (LF_CORPROF, 
4377          LL_INFO1000, 
4378          "**PROF: GetILFunctionBody 0x%p, 0x%08x.\n",
4379          moduleId, 
4380          methodId));    
4381
4382     Module *    pModule;                // Working pointer for real class.
4383     ULONG       RVA;                    // Return RVA of the method body.
4384     DWORD       dwImplFlags;            // Flags for the item.
4385     
4386     if ((moduleId == NULL) ||
4387         (methodId == mdMethodDefNil) ||
4388         (methodId == 0) ||
4389         (TypeFromToken(methodId) != mdtMethodDef))
4390     {
4391         return E_INVALIDARG;
4392     }
4393     
4394     pModule = (Module *) moduleId;
4395     _ASSERTE(pModule != NULL && methodId != mdMethodDefNil);
4396     if (pModule->IsBeingUnloaded())
4397     {
4398         return CORPROF_E_DATAINCOMPLETE;
4399     }
4400
4401     // Find the method body based on metadata.
4402     IMDInternalImport *pImport = pModule->GetMDImport();
4403     _ASSERTE(pImport);
4404
4405     PEFile *pFile = pModule->GetFile();
4406
4407     if (!pFile->CheckLoaded())
4408         return (CORPROF_E_DATAINCOMPLETE);
4409
4410     LPCBYTE pbMethod = NULL;
4411
4412     // Don't return rewritten IL, use the new API to get that.
4413     pbMethod = (LPCBYTE) pModule->GetDynamicIL(methodId, FALSE);
4414
4415     // Method not overriden - get the original copy of the IL by going to metadata
4416     if (pbMethod == NULL)
4417     {
4418         HRESULT hr = S_OK;
4419         IfFailRet(pImport->GetMethodImplProps(methodId, &RVA, &dwImplFlags));
4420         
4421         // Check to see if the method has associated IL
4422         if ((RVA == 0 && !pFile->IsDynamic()) || !(IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags) || IsMiInternalCall(dwImplFlags)))
4423         {
4424             return (CORPROF_E_FUNCTION_NOT_IL);
4425         }
4426         
4427         EX_TRY
4428         {
4429             // Get the location of the IL
4430             pbMethod = (LPCBYTE) (pModule->GetIL(RVA));
4431         }
4432         EX_CATCH_HRESULT(hr);
4433         
4434         if (FAILED(hr))
4435         {
4436             return hr;
4437         }
4438     }
4439     
4440     // Fill out param if provided
4441     if (ppMethodHeader)
4442         *ppMethodHeader = pbMethod;
4443
4444     // Calculate the size of the method itself.
4445     if (pcbMethodSize)
4446     {
4447         if (!FitsIn<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod)))
4448         {
4449             return E_UNEXPECTED;
4450         }
4451         *pcbMethodSize = static_cast<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod));
4452     }
4453     return (S_OK);
4454 }
4455
4456 //---------------------------------------------------------------------------------------
4457 // Retrieves an IMethodMalloc pointer around a ModuleILHeap instance that will own
4458 // allocating heap space for this module (for IL rewriting).
4459 //
4460 // Arguments:
4461 //      moduleId - ModuleID this allocator shall allocate for
4462 //      ppMalloc - [out] IMethodMalloc pointer the profiler will use for allocation requests
4463 //                       against this module
4464 //
4465 // Return value
4466 //      HRESULT indicating success / failure
4467 //
4468 // Notes
4469 //        IL method bodies used to have the requirement that they must be referenced as
4470 //        RVA's to the loaded module, which means they come after the module within
4471 //        METHOD_MAX_RVA.  In order to make it easier for a tool to swap out the body of
4472 //        a method, this allocator will ensure memory allocated after that point.
4473 //
4474 //        Now that requirement is completely gone, so there's nothing terribly special
4475 //        about this allocator, we just keep it around for legacy purposes.
4476
4477 HRESULT ProfToEEInterfaceImpl::GetILFunctionBodyAllocator(ModuleID         moduleId,
4478                                                           IMethodMalloc ** ppMalloc)
4479 {
4480     CONTRACTL
4481     {
4482         // Yay!
4483         NOTHROW;
4484
4485         // ModuleILHeap::FindOrCreateHeap may take a Crst if it
4486         // needs to create a new allocator and add it to the list.  Taking a crst
4487         // switches to preemptive, which is effectively a GC trigger
4488         GC_TRIGGERS;
4489
4490         // Yay!
4491         MODE_ANY;
4492
4493         // Yay!
4494         EE_THREAD_NOT_REQUIRED;
4495
4496         // (see GC_TRIGGERS comment)
4497         CAN_TAKE_LOCK;
4498
4499     }
4500     CONTRACTL_END;
4501     
4502     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4503         kP2EEAllowableAfterAttach | kP2EETriggers,
4504         (LF_CORPROF, 
4505         LL_INFO1000, 
4506         "**PROF: GetILFunctionBodyAllocator 0x%p.\n", 
4507         moduleId));
4508     
4509     if ((moduleId == NULL) || (ppMalloc == NULL))
4510     {
4511         return E_INVALIDARG;
4512     }
4513
4514     Module * pModule = (Module *) moduleId;
4515
4516     if (pModule->IsBeingUnloaded() ||
4517         !pModule->GetFile()->CheckLoaded())
4518     {
4519         return (CORPROF_E_DATAINCOMPLETE);
4520     }
4521
4522     *ppMalloc = &ModuleILHeap::s_Heap;
4523     return S_OK;
4524 }
4525
4526 /*
4527  * Replaces the method body for a function in a module.  This will replace
4528  * the RVA of the method in the metadata to point to this new method body,
4529  * and adjust any internal data structures as required.  This function can
4530  * only be called on those methods which have never been compiled by a JITTER.
4531  * Please use the GetILFunctionBodyAllocator to allocate space for the new method to
4532  * ensure the buffer is compatible.
4533  */
4534 HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID    moduleId,
4535     mdMethodDef methodId,
4536     LPCBYTE     pbNewILMethodHeader)
4537 {
4538     CONTRACTL
4539     {
4540         // PEFile::GetEmitter, Module::SetDynamicIL all throw
4541         THROWS;
4542         
4543         // Locks are taken (see CAN_TAKE_LOCK below), which may cause mode switch to
4544         // preemptive, which is triggers.
4545         GC_TRIGGERS;
4546
4547         // Yay!
4548         MODE_ANY;
4549
4550         // Module::SetDynamicIL & PEFile::CheckLoaded & PEFile::GetEmitter take locks
4551         CAN_TAKE_LOCK;
4552
4553     }
4554     CONTRACTL_END;
4555
4556     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4557         kP2EEAllowableAfterAttach | kP2EETriggers,
4558         (LF_CORPROF, 
4559          LL_INFO1000, 
4560          "**PROF: SetILFunctionBody 0x%p, 0x%08x.\n",
4561          moduleId, 
4562          methodId));        
4563     
4564     if ((moduleId == NULL) ||
4565         (methodId == mdMethodDefNil) ||
4566         (TypeFromToken(methodId) != mdtMethodDef) ||
4567         (pbNewILMethodHeader == NULL))
4568     {
4569         return E_INVALIDARG;
4570     }
4571     
4572     Module      *pModule;               // Working pointer for real class.
4573     HRESULT     hr = S_OK;
4574
4575     // Cannot set the body for anything other than a method def
4576     if (TypeFromToken(methodId) != mdtMethodDef)
4577         return (E_INVALIDARG);
4578
4579     // Cast module to appropriate type
4580     pModule = (Module *) moduleId;
4581     _ASSERTE (pModule != NULL); // Enforced in CorProfInfo::SetILFunctionBody
4582     if (pModule->IsBeingUnloaded())
4583     {
4584         return CORPROF_E_DATAINCOMPLETE;
4585     }
4586
4587     // Remember the profiler is doing this, as that means we must never detach it!
4588     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
4589
4590     // This action is not temporary!
4591     // If the profiler want to be able to revert, they need to use
4592     // the new ReJIT APIs.
4593     pModule->SetDynamicIL(methodId, (TADDR)pbNewILMethodHeader, FALSE);
4594
4595     return (hr);
4596 }
4597
4598 /*
4599  * Sets the codemap for the replaced IL function body
4600  */
4601 HRESULT ProfToEEInterfaceImpl::SetILInstrumentedCodeMap(FunctionID functionId,
4602         BOOL fStartJit,
4603         ULONG cILMapEntries,
4604         COR_IL_MAP rgILMapEntries[])
4605 {
4606     CONTRACTL
4607     {
4608         // Debugger::SetILInstrumentedCodeMap throws
4609         THROWS;
4610
4611         // Debugger::SetILInstrumentedCodeMap triggers
4612         GC_TRIGGERS;
4613
4614         // Yay!
4615         MODE_ANY;
4616
4617         // Yay!
4618         EE_THREAD_NOT_REQUIRED;
4619
4620         // Debugger::SetILInstrumentedCodeMap takes a lock when it calls Debugger::GetOrCreateMethodInfo
4621         CAN_TAKE_LOCK;
4622
4623     }
4624     CONTRACTL_END;
4625
4626     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4627         kP2EEAllowableAfterAttach | kP2EETriggers,
4628         (LF_CORPROF, 
4629          LL_INFO1000, 
4630          "**PROF: SetILInstrumentedCodeMap 0x%p, %d.\n",
4631          functionId, 
4632          fStartJit));        
4633        
4634     if (functionId == NULL)
4635     {
4636         return E_INVALIDARG;
4637     }
4638
4639     if (cILMapEntries >= (MAXULONG / sizeof(COR_IL_MAP)))
4640     {
4641         // Too big!  The allocation below would overflow when calculating the size.
4642         return E_INVALIDARG;
4643     }
4644     
4645     
4646 #ifdef DEBUGGING_SUPPORTED
4647
4648     MethodDesc *pMethodDesc = FunctionIdToMethodDesc(functionId);
4649
4650     // it's not safe to examine a methoddesc that has not been restored so do not do so
4651     if (!pMethodDesc ->IsRestored())
4652         return CORPROF_E_DATAINCOMPLETE;
4653
4654     if (g_pDebugInterface == NULL)
4655     {
4656         return CORPROF_E_DEBUGGING_DISABLED;
4657     }
4658
4659     COR_IL_MAP * rgNewILMapEntries = new (nothrow) COR_IL_MAP[cILMapEntries];
4660
4661     if (rgNewILMapEntries == NULL)
4662         return E_OUTOFMEMORY;
4663
4664     memcpy_s(rgNewILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries, rgILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries);
4665
4666     return g_pDebugInterface->SetILInstrumentedCodeMap(pMethodDesc,
4667                                                        fStartJit,
4668                                                        cILMapEntries,
4669                                                        rgNewILMapEntries);
4670
4671 #else //DEBUGGING_SUPPORTED
4672     return E_NOTIMPL;
4673 #endif //DEBUGGING_SUPPORTED
4674 }
4675
4676 HRESULT ProfToEEInterfaceImpl::ForceGC()
4677 {
4678     CONTRACTL
4679     {
4680         // GC calls "new" which throws
4681         THROWS;
4682
4683         // Uh duh, look at the name of the function, dude
4684         GC_TRIGGERS;
4685
4686         // Yay!
4687         MODE_ANY;
4688
4689         // Yay!
4690         EE_THREAD_NOT_REQUIRED;
4691
4692         // Initiating a GC causes a runtime suspension which requires the
4693         // mother of all locks: the thread store lock.
4694         CAN_TAKE_LOCK;
4695
4696     }
4697     CONTRACTL_END;
4698
4699     ASSERT_NO_EE_LOCKS_HELD();
4700
4701     // We need to use IsGarbageCollectorFullyInitialized() instead of IsGCHeapInitialized() because
4702     // there are other GC initialization being done after IsGCHeapInitialized() becomes TRUE, 
4703     // and before IsGarbageCollectorFullyInitialized() becomes TRUE.
4704     if (!IsGarbageCollectorFullyInitialized())
4705     {
4706         return CORPROF_E_NOT_YET_AVAILABLE;
4707     }
4708
4709     // Disallow the cases where a profiler calls this off a hijacked CLR thread 
4710     // or inside a profiler callback.  (Allow cases where this is a native thread, or a
4711     // thread which previously successfully called ForceGC.)
4712     Thread * pThread = GetThreadNULLOk();
4713     if ((pThread != NULL) &&
4714             (!AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED)) &&
4715             (pThread->GetFrame() != FRAME_TOP
4716             || AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_INCALLBACK)))
4717     {
4718         LOG((LF_CORPROF,
4719              LL_ERROR,
4720              "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE "
4721              "due to illegal hijacked profiler call or call from inside another callback\n"));
4722         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
4723     }
4724
4725     // NOTE: We cannot use the standard macro PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX
4726     // here because the macro ensures that either the current thread is not an 
4727     // EE thread, or, if it is, that the CALLBACK flag is set. In classic apps
4728     // a profiler-owned native thread will not get an EE thread associated with 
4729     // it, however, in AppX apps, during the first call into the GC on a
4730     // profiler-owned thread, the EE will associate an EE-thread with the profiler
4731     // thread. As a consequence the second call to ForceGC on the same thread
4732     // would fail, since this is now an EE thread and this API is not called from
4733     // a callback.
4734
4735     // First part of the PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX macro:
4736     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4737         kP2EEAllowableAfterAttach | kP2EETriggers,
4738         (LF_CORPROF, 
4739         LL_INFO1000, 
4740         "**PROF: ForceGC.\n"));        
4741
4742 #ifdef FEATURE_EVENT_TRACE
4743     // This helper, used by ETW and profAPI ensures a managed thread gets created for
4744     // this thread before forcing the GC (to work around Jupiter issues where it's
4745     // expected this thread is already managed before starting the GC).
4746     HRESULT hr = ETW::GCLog::ForceGCForDiagnostics();
4747 #else // !FEATURE_EVENT_TRACE
4748     HRESULT hr = E_FAIL;
4749 #endif // FEATURE_EVENT_TRACE
4750  
4751     // If a Thread object was just created for this thread, remember the fact that it
4752     // was a ForceGC() thread, so we can be more lenient when doing
4753     // COR_PRF_CALLBACKSTATE_INCALLBACK later on from other APIs
4754     pThread = GetThreadNULLOk();
4755     if (pThread != NULL)
4756     {
4757         pThread->SetProfilerCallbackStateFlags(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED);
4758     }
4759
4760     return hr;
4761 }
4762
4763
4764 /*
4765  * Returns the ContextID for the current thread.
4766  */
4767 HRESULT ProfToEEInterfaceImpl::GetThreadContext(ThreadID threadId,
4768                                                 ContextID *pContextId)
4769 {
4770     CONTRACTL
4771     {
4772         // Yay!
4773         NOTHROW;
4774
4775         // Yay!
4776         GC_NOTRIGGER;
4777
4778         // Yay!
4779         MODE_ANY;
4780
4781         // Yay!
4782         EE_THREAD_NOT_REQUIRED;
4783
4784         // Yay!
4785         CANNOT_TAKE_LOCK;
4786
4787     }
4788     CONTRACTL_END;
4789
4790     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4791         (LF_CORPROF, 
4792          LL_INFO1000, 
4793          "**PROF: GetThreadContext 0x%p.\n", 
4794          threadId));
4795     
4796     if (!IsManagedThread(threadId))
4797     {
4798         return E_INVALIDARG;
4799     }
4800
4801     // Cast to right type
4802     Thread *pThread = reinterpret_cast<Thread *>(threadId);
4803
4804     // Get the context for the Thread* provided
4805     AppDomain *pContext = pThread->GetDomain(); // Context is same as AppDomain in CoreCLR
4806     _ASSERTE(pContext);
4807
4808     // If there's no current context, return incomplete info
4809     if (!pContext)
4810         return (CORPROF_E_DATAINCOMPLETE);
4811
4812     // Set the result and return
4813     if (pContextId)
4814         *pContextId = reinterpret_cast<ContextID>(pContext);
4815
4816     return (S_OK);
4817 }
4818
4819 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo(ClassID classId,
4820     ModuleID *pModuleId,
4821     mdTypeDef *pTypeDefToken)
4822 {
4823     CONTRACTL
4824     {
4825         // Yay!
4826         NOTHROW;
4827
4828         // Yay!
4829         GC_NOTRIGGER;
4830
4831         // Yay!
4832         MODE_ANY;
4833
4834         // Yay!
4835         EE_THREAD_NOT_REQUIRED;
4836
4837         // Yay!
4838         CANNOT_TAKE_LOCK;
4839
4840     }
4841     CONTRACTL_END;
4842     
4843     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4844         (LF_CORPROF, 
4845         LL_INFO1000, 
4846         "**PROF: GetClassIDInfo 0x%p.\n",
4847         classId));
4848
4849     if (classId == NULL)
4850     {
4851         return E_INVALIDARG;
4852     }
4853     
4854     if (pModuleId != NULL)
4855     {
4856         *pModuleId = NULL;
4857     }
4858
4859     if (pTypeDefToken != NULL)
4860     {
4861         *pTypeDefToken = NULL;
4862     }
4863
4864     // Handle globals which don't have the instances.
4865     if (classId == PROFILER_GLOBAL_CLASS)
4866     {
4867         if (pModuleId != NULL)
4868         {
4869             *pModuleId = PROFILER_GLOBAL_MODULE;
4870         }
4871
4872         if (pTypeDefToken != NULL)
4873         {
4874             *pTypeDefToken = mdTokenNil;
4875     }
4876     }
4877     else if (classId == NULL)
4878     {
4879         return E_INVALIDARG;
4880     }
4881     // Get specific data.
4882     else
4883     {
4884         TypeHandle th = TypeHandle::FromPtr((void *)classId);
4885
4886         if (!th.IsTypeDesc())
4887         {
4888             if (!th.IsArray())
4889             {
4890                 //
4891                 // If this class is not fully restored, that is all the information we can get at this time.
4892                 //
4893                 if (!th.IsRestored())
4894                 {
4895                     return CORPROF_E_DATAINCOMPLETE;
4896                 }
4897
4898                 if (pModuleId != NULL)
4899                 {
4900                     *pModuleId = (ModuleID) th.GetModule();
4901                     _ASSERTE(*pModuleId != NULL);
4902                 }
4903
4904                 if (pTypeDefToken != NULL)
4905                 {
4906                     *pTypeDefToken = th.GetCl();
4907                     _ASSERTE(*pTypeDefToken != NULL);
4908                 }
4909             }
4910         }
4911     }
4912
4913     return (S_OK);
4914 }
4915
4916
4917 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo(FunctionID functionId,
4918     ClassID *pClassId,
4919     ModuleID *pModuleId,
4920     mdToken *pToken)
4921 {
4922     CONTRACTL
4923     {
4924         // Yay!
4925         NOTHROW;
4926
4927         // Yay!
4928         GC_NOTRIGGER;
4929
4930         // Yay!
4931         MODE_ANY;
4932
4933         // Yay!
4934         EE_THREAD_NOT_REQUIRED;
4935
4936         // Yay!
4937         CANNOT_TAKE_LOCK;
4938
4939     }
4940     CONTRACTL_END;
4941
4942     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4943         (LF_CORPROF, 
4944         LL_INFO1000, 
4945         "**PROF: GetFunctionInfo 0x%p.\n",
4946         functionId));
4947     
4948     if (functionId == NULL)
4949     {
4950         return E_INVALIDARG;
4951     }
4952
4953     MethodDesc *pMDesc = (MethodDesc *) functionId;
4954     if (!pMDesc->IsRestored())
4955     {
4956         return CORPROF_E_DATAINCOMPLETE;
4957     }
4958
4959     MethodTable *pMT = pMDesc->GetMethodTable();
4960     if (!pMT->IsRestored())
4961     {
4962         return CORPROF_E_DATAINCOMPLETE;
4963     }
4964
4965     ClassID classId = PROFILER_GLOBAL_CLASS;
4966
4967     if (pMT != NULL)
4968     {
4969         classId = NonGenericTypeHandleToClassID(TypeHandle(pMT));
4970     }
4971
4972     if (pClassId != NULL)
4973     {
4974         *pClassId = classId;
4975     }
4976
4977     if (pModuleId != NULL)
4978     {
4979         *pModuleId = (ModuleID) pMDesc->GetModule();
4980     }
4981
4982     if (pToken != NULL)
4983     {
4984         *pToken = pMDesc->GetMemberDef();
4985     }
4986
4987     return (S_OK);
4988 }
4989
4990 /*
4991  * GetILToNativeMapping returns a map from IL offsets to native
4992  * offsets for this code. An array of COR_DEBUG_IL_TO_NATIVE_MAP
4993  * structs will be returned, and some of the ilOffsets in this array
4994  * may be the values specified in CorDebugIlToNativeMappingTypes.
4995  */
4996 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping(FunctionID functionId,
4997                                                     ULONG32 cMap,
4998                                                     ULONG32 * pcMap,    // [out]
4999                                                     COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
5000 {
5001     CONTRACTL
5002     {
5003         // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
5004         THROWS;
5005
5006         // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
5007         // called from here.  Since the profiler has a valid functionId, the methoddesc for
5008         // this code will already have been created.  We should be able to enforce this by
5009         // passing allowCreate=FALSE  to FindOrCreateTypicalSharedInstantiation.
5010         DISABLED(GC_NOTRIGGER);
5011     
5012         // Yay!
5013         MODE_ANY;
5014     
5015         // The call to g_pDebugInterface->GetILToNativeMapping() below may call
5016         // Debugger::AcquireDebuggerLock
5017         CAN_TAKE_LOCK;
5018
5019     }
5020     CONTRACTL_END;
5021
5022     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5023         (LF_CORPROF, 
5024         LL_INFO1000, 
5025         "**PROF: GetILToNativeMapping 0x%p.\n",
5026         functionId));
5027
5028     return GetILToNativeMapping2(functionId, 0, cMap, pcMap, map);
5029 }
5030
5031 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId,
5032                                                     ReJITID reJitId,
5033                                                     ULONG32 cMap,
5034                                                     ULONG32 * pcMap,    // [out]
5035                                                     COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
5036 {
5037     CONTRACTL
5038     {
5039         // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
5040         THROWS;
5041
5042         // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
5043         // called from here.  Since the profiler has a valid functionId, the methoddesc for
5044         // this code will already have been created.  We should be able to enforce this by
5045         // passing allowCreate=FALSE  to FindOrCreateTypicalSharedInstantiation.
5046         DISABLED(GC_NOTRIGGER);
5047
5048         // Yay!
5049         MODE_ANY;
5050     
5051         // The call to g_pDebugInterface->GetILToNativeMapping() below may call
5052         // Debugger::AcquireDebuggerLock
5053         CAN_TAKE_LOCK;
5054
5055     }
5056     CONTRACTL_END;
5057
5058     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5059         (LF_CORPROF, 
5060         LL_INFO1000, 
5061         "**PROF: GetILToNativeMapping2 0x%p 0x%p.\n",
5062         functionId, reJitId));
5063
5064     if (functionId == NULL)
5065     {
5066         return E_INVALIDARG;
5067     }
5068
5069     if ((cMap > 0) && 
5070         ((pcMap == NULL) || (map == NULL)))
5071     {
5072         return E_INVALIDARG;
5073     }
5074
5075     HRESULT hr = S_OK;
5076
5077     EX_TRY
5078     {
5079         // Cast to proper type
5080         MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
5081
5082         if (pMD->HasClassOrMethodInstantiation() && pMD->IsTypicalMethodDefinition())
5083         {
5084             // In this case, we used to replace pMD with its canonical instantiation
5085             // (FindOrCreateTypicalSharedInstantiation).  However, a profiler should never be able
5086             // to get to this point anyway, since any MethodDesc a profiler gets from us
5087             // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
5088             // We assert here just in case a test proves me wrong, but generally we will
5089             // disallow this code path.
5090             _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetILToNativeMapping2");
5091             hr = E_INVALIDARG;
5092         }
5093         else
5094         {
5095             PCODE pCodeStart = NULL;
5096             CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
5097             ILCodeVersion ilCodeVersion = NULL;
5098             {
5099                 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
5100
5101                 pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
5102         
5103                 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
5104                 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
5105                 {
5106                     // Now that tiered compilation can create more than one jitted code version for the same rejit id
5107                     // we are arbitrarily choosing the first one to return.  To address a specific version of native code
5108                     // use GetILToNativeMapping3.
5109                     pCodeStart = iter->GetNativeCode();
5110                     break;
5111                 }
5112             }
5113
5114             hr = GetILToNativeMapping3(pCodeStart, cMap, pcMap, map);
5115         }
5116     }
5117     EX_CATCH_HRESULT(hr);
5118
5119     return hr;
5120 }
5121
5122
5123
5124 //*****************************************************************************
5125 // Given an ObjectID, go get the EE ClassID for it.
5126 //*****************************************************************************
5127 HRESULT ProfToEEInterfaceImpl::GetClassFromObject(ObjectID objectId,
5128                                                   ClassID * pClassId)
5129 {
5130     CONTRACTL
5131     {
5132         // Yay!
5133         NOTHROW;
5134
5135         // Yay!
5136         GC_NOTRIGGER;
5137
5138         // Yay!  Fail at runtime if in preemptive mode via AllowObjectInspection()
5139         MODE_ANY;
5140
5141         // Object::GetTypeHandle takes a lock
5142         CAN_TAKE_LOCK;
5143
5144     }
5145     CONTRACTL_END;
5146
5147     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5148         (LF_CORPROF, 
5149          LL_INFO1000, 
5150          "**PROF: GetClassFromObject 0x%p.\n",
5151          objectId));    
5152     
5153     if (objectId == NULL)
5154     {
5155         return E_INVALIDARG;
5156     }
5157     
5158     HRESULT hr = AllowObjectInspection();
5159     if (FAILED(hr))
5160     {
5161         return hr;
5162     }
5163
5164     // Cast the ObjectID as a Object
5165     Object *pObj = reinterpret_cast<Object *>(objectId);
5166
5167     // Set the out param and indicate success
5168     // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
5169     if (pClassId)
5170     {
5171         *pClassId = SafeGetClassIDFromObject(pObj);
5172     }
5173
5174     return S_OK;
5175 }
5176
5177 //*****************************************************************************
5178 // Given a module and a token for a class, go get the EE data structure for it.
5179 //*****************************************************************************
5180 HRESULT ProfToEEInterfaceImpl::GetClassFromToken(ModuleID    moduleId,
5181     mdTypeDef   typeDef,
5182     ClassID     *pClassId)
5183 {
5184     CONTRACTL
5185     {
5186         // Yay!
5187         NOTHROW;
5188
5189         // ClassLoader::LoadTypeDefOrRefThrowing triggers
5190         GC_TRIGGERS;
5191
5192         // Yay!
5193         MODE_ANY;
5194
5195         // ClassLoader::LoadTypeDefOrRefThrowing takes a lock
5196         CAN_TAKE_LOCK;
5197
5198     }
5199     CONTRACTL_END;
5200
5201     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5202         kP2EEAllowableAfterAttach | kP2EETriggers,
5203         (LF_CORPROF, 
5204          LL_INFO1000, 
5205          "**PROF: GetClassFromToken 0x%p, 0x%08x.\n",
5206          moduleId, 
5207          typeDef));    
5208         
5209     if ((moduleId == NULL) || (typeDef == mdTypeDefNil) || (typeDef == NULL))
5210     {
5211         return E_INVALIDARG;
5212     }
5213     
5214     if (!g_profControlBlock.fBaseSystemClassesLoaded)
5215     {
5216         return CORPROF_E_RUNTIME_UNINITIALIZED;
5217     }
5218
5219     // Get the module
5220     Module *pModule = (Module *) moduleId;
5221
5222     // No module, or it's disassociated from metadata
5223     if ((pModule == NULL) || (pModule->IsBeingUnloaded()))
5224     {
5225         return CORPROF_E_DATAINCOMPLETE;
5226     }
5227
5228     // First, check the RID map. This is important since it
5229     // works during teardown (and the below doesn't)
5230     TypeHandle th;
5231     th = pModule->LookupTypeDef(typeDef);
5232     if (th.IsNull())
5233     {
5234         HRESULT hr = S_OK;
5235
5236         EX_TRY {
5237             th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, typeDef,
5238                                                       ClassLoader::ThrowIfNotFound,
5239                                                       ClassLoader::PermitUninstDefOrRef);
5240         }
5241         EX_CATCH_HRESULT(hr);
5242
5243         if (FAILED(hr))
5244         {
5245             return hr;
5246         }
5247     }
5248
5249     if (!th.GetMethodTable())
5250     {
5251         return CORPROF_E_DATAINCOMPLETE;
5252     }
5253
5254     //
5255     // Check if it is generic
5256     //
5257     ClassID classId = NonGenericTypeHandleToClassID(th);
5258
5259     if (classId == NULL)
5260     {
5261         return CORPROF_E_TYPE_IS_PARAMETERIZED;
5262     }
5263
5264     // Return value if necessary
5265     if (pClassId)
5266     {
5267         *pClassId = classId;
5268     }
5269
5270     return S_OK;
5271 }
5272
5273
5274 HRESULT ProfToEEInterfaceImpl::GetClassFromTokenAndTypeArgs(ModuleID moduleID,
5275                                                             mdTypeDef typeDef,
5276                                                             ULONG32 cTypeArgs,
5277                                                             ClassID typeArgs[],
5278                                                             ClassID* pClassID)
5279 {
5280     CONTRACTL
5281     {
5282         // Yay!
5283         NOTHROW;
5284
5285         // LoadGenericInstantiationThrowing may load
5286         GC_TRIGGERS;
5287
5288         // Yay!
5289         MODE_ANY;
5290
5291         // ClassLoader::LoadGenericInstantiationThrowing takes a lock
5292         CAN_TAKE_LOCK;
5293
5294     }
5295     CONTRACTL_END;
5296         
5297     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5298         kP2EEAllowableAfterAttach | kP2EETriggers,
5299         (LF_CORPROF, 
5300          LL_INFO1000, 
5301          "**PROF: GetClassFromTokenAndTypeArgs 0x%p, 0x%08x.\n",
5302          moduleID, 
5303          typeDef));    
5304     
5305     if (!g_profControlBlock.fBaseSystemClassesLoaded)
5306     {
5307         return CORPROF_E_RUNTIME_UNINITIALIZED;
5308     }
5309
5310     Module* pModule = reinterpret_cast< Module* >(moduleID);
5311
5312     if (pModule == NULL || pModule->IsBeingUnloaded())
5313     {
5314         return CORPROF_E_DATAINCOMPLETE;
5315     }
5316
5317     // This array needs to be accessible at least until the call to
5318     // ClassLoader::LoadGenericInstantiationThrowing
5319     TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5320     NewArrayHolder< TypeHandle > holder(genericParameters);
5321
5322     if (NULL == genericParameters)
5323     {
5324         return E_OUTOFMEMORY;
5325     }
5326
5327     for (ULONG32 i = 0; i < cTypeArgs; ++i)
5328     {
5329         genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5330     }
5331
5332     //
5333     // nickbe 11/24/2003 10:12:56
5334     //
5335     // In RTM/Everett we decided to load the class if it hadn't been loaded yet
5336     // (see ProfToEEInterfaceImpl::GetClassFromToken). For compatibility we're
5337     // going to make the same decision here. It's potentially confusing to tell
5338     // someone a type doesn't exist at one point in time, but does exist later,
5339     // and there is no good way for us to determing that a class may eventually
5340     // be loaded without going ahead and loading it
5341     //
5342     TypeHandle th;
5343     HRESULT hr = S_OK;
5344
5345     EX_TRY
5346     {
5347         // Not sure if this is a valid override or not - making this a VIOLATION
5348         // until we're sure.
5349         CONTRACT_VIOLATION(LoadsTypeViolation);
5350     
5351         if (GetThreadNULLOk() == NULL)
5352         {
5353             // Type system will try to validate as part of its contract if the current 
5354             // AppDomain returned by GetAppDomain can load types in specified module's 
5355             // assembly.   On a non-EE thread it results in an AV in a check build 
5356             // since the type system tries to dereference NULL returned by GetAppDomain.  
5357             // More importantly, loading a type on a non-EE thread is not allowed.
5358             //
5359             // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE() states that callers will not 
5360             // try to load a type, so that type system will not try to test type 
5361             // loadability in the current AppDomain.  However, 
5362             // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE does not prevent callers from 
5363             // loading a type.   It is profiler's responsibility not to attempt to load
5364             // a type in unsupported ways (e.g. from a non-EE thread).  It doesn't 
5365             // impact retail builds, in which contracts are not available. 
5366             ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5367
5368             // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE also defines FAULT_FORBID, which 
5369             // causes Scanruntime to flag a fault violation in AssemblySpec::InitializeSpec,
5370             // which is defined as FAULTS.   It only happens in a type-loading path, which
5371             // is not supported on a non-EE thread.  Suppressing a contract violation in an
5372             // unsupported execution path is more preferable than causing AV when calling
5373             // GetClassFromTokenAndTypeArgs on a non-EE thread in a check build.  See Dev10 
5374             // 682526 for more details.
5375             FAULT_NOT_FATAL();
5376
5377             th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5378                                                                typeDef,
5379                                                                Instantiation(genericParameters, cTypeArgs),
5380                                                                ClassLoader::LoadTypes);
5381         }
5382         else
5383         {
5384             th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5385                                                                typeDef,
5386                                                                Instantiation(genericParameters, cTypeArgs),
5387                                                                ClassLoader::LoadTypes);
5388         }
5389     }
5390     EX_CATCH_HRESULT(hr);
5391
5392     if (FAILED(hr))
5393     {
5394         return hr;
5395     }
5396
5397     if (th.IsNull())
5398     {
5399         // Hmm, the type isn't loaded yet.
5400         return CORPROF_E_DATAINCOMPLETE;
5401     }
5402
5403     *pClassID = TypeHandleToClassID(th);
5404
5405     return S_OK;
5406 }
5407
5408 //*****************************************************************************
5409 // Given the token for a method, return the fucntion id.
5410 //*****************************************************************************
5411 HRESULT ProfToEEInterfaceImpl::GetFunctionFromToken(ModuleID moduleId,
5412     mdToken typeDef,
5413     FunctionID *pFunctionId)
5414 {
5415     CONTRACTL
5416     {
5417         // Yay!
5418         NOTHROW;
5419
5420         // Yay!
5421         GC_NOTRIGGER;
5422
5423         // Yay!
5424         MODE_ANY;
5425
5426         // Yay!
5427         EE_THREAD_NOT_REQUIRED;
5428
5429         // Yay!
5430         CANNOT_TAKE_LOCK;
5431
5432     }
5433     CONTRACTL_END;
5434
5435     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5436         (LF_CORPROF, 
5437          LL_INFO1000, 
5438          "**PROF: GetFunctionFromToken 0x%p, 0x%08x.\n",
5439          moduleId, 
5440          typeDef));    
5441         
5442     if ((moduleId == NULL) || (typeDef == mdTokenNil))
5443     {
5444         return E_INVALIDARG;
5445     }
5446     
5447     if (!g_profControlBlock.fBaseSystemClassesLoaded)
5448     {
5449         return CORPROF_E_RUNTIME_UNINITIALIZED;
5450     }
5451
5452     // Default HRESULT
5453     HRESULT hr = S_OK;
5454
5455     // Get the module
5456     Module *pModule = (Module *) moduleId;
5457
5458     // No module, or disassociated from metadata
5459     if (pModule == NULL || pModule->IsBeingUnloaded())
5460     {
5461         return CORPROF_E_DATAINCOMPLETE;
5462     }
5463
5464     // Default return value of NULL
5465     MethodDesc *pDesc = NULL;
5466
5467     // Different lookup depending on whether it's a Def or Ref
5468     if (TypeFromToken(typeDef) == mdtMethodDef)
5469     {
5470         pDesc = pModule->LookupMethodDef(typeDef);
5471     }
5472     else if (TypeFromToken(typeDef) == mdtMemberRef)
5473     {
5474         pDesc = pModule->LookupMemberRefAsMethod(typeDef);
5475     }
5476     else
5477     {
5478         return E_INVALIDARG;
5479     }
5480
5481     if (NULL == pDesc)
5482     {
5483         return E_INVALIDARG;
5484     }
5485
5486     //
5487     // Check that this is a non-generic method
5488     //
5489     if (pDesc->HasClassOrMethodInstantiation())
5490     {
5491         return CORPROF_E_FUNCTION_IS_PARAMETERIZED;
5492     }
5493
5494     if (pFunctionId && SUCCEEDED(hr))
5495     {
5496         *pFunctionId = MethodDescToFunctionID(pDesc);
5497     }
5498
5499     return (hr);
5500 }
5501
5502 HRESULT ProfToEEInterfaceImpl::GetFunctionFromTokenAndTypeArgs(ModuleID moduleID,
5503                                                                mdMethodDef funcDef,
5504                                                                ClassID classId,
5505                                                                ULONG32 cTypeArgs,
5506                                                                ClassID typeArgs[],
5507                                                                FunctionID* pFunctionID)
5508 {
5509     CONTRACTL
5510     {
5511         // Yay!
5512         NOTHROW;
5513
5514         // It can trigger type loads
5515         GC_TRIGGERS;
5516
5517         // Yay!
5518         MODE_ANY;
5519
5520         // MethodDesc::FindOrCreateAssociatedMethodDesc enters a Crst
5521         CAN_TAKE_LOCK;
5522
5523     }
5524     CONTRACTL_END;
5525
5526     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5527         kP2EEAllowableAfterAttach | kP2EETriggers,
5528         (LF_CORPROF, 
5529          LL_INFO1000, 
5530          "**PROF: GetFunctionFromTokenAndTypeArgs 0x%p, 0x%08x, 0x%p.\n",
5531          moduleID, 
5532          funcDef, 
5533          classId));        
5534     
5535     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
5536     Module* pModule = reinterpret_cast< Module* >(moduleID);
5537
5538     if ((pModule == NULL) || typeHandle.IsNull())
5539     {
5540         return E_INVALIDARG;
5541     }
5542          
5543     if (!g_profControlBlock.fBaseSystemClassesLoaded)
5544     {
5545         return CORPROF_E_RUNTIME_UNINITIALIZED;
5546     }
5547
5548     if (pModule->IsBeingUnloaded())
5549     {
5550         return CORPROF_E_DATAINCOMPLETE;
5551     }
5552
5553     MethodDesc* pMethodDesc = NULL;
5554
5555     if (mdtMethodDef == TypeFromToken(funcDef))
5556     {
5557         pMethodDesc = pModule->LookupMethodDef(funcDef);
5558     }
5559     else if (mdtMemberRef == TypeFromToken(funcDef))
5560     {
5561         pMethodDesc = pModule->LookupMemberRefAsMethod(funcDef);
5562     }
5563     else
5564     {
5565         return E_INVALIDARG;
5566     }
5567
5568     MethodTable* pMethodTable = typeHandle.GetMethodTable();
5569
5570     if (pMethodTable == NULL || !pMethodTable->IsRestored() || 
5571         pMethodDesc == NULL || !pMethodDesc->IsRestored())
5572     {
5573         return CORPROF_E_DATAINCOMPLETE;
5574     }
5575
5576     // This array needs to be accessible at least until the call to
5577     // MethodDesc::FindOrCreateAssociatedMethodDesc
5578     TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5579     NewArrayHolder< TypeHandle > holder(genericParameters);
5580
5581     if (NULL == genericParameters)
5582     {
5583         return E_OUTOFMEMORY;
5584     }
5585
5586     for (ULONG32 i = 0; i < cTypeArgs; ++i)
5587     {
5588         genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5589     }
5590
5591     MethodDesc* result = NULL;
5592     HRESULT hr = S_OK;
5593
5594     EX_TRY
5595     {
5596         result = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethodDesc,
5597                                                               pMethodTable,
5598                                                               FALSE,
5599                                                               Instantiation(genericParameters, cTypeArgs),
5600                                                               TRUE);
5601     }
5602     EX_CATCH_HRESULT(hr);
5603
5604     if (NULL != result)
5605     {
5606         *pFunctionID = MethodDescToFunctionID(result);
5607     }
5608
5609     return hr;
5610 }
5611
5612 //*****************************************************************************
5613 // Retrieve information about a given application domain, which is like a
5614 // sub-process.
5615 //*****************************************************************************
5616 HRESULT ProfToEEInterfaceImpl::GetAppDomainInfo(AppDomainID appDomainId,
5617     ULONG       cchName,
5618     ULONG       *pcchName,
5619     __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5620     ProcessID   *pProcessId)
5621 {
5622     CONTRACTL
5623     {
5624         // Yay!
5625         NOTHROW;
5626
5627         // AppDomain::GetFriendlyNameForDebugger triggers
5628         GC_TRIGGERS;
5629
5630         // Yay!
5631         MODE_ANY;
5632
5633         // AppDomain::GetFriendlyNameForDebugger takes a lock
5634         CAN_TAKE_LOCK;
5635
5636     }
5637     CONTRACTL_END;
5638
5639     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5640         kP2EEAllowableAfterAttach | kP2EETriggers,
5641         (LF_CORPROF, 
5642          LL_INFO1000, 
5643          "**PROF: GetAppDomainInfo 0x%p.\n",
5644          appDomainId));
5645     
5646     if (appDomainId == NULL)
5647     {
5648         return E_INVALIDARG;
5649     }
5650     
5651     BaseDomain   *pDomain;            // Internal data structure.
5652     HRESULT     hr = S_OK;
5653
5654     // <TODO>@todo:
5655     // Right now, this ID is not a true AppDomain, since we use the old
5656     // AppDomain/SystemDomain model in the profiling API.  This means that
5657     // the profiler exposes the SharedDomain and the SystemDomain to the
5658     // outside world. It's not clear whether this is actually the right thing
5659     // to do or not. - seantrow
5660     //
5661     // Postponed to V2.
5662     // </TODO>
5663
5664     pDomain = (BaseDomain *) appDomainId;
5665
5666     // Make sure they've passed in a valid appDomainId
5667     if (pDomain == NULL)
5668         return (E_INVALIDARG);
5669
5670     // Pick sensible defaults.
5671     if (pcchName)
5672         *pcchName = 0;
5673     if (szName)
5674         *szName = 0;
5675     if (pProcessId)
5676         *pProcessId = 0;
5677
5678     LPCWSTR szFriendlyName;
5679     if (pDomain == SystemDomain::System())
5680         szFriendlyName = g_pwBaseLibrary;
5681     else
5682         szFriendlyName = ((AppDomain*)pDomain)->GetFriendlyNameForDebugger();
5683
5684     if (szFriendlyName != NULL)
5685     {
5686         // Get the module file name
5687         ULONG trueLen = (ULONG)(wcslen(szFriendlyName) + 1);
5688
5689         // Return name of module as required.
5690         if (szName && cchName > 0)
5691         {
5692             ULONG copyLen = trueLen;
5693
5694             if (copyLen >= cchName)
5695             {
5696                 copyLen = cchName - 1;
5697             }
5698
5699             wcsncpy_s(szName, cchName, szFriendlyName, copyLen);
5700         }
5701
5702         // If they request the actual length of the name
5703         if (pcchName)
5704             *pcchName = trueLen;
5705     }
5706
5707     // If we don't have a friendly name but the call was requesting it, then return incomplete data HR
5708     else
5709     {
5710         if ((szName != NULL && cchName > 0) || pcchName)
5711             hr = CORPROF_E_DATAINCOMPLETE;
5712     }
5713
5714     if (pProcessId)
5715         *pProcessId = (ProcessID) GetCurrentProcessId();
5716
5717     return (hr);
5718 }
5719
5720
5721 //*****************************************************************************
5722 // Retrieve information about an assembly, which is a collection of dll's.
5723 //*****************************************************************************
5724 HRESULT ProfToEEInterfaceImpl::GetAssemblyInfo(AssemblyID    assemblyId,
5725     ULONG       cchName,
5726     ULONG       *pcchName,
5727     __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5728     AppDomainID *pAppDomainId,
5729     ModuleID    *pModuleId)
5730 {
5731     CONTRACTL
5732     {
5733         // SString::SString throws
5734         THROWS;
5735
5736         // Yay!
5737         GC_NOTRIGGER;
5738
5739         // Yay!
5740         MODE_ANY;
5741
5742         // Yay!
5743         EE_THREAD_NOT_REQUIRED;
5744
5745         // PEAssembly::GetSimpleName() enters a lock via use of the metadata interface
5746         CAN_TAKE_LOCK;
5747
5748     }
5749     CONTRACTL_END;
5750
5751     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5752         (LF_CORPROF, 
5753          LL_INFO1000, 
5754          "**PROF: GetAssemblyInfo 0x%p.\n", 
5755          assemblyId));    
5756     
5757     if (assemblyId == NULL)
5758     {
5759         return E_INVALIDARG;
5760     }
5761     
5762     HRESULT hr = S_OK;
5763
5764     Assembly    *pAssembly;             // Internal data structure for assembly.
5765
5766     pAssembly = (Assembly *) assemblyId;
5767     _ASSERTE(pAssembly != NULL);
5768
5769     if (pcchName || szName)
5770     {
5771         // Get the friendly name of the assembly
5772         SString name(SString::Utf8, pAssembly->GetSimpleName());
5773
5774         const COUNT_T nameLength = name.GetCount() + 1;
5775
5776         if ((NULL != szName) && (cchName > 0))
5777         {
5778             wcsncpy_s(szName, cchName, name.GetUnicode(), min(nameLength, cchName - 1));
5779         }
5780
5781         if (NULL != pcchName)
5782         {
5783             *pcchName = nameLength;
5784         }
5785     }
5786
5787     // Get the parent application domain.
5788     if (pAppDomainId)
5789     {
5790         *pAppDomainId = (AppDomainID) pAssembly->GetDomain();
5791         _ASSERTE(*pAppDomainId != NULL);
5792     }
5793
5794     // Find the module the manifest lives in.
5795     if (pModuleId)
5796     {
5797         *pModuleId = (ModuleID) pAssembly->GetManifestModule();
5798
5799         // This is the case where the profiler has called GetAssemblyInfo
5800         // on an assembly that has been completely created yet.
5801         if (!*pModuleId)
5802             hr = CORPROF_E_DATAINCOMPLETE;
5803     }
5804
5805     return (hr);
5806 }
5807
5808 // Setting ELT hooks is only allowed from within Initialize().  However, test-only
5809 // profilers may need to set those hooks from an attaching profiling.  See
5810 // code:ProfControlBlock#TestOnlyELT
5811 #ifdef PROF_TEST_ONLY_FORCE_ELT
5812 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT(logParams)                                   \
5813     do                                                                                  \
5814     {                                                                                   \
5815         if (g_profControlBlock.fTestOnlyForceEnterLeave)                                \
5816         {                                                                               \
5817             PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, logParams);  \
5818         }                                                                               \
5819         else                                                                            \
5820         {                                                                               \
5821             PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams);                \
5822         }                                                                               \
5823     } while(0)
5824 #else //  PROF_TEST_ONLY_FORCE_ELT
5825 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT                                              \
5826     PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY
5827 #endif //  PROF_TEST_ONLY_FORCE_ELT
5828
5829
5830 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
5831                                                           FunctionLeave * pFuncLeave,
5832                                                           FunctionTailcall * pFuncTailcall)
5833 {
5834     CONTRACTL
5835     {
5836         // Yay!
5837         NOTHROW;
5838
5839         // Yay!
5840         GC_NOTRIGGER;
5841
5842         // Yay!
5843         MODE_ANY;
5844
5845         // Yay!
5846         EE_THREAD_NOT_REQUIRED;
5847
5848         CANNOT_TAKE_LOCK;
5849
5850     }
5851     CONTRACTL_END;
5852
5853     // The profiler must call SetEnterLeaveFunctionHooks during initialization, since
5854     // the enter/leave events are immutable and must also be set during initialization.
5855     PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF, 
5856                                         LL_INFO10, 
5857                                         "**PROF: SetEnterLeaveFunctionHooks 0x%p, 0x%p, 0x%p.\n",
5858                                         pFuncEnter, 
5859                                         pFuncLeave, 
5860                                         pFuncTailcall));
5861
5862     return g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall);
5863 }
5864
5865
5866 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
5867                                                            FunctionLeave2 * pFuncLeave,
5868                                                            FunctionTailcall2 * pFuncTailcall)
5869 {
5870     CONTRACTL
5871     {
5872         // Yay!
5873         NOTHROW;
5874
5875         // Yay!
5876         GC_NOTRIGGER;
5877
5878         // Yay!
5879         MODE_ANY;
5880
5881         // Yay!
5882         EE_THREAD_NOT_REQUIRED;
5883
5884         CANNOT_TAKE_LOCK;
5885
5886     }
5887     CONTRACTL_END;
5888
5889     // The profiler must call SetEnterLeaveFunctionHooks2 during initialization, since
5890     // the enter/leave events are immutable and must also be set during initialization.
5891     PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF, 
5892                                         LL_INFO10, 
5893                                         "**PROF: SetEnterLeaveFunctionHooks2 0x%p, 0x%p, 0x%p.\n", 
5894                                         pFuncEnter, 
5895                                         pFuncLeave, 
5896                                         pFuncTailcall));    
5897
5898     return 
5899         g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall);
5900 }
5901
5902
5903 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
5904                                                            FunctionLeave3 * pFuncLeave3,
5905                                                            FunctionTailcall3 * pFuncTailcall3)
5906 {
5907     CONTRACTL
5908     {
5909         // Yay!
5910         NOTHROW;
5911
5912         // Yay!
5913         GC_NOTRIGGER;
5914
5915         // Yay!
5916         MODE_ANY;
5917
5918         // Yay!
5919         EE_THREAD_NOT_REQUIRED;
5920
5921         CANNOT_TAKE_LOCK;
5922
5923     }
5924     CONTRACTL_END;
5925
5926     // The profiler must call SetEnterLeaveFunctionHooks3 during initialization, since
5927     // the enter/leave events are immutable and must also be set during initialization.
5928     PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF, 
5929                                         LL_INFO10, 
5930                                         "**PROF: SetEnterLeaveFunctionHooks3 0x%p, 0x%p, 0x%p.\n", 
5931                                         pFuncEnter3, 
5932                                         pFuncLeave3, 
5933                                         pFuncTailcall3));    
5934
5935     return 
5936         g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3, 
5937                                                                        pFuncLeave3, 
5938                                                                        pFuncTailcall3);
5939 }
5940
5941
5942
5943 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
5944                                                                    FunctionLeave3WithInfo * pFuncLeave3WithInfo,
5945                                                                    FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
5946 {
5947     CONTRACTL
5948     {
5949         // Yay!
5950         NOTHROW;
5951
5952         // Yay!
5953         GC_NOTRIGGER;
5954
5955         // Yay!
5956         MODE_ANY;
5957
5958         // Yay!
5959         EE_THREAD_NOT_REQUIRED;
5960
5961         CANNOT_TAKE_LOCK;
5962
5963     }
5964     CONTRACTL_END;
5965
5966     // The profiler must call SetEnterLeaveFunctionHooks3WithInfo during initialization, since
5967     // the enter/leave events are immutable and must also be set during initialization.
5968     PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5969                                         LL_INFO10, 
5970                                         "**PROF: SetEnterLeaveFunctionHooks3WithInfo 0x%p, 0x%p, 0x%p.\n", 
5971                                         pFuncEnter3WithInfo, 
5972                                         pFuncLeave3WithInfo, 
5973                                         pFuncTailcall3WithInfo));    
5974
5975     return 
5976         g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo, 
5977                                                                                pFuncLeave3WithInfo, 
5978                                                                                pFuncTailcall3WithInfo);
5979 }
5980
5981
5982 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper(FunctionIDMapper *pFunc)
5983 {
5984     CONTRACTL
5985     {
5986         // Yay!
5987         NOTHROW;
5988
5989         // Yay!
5990         GC_NOTRIGGER;
5991
5992         // Yay!
5993         MODE_ANY;
5994
5995         // Yay!
5996         EE_THREAD_NOT_REQUIRED;
5997
5998         // Yay!
5999         CANNOT_TAKE_LOCK;
6000     
6001     }
6002     CONTRACTL_END;
6003     
6004     PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF, 
6005                                       LL_INFO10, 
6006                                       "**PROF: SetFunctionIDMapper 0x%p.\n",
6007                                       pFunc));
6008     
6009     g_profControlBlock.pProfInterface->SetFunctionIDMapper(pFunc);
6010
6011     return (S_OK);
6012 }
6013
6014 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper2(FunctionIDMapper2 *pFunc, void * clientData)
6015 {
6016     CONTRACTL
6017     {
6018         // Yay!
6019         NOTHROW;
6020
6021         // Yay!
6022         GC_NOTRIGGER;
6023
6024         // Yay!
6025         MODE_ANY;
6026
6027         // Yay!
6028         EE_THREAD_NOT_REQUIRED;
6029
6030         // Yay!
6031         CANNOT_TAKE_LOCK;
6032     
6033     }
6034     CONTRACTL_END;
6035     
6036     PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF, 
6037                                       LL_INFO10, 
6038                                       "**PROF: SetFunctionIDMapper2. pFunc: 0x%p. clientData: 0x%p.\n",
6039                                       pFunc,
6040                                       clientData));
6041     
6042     g_profControlBlock.pProfInterface->SetFunctionIDMapper2(pFunc, clientData);
6043
6044     return (S_OK);
6045 }
6046
6047 /*
6048  * GetFunctionInfo2
6049  *
6050  * This function takes the frameInfo returned from a profiler callback and splays it
6051  * out into as much information as possible.
6052  *
6053  * Parameters:
6054  *   funcId - The function that is being requested.
6055  *   frameInfo - Frame specific information from a callback (for resolving generics).
6056  *   pClassId - An optional parameter for returning the class id of the function.
6057  *   pModuleId - An optional parameter for returning the module of the function.
6058  *   pToken - An optional parameter for returning the metadata token of the function.
6059  *   cTypeArgs - The count of the size of the array typeArgs
6060  *   pcTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
6061  *         the number that would be needed.
6062  *   typeArgs - An array to store generic type parameters for the function.
6063  *
6064  * Returns:
6065  *   S_OK if successful.
6066  */
6067 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo2(FunctionID funcId,
6068                                              COR_PRF_FRAME_INFO frameInfo,
6069                                              ClassID *pClassId,
6070                                              ModuleID *pModuleId,
6071                                              mdToken *pToken,
6072                                              ULONG32 cTypeArgs,
6073                                              ULONG32 *pcTypeArgs,
6074                                              ClassID typeArgs[])
6075 {
6076     CONTRACTL
6077     {
6078         // Yay!
6079         NOTHROW;
6080
6081         // Yay!
6082         GC_NOTRIGGER;
6083
6084         // Yay!
6085         MODE_ANY;
6086
6087         // Yay!
6088         EE_THREAD_NOT_REQUIRED;
6089
6090         // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6091         // reads metadata which causes us to take a reader lock.  However, see
6092         // code:#DisableLockOnAsyncCalls
6093         DISABLED(CAN_TAKE_LOCK);
6094
6095         // Asynchronous functions can be called at arbitrary times when runtime 
6096         // is holding locks that cannot be reentered without causing deadlock.
6097         // This contract detects any attempts to reenter locks held at the time 
6098         // this function was called.  
6099         CANNOT_RETAKE_LOCK;
6100
6101
6102         PRECONDITION(CheckPointer(pClassId, NULL_OK));
6103         PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6104         PRECONDITION(CheckPointer(pToken,  NULL_OK));
6105         PRECONDITION(CheckPointer(pcTypeArgs, NULL_OK));
6106         PRECONDITION(CheckPointer(typeArgs, NULL_OK));
6107     }
6108     CONTRACTL_END;
6109
6110     // See code:#DisableLockOnAsyncCalls
6111     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6112
6113     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6114         (LF_CORPROF, 
6115         LL_INFO1000, 
6116         "**PROF: GetFunctionInfo2 0x%p.\n",
6117         funcId));
6118
6119     //
6120     // Verify parameters.
6121     //
6122     COR_PRF_FRAME_INFO_INTERNAL *pFrameInfo = (COR_PRF_FRAME_INFO_INTERNAL *)frameInfo;
6123
6124     if ((funcId == NULL) ||
6125         ((pFrameInfo != NULL) && (pFrameInfo->funcID != funcId)))
6126     {
6127         return E_INVALIDARG;
6128     }
6129
6130     MethodDesc *pMethDesc = FunctionIdToMethodDesc(funcId);
6131
6132     if (pMethDesc == NULL)
6133     {
6134         return E_INVALIDARG;
6135     }
6136
6137     if ((cTypeArgs != 0) && (typeArgs == NULL))
6138     {
6139         return E_INVALIDARG;
6140     }
6141
6142     // it's not safe to examine a methoddesc that has not been restored so do not do so
6143     if (!pMethDesc ->IsRestored())
6144         return CORPROF_E_DATAINCOMPLETE;      
6145
6146     //
6147     // Find the exact instantiation of this function.
6148     //
6149     TypeHandle specificClass;
6150     MethodDesc* pActualMethod;
6151
6152     ClassID classId = NULL;
6153
6154     if (pMethDesc->IsSharedByGenericInstantiations())
6155     {
6156         BOOL exactMatch;
6157         OBJECTREF pThis = NULL;
6158
6159         if (pFrameInfo != NULL)
6160         {
6161             // If FunctionID represents a generic methoddesc on a struct, then pFrameInfo->thisArg
6162             // isn't an Object*.  It's a pointer directly into the struct's members (i.e., it's not pointing at the
6163             // method table).  That means pFrameInfo->thisArg cannot be casted to an OBJECTREF for
6164             // use by Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation.  However,
6165             // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation won't even need a this pointer
6166             // for the methoddesc it's processing if the methoddesc is on a value type.  So we
6167             // can safely pass NULL for the methoddesc's this in such a case.
6168             if (pMethDesc->GetMethodTable()->IsValueType())
6169             {
6170                 _ASSERTE(!pMethDesc->AcquiresInstMethodTableFromThis());
6171                 _ASSERTE(pThis == NULL);
6172             }
6173             else
6174             {
6175                 pThis = ObjectToOBJECTREF((PTR_Object)(pFrameInfo->thisArg));
6176             }
6177         }
6178
6179         exactMatch = Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
6180             pMethDesc,
6181             pThis,
6182             PTR_VOID((pFrameInfo != NULL) ? pFrameInfo->extraArg : NULL),
6183             &specificClass,
6184             &pActualMethod);
6185
6186         if (exactMatch)
6187         {
6188             classId = TypeHandleToClassID(specificClass);
6189         }
6190         else if (!specificClass.HasInstantiation() || !specificClass.IsSharedByGenericInstantiations())
6191         {
6192             //
6193             // In this case we could not get the type args for the method, but if the class 
6194             // is not a generic class or is instantiated with value types, this value is correct.
6195             //
6196             classId = TypeHandleToClassID(specificClass);
6197         }
6198         else
6199         {
6200             //
6201             // We could not get any class information.
6202             //
6203             classId = NULL;
6204         }
6205     }
6206     else
6207     {
6208         TypeHandle typeHandle(pMethDesc->GetMethodTable());
6209         classId = TypeHandleToClassID(typeHandle);
6210         pActualMethod = pMethDesc;
6211     }
6212
6213
6214     //
6215     // Fill in the ClassId, if desired
6216     //
6217     if (pClassId != NULL)
6218     {
6219         *pClassId = classId;
6220     }
6221
6222     //
6223     // Fill in the ModuleId, if desired.
6224     //
6225     if (pModuleId != NULL)
6226     {
6227         *pModuleId = (ModuleID)pMethDesc->GetModule();
6228     }
6229
6230     //
6231     // Fill in the token, if desired.
6232     //
6233     if (pToken != NULL)
6234     {
6235         *pToken = (mdToken)pMethDesc->GetMemberDef();
6236     }
6237
6238     if ((cTypeArgs == 0) && (pcTypeArgs != NULL))
6239     {
6240         //
6241         // They are searching for the size of the array needed, we can return that now and
6242         // short-circuit all the work below.
6243         //
6244         if (pcTypeArgs != NULL)
6245         {
6246             *pcTypeArgs = pActualMethod->GetNumGenericMethodArgs();
6247         }
6248         return S_OK;
6249     }
6250
6251     //
6252     // If no place to store resulting count, quit now.
6253     //
6254     if (pcTypeArgs == NULL)
6255     {
6256         return S_OK;
6257     }
6258
6259     //
6260     // Fill in the type args
6261     //
6262     DWORD cArgsToFill = pActualMethod->GetNumGenericMethodArgs();
6263
6264     if (cArgsToFill > cTypeArgs)
6265     {
6266         cArgsToFill = cTypeArgs;
6267     }
6268
6269     *pcTypeArgs = cArgsToFill;
6270
6271     if (cArgsToFill == 0)
6272     {
6273         return S_OK;
6274     }
6275
6276     Instantiation inst = pActualMethod->GetMethodInstantiation();
6277
6278     for (DWORD i = 0; i < cArgsToFill; i++)
6279     {
6280         typeArgs[i] = TypeHandleToClassID(inst[i]);
6281     }
6282
6283     return S_OK;
6284 }
6285
6286 /*
6287 * IsFunctionDynamic
6288 *
6289 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6290 * or LCG method and returns true in the pHasNoMetadata if it is indeed a metadata-less
6291 * method.
6292 *
6293 * Parameters:
6294 *   functionId - The function that is being requested.
6295 *   isDynamic - An optional parameter for returning if the function has metadata or not.
6296 *
6297 * Returns:
6298 *   S_OK if successful.
6299 */
6300 HRESULT ProfToEEInterfaceImpl::IsFunctionDynamic(FunctionID functionId, BOOL *isDynamic)
6301 {
6302     CONTRACTL
6303     {
6304         NOTHROW;
6305         GC_NOTRIGGER;
6306         MODE_ANY;
6307         EE_THREAD_NOT_REQUIRED;
6308
6309         // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6310         // reads metadata which causes us to take a reader lock.  However, see
6311         // code:#DisableLockOnAsyncCalls
6312         DISABLED(CAN_TAKE_LOCK);
6313
6314         // Asynchronous functions can be called at arbitrary times when runtime 
6315         // is holding locks that cannot be reentered without causing deadlock.
6316         // This contract detects any attempts to reenter locks held at the time 
6317         // this function was called.  
6318         CANNOT_RETAKE_LOCK;
6319
6320
6321         PRECONDITION(CheckPointer(isDynamic, NULL_OK));
6322     }
6323     CONTRACTL_END;
6324
6325     // See code:#DisableLockOnAsyncCalls
6326     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6327
6328     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6329         (LF_CORPROF,
6330             LL_INFO1000,
6331             "**PROF: IsFunctionDynamic 0x%p.\n",
6332             functionId));
6333
6334     //
6335     // Verify parameters.
6336     //
6337
6338     if (functionId == NULL)
6339     {
6340         return E_INVALIDARG;
6341     }
6342
6343     MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6344
6345     if (pMethDesc == NULL)
6346     {
6347         return E_INVALIDARG;
6348     }
6349
6350     // it's not safe to examine a methoddesc that has not been restored so do not do so
6351     if (!pMethDesc->IsRestored())
6352         return CORPROF_E_DATAINCOMPLETE;
6353
6354     //
6355     // Fill in the pHasNoMetadata, if desired.
6356     //
6357     if (isDynamic != NULL)
6358     {
6359         *isDynamic = pMethDesc->IsNoMetadata();
6360     }
6361
6362     return S_OK;
6363 }
6364
6365 /*
6366 * GetFunctionFromIP3
6367 *
6368 * This function takes an IP and determines if it is a managed function returning its
6369 * FunctionID. This method is different from GetFunctionFromIP in that will return
6370 * FunctionIDs even if they have no associated metadata.
6371 *
6372 * Parameters:
6373 *   ip - The instruction pointer.
6374 *   pFunctionId - An optional parameter for returning the FunctionID.
6375 *   pReJitId - The ReJIT id.
6376 *
6377 * Returns:
6378 *   S_OK if successful.
6379 */
6380 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP3(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
6381 {
6382     CONTRACTL
6383     {
6384         NOTHROW;
6385
6386         // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6387         // which can switch us to preemptive mode and trigger GCs
6388         GC_TRIGGERS;
6389         MODE_ANY;
6390         EE_THREAD_NOT_REQUIRED;
6391
6392         // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6393         CAN_TAKE_LOCK;
6394
6395     }
6396     CONTRACTL_END;
6397
6398     // See code:#DisableLockOnAsyncCalls
6399     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6400
6401     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6402         kP2EEAllowableAfterAttach | kP2EETriggers,
6403         (LF_CORPROF,
6404             LL_INFO1000,
6405             "**PROF: GetFunctionFromIP3 0x%p.\n",
6406             ip));
6407
6408     HRESULT hr = S_OK;
6409
6410     EECodeInfo codeInfo;
6411
6412     hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ FALSE);
6413     if (FAILED(hr))
6414     {
6415         return hr;
6416     }
6417
6418     if (pFunctionId)
6419     {
6420         *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
6421     }
6422
6423     if (pReJitId != NULL)
6424     {
6425         MethodDesc * pMD = codeInfo.GetMethodDesc();
6426         *pReJitId = ReJitManager::GetReJitId(pMD, codeInfo.GetStartAddress());
6427     }
6428
6429     return S_OK;
6430 }
6431
6432 /*
6433 * GetDynamicFunctionInfo
6434 *
6435 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6436 * or LCG method and gives information about it without failing like GetFunctionInfo.
6437 *
6438 * Parameters:
6439 *   functionId - The function that is being requested.
6440 *   pModuleId - An optional parameter for returning the module of the function.
6441 *   ppvSig -  An optional parameter for returning the signature of the function.
6442 *   pbSig - An optional parameter for returning the size of the signature of the function.
6443 *   cchName - A parameter for indicating the size of buffer for the wszName parameter.
6444 *   pcchName - An optional parameter for returning the true size of the wszName parameter.
6445 *   wszName - A parameter to the caller allocated buffer of size cchName
6446 *
6447 * Returns:
6448 *   S_OK if successful.
6449 */
6450 HRESULT ProfToEEInterfaceImpl::GetDynamicFunctionInfo(FunctionID functionId,
6451                                                       ModuleID *pModuleId,
6452                                                       PCCOR_SIGNATURE* ppvSig,
6453                                                       ULONG* pbSig,
6454                                                       ULONG cchName,
6455                                                       ULONG *pcchName,
6456             __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[])
6457 {
6458     CONTRACTL
6459     {
6460         NOTHROW;
6461         GC_NOTRIGGER;
6462         MODE_ANY;
6463         EE_THREAD_NOT_REQUIRED;
6464
6465         // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6466         // reads metadata which causes us to take a reader lock.  However, see
6467         // code:#DisableLockOnAsyncCalls
6468         DISABLED(CAN_TAKE_LOCK);
6469
6470         // Asynchronous functions can be called at arbitrary times when runtime 
6471         // is holding locks that cannot be reentered without causing deadlock.
6472         // This contract detects any attempts to reenter locks held at the time 
6473         // this function was called.  
6474         CANNOT_RETAKE_LOCK;
6475
6476
6477         PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6478         PRECONDITION(CheckPointer(ppvSig, NULL_OK));
6479         PRECONDITION(CheckPointer(pbSig,  NULL_OK));
6480         PRECONDITION(CheckPointer(pcchName, NULL_OK));
6481     }
6482     CONTRACTL_END;
6483
6484     // See code:#DisableLockOnAsyncCalls
6485     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6486
6487     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6488         (LF_CORPROF,
6489             LL_INFO1000,
6490             "**PROF: GetDynamicFunctionInfo 0x%p.\n",
6491             functionId));
6492
6493     //
6494     // Verify parameters.
6495     //
6496
6497     if (functionId == NULL)
6498     {
6499         return E_INVALIDARG;
6500     }
6501
6502     MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6503
6504     if (pMethDesc == NULL)
6505     {
6506         return E_INVALIDARG;
6507     }
6508
6509     // it's not safe to examine a methoddesc that has not been restored so do not do so
6510     if (!pMethDesc->IsRestored())
6511         return CORPROF_E_DATAINCOMPLETE;
6512
6513
6514     if (!pMethDesc->IsNoMetadata())
6515         return E_INVALIDARG;
6516
6517     //
6518     // Fill in the ModuleId, if desired.
6519     //
6520     if (pModuleId != NULL)
6521     {
6522         *pModuleId = (ModuleID)pMethDesc->GetModule();
6523     }
6524
6525     //
6526     // Fill in the ppvSig and pbSig, if desired
6527     //
6528     if (ppvSig != NULL && pbSig != NULL)
6529     {
6530         pMethDesc->GetSig(ppvSig, pbSig);
6531     }
6532
6533     HRESULT hr = S_OK;
6534
6535     EX_TRY
6536     {
6537         if (wszName != NULL)
6538             *wszName = 0;
6539         if (pcchName != NULL)
6540             *pcchName = 0;
6541
6542         StackSString ss;
6543         ss.SetUTF8(pMethDesc->GetName());
6544         ss.Normalize();
6545         LPCWSTR methodName = ss.GetUnicode();
6546
6547         ULONG trueLen = (ULONG)(wcslen(methodName) + 1);
6548
6549         // Return name of method as required.
6550         if (wszName && cchName > 0)
6551         {
6552             if (cchName < trueLen)
6553             {
6554                 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6555             }
6556             else
6557             {
6558                 wcsncpy_s(wszName, cchName, methodName, trueLen);
6559             }
6560         }
6561
6562         // If they request the actual length of the name
6563         if (pcchName)
6564             *pcchName = trueLen;
6565     }
6566     EX_CATCH_HRESULT(hr);
6567
6568     return (hr);
6569 }
6570
6571 /*
6572  * GetNativeCodeStartAddresses
6573  * 
6574  * Gets all of the native code addresses associated with a particular function. iered compilation 
6575  * potentially creates different native code versions for a method, and this function allows profilers
6576  * to view all native versions of a method.
6577  * 
6578  * Parameters:
6579  *      functionID           - The function that is being requested.
6580  *      reJitId              - The ReJIT id.
6581  *      cCodeStartAddresses  - A parameter for indicating the size of buffer for the codeStartAddresses parameter.
6582  *      pcCodeStartAddresses - An optional parameter for returning the true size of the codeStartAddresses parameter.
6583  *      codeStartAddresses   - The array to be filled up with native code addresses.
6584  * 
6585  * Returns:
6586  *   S_OK if successful
6587  *
6588  */
6589 HRESULT ProfToEEInterfaceImpl::GetNativeCodeStartAddresses(FunctionID functionID, 
6590                                                            ReJITID reJitId, 
6591                                                            ULONG32 cCodeStartAddresses, 
6592                                                            ULONG32 *pcCodeStartAddresses, 
6593                                                            UINT_PTR codeStartAddresses[])
6594 {
6595     CONTRACTL
6596     {
6597         NOTHROW;
6598         GC_NOTRIGGER;
6599         MODE_ANY;
6600         EE_THREAD_NOT_REQUIRED;
6601         CAN_TAKE_LOCK;
6602
6603
6604         PRECONDITION(CheckPointer(pcCodeStartAddresses, NULL_OK));
6605         PRECONDITION(CheckPointer(codeStartAddresses, NULL_OK));
6606     }
6607     CONTRACTL_END;
6608
6609     if (functionID == NULL)
6610     {
6611         return E_INVALIDARG;
6612     }
6613
6614     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6615     (LF_CORPROF,
6616         LL_INFO1000,
6617         "**PROF: GetNativeCodeStartAddresses 0x%p 0x%p.\n",
6618         functionID, reJitId));
6619     
6620     HRESULT hr = S_OK;
6621    
6622     EX_TRY
6623     {
6624         if (pcCodeStartAddresses != NULL)
6625         {
6626             *pcCodeStartAddresses = 0;
6627         }
6628
6629         MethodDesc * methodDesc = FunctionIdToMethodDesc(functionID);
6630         PTR_MethodDesc pMD = PTR_MethodDesc(methodDesc);
6631         ULONG32 trueLen = 0;
6632         StackSArray<UINT_PTR> addresses;
6633
6634         CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
6635
6636         ILCodeVersion ilCodeVersion = NULL;
6637         {
6638             CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
6639
6640             ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
6641             
6642             NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
6643             for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
6644             {
6645                 addresses.Append((*iter).GetNativeCode());
6646
6647                 ++trueLen;
6648             }
6649         }
6650
6651         if (pcCodeStartAddresses != NULL)
6652         {
6653             *pcCodeStartAddresses = trueLen;
6654         }
6655
6656         if (codeStartAddresses != NULL)
6657         {
6658             if (cCodeStartAddresses < trueLen)
6659             {
6660                 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6661             }
6662             else
6663             {
6664                 for(ULONG32 i = 0; i < trueLen; ++i)
6665                 {
6666                     codeStartAddresses[i] = addresses[i];
6667                 }
6668             }
6669         }
6670     }
6671     EX_CATCH_HRESULT(hr);
6672     
6673     return hr;
6674 }
6675
6676 /*
6677  * GetILToNativeMapping3
6678  * 
6679  * This overload behaves the same as GetILToNativeMapping2, except it allows the profiler
6680  * to address specific native code versions instead of defaulting to the first one.
6681  * 
6682  * Parameters:
6683  *      pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
6684  *      cMap                    - size of the map array
6685  *      pcMap                   - how many items are returned in the map array
6686  *      map                     - an array to store the il to native mappings in
6687  *
6688  * Returns:
6689  *   S_OK if successful
6690  *
6691  */
6692 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping3(UINT_PTR pNativeCodeStartAddress, 
6693                                                      ULONG32 cMap, 
6694                                                      ULONG32 *pcMap, 
6695                                                      COR_DEBUG_IL_TO_NATIVE_MAP map[])
6696 {
6697     CONTRACTL
6698     {
6699         THROWS;
6700         DISABLED(GC_NOTRIGGER);
6701         MODE_ANY;
6702         CAN_TAKE_LOCK;
6703
6704
6705         PRECONDITION(CheckPointer(pcMap, NULL_OK));
6706         PRECONDITION(CheckPointer(map, NULL_OK));
6707     }
6708     CONTRACTL_END;
6709
6710     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
6711         (LF_CORPROF, 
6712         LL_INFO1000, 
6713         "**PROF: GetILToNativeMapping3 0x%p.\n",
6714         pNativeCodeStartAddress));
6715
6716     if (pNativeCodeStartAddress == NULL)
6717     {
6718         return E_INVALIDARG;
6719     }
6720
6721     if ((cMap > 0) && 
6722         ((pcMap == NULL) || (map == NULL)))
6723     {
6724         return E_INVALIDARG;
6725     }
6726
6727 #ifdef DEBUGGING_SUPPORTED
6728     if (g_pDebugInterface == NULL)
6729     {
6730         return CORPROF_E_DEBUGGING_DISABLED;
6731     }
6732
6733     return (g_pDebugInterface->GetILToNativeMapping(pNativeCodeStartAddress, cMap, pcMap, map));
6734 #else
6735     return E_NOTIMPL;
6736 #endif
6737 }
6738
6739 /*
6740  * GetCodeInfo4
6741  * 
6742  * Gets the location and size of a jitted function. Tiered compilation potentially creates different native code 
6743  * versions for a method, and this overload allows profilers to specify which native version it would like the 
6744  * code info for.
6745  * 
6746  * Parameters:
6747  *      pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
6748  *      cCodeInfos              - size of the codeInfos array
6749  *      pcCodeInfos             - how many items are returned in the codeInfos array
6750  *      codeInfos               - an array to store the code infos in
6751  *
6752  * Returns:
6753  *   S_OK if successful
6754  *
6755  */
6756 HRESULT ProfToEEInterfaceImpl::GetCodeInfo4(UINT_PTR pNativeCodeStartAddress, 
6757                                             ULONG32 cCodeInfos, 
6758                                             ULONG32* pcCodeInfos, 
6759                                             COR_PRF_CODE_INFO codeInfos[])
6760 {
6761     CONTRACTL
6762     {
6763         NOTHROW;
6764         GC_TRIGGERS;
6765         MODE_ANY;
6766         EE_THREAD_NOT_REQUIRED;
6767         CAN_TAKE_LOCK;
6768         
6769
6770         PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
6771         PRECONDITION(CheckPointer(codeInfos, NULL_OK));
6772     }
6773     CONTRACTL_END;
6774
6775     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6776         kP2EEAllowableAfterAttach | kP2EETriggers,
6777         (LF_CORPROF, 
6778         LL_INFO1000, 
6779         "**PROF: GetCodeInfo4 0x%p.\n", 
6780         pNativeCodeStartAddress));  
6781
6782     if ((cCodeInfos != 0) && (codeInfos == NULL))
6783     {
6784         return E_INVALIDARG;
6785     }
6786
6787     return GetCodeInfoFromCodeStart(pNativeCodeStartAddress,
6788                                     cCodeInfos,
6789                                     pcCodeInfos,
6790                                     codeInfos);
6791 }
6792
6793 /*
6794  * GetObjectReferences
6795  * 
6796  * Gets the object references (if any) from the ObjectID.
6797  * 
6798  * Parameters:
6799  *      objectId        - object id of interest
6800  *      cNumReferences  - count of references for which the profiler has allocated buffer space
6801  *      pcNumReferences - actual count of references
6802  *      references      - filled array of object references
6803  *
6804  * Returns:
6805  *   S_OK if successful
6806  *
6807  */
6808 HRESULT ProfToEEInterfaceImpl::GetObjectReferences(ObjectID objectId, ULONG32 cNumReferences, ULONG32 *pcNumReferences, ObjectID references[], SIZE_T offsets[])
6809 {
6810     CONTRACTL
6811     {
6812         NOTHROW;
6813         GC_NOTRIGGER;
6814         MODE_ANY;
6815         EE_THREAD_NOT_REQUIRED;
6816         CANNOT_TAKE_LOCK;
6817     }
6818     CONTRACTL_END;
6819
6820     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6821         kP2EEAllowableAfterAttach,
6822         (LF_CORPROF,
6823         LL_INFO1000,
6824         "**PROF: GetObjectReferences 0x%p.\n",
6825         objectId));
6826
6827     if (cNumReferences > 0 && (pcNumReferences == nullptr || references == nullptr || offsets == nullptr))
6828     {
6829         return E_INVALIDARG;
6830     }
6831
6832     Object* pBO = (Object*)objectId;
6833     MethodTable *pMT = pBO->GetMethodTable();
6834
6835     if (pMT->ContainsPointersOrCollectible())
6836     {
6837         if (cNumReferences == 0)
6838         {
6839             *pcNumReferences = 0;
6840             GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &CountContainedObjectRef, (void*)pcNumReferences);
6841         }
6842         else
6843         {
6844             ObjectRefOffsetTuple t;
6845             t.pCurObjRef = (Object*)references;
6846             t.pCurObjOffset = offsets;
6847
6848             GCHeapUtilities::GetGCHeap()->DiagWalkObject2(pBO, &SaveContainedObjectRef2, (void*)&t);
6849         }
6850     }
6851     else
6852     {
6853         *pcNumReferences = 0;
6854     }
6855
6856     return S_OK;
6857 }
6858
6859 /*
6860  * IsFrozenObject
6861  * 
6862  * Determines whether the object is in a read-only segment
6863  * 
6864  * Parameters:
6865  *      objectId        - object id of interest
6866  *
6867  * Returns:
6868  *   S_OK if successful
6869  *
6870  */
6871 HRESULT ProfToEEInterfaceImpl::IsFrozenObject(ObjectID objectId, BOOL *pbFrozen)
6872 {
6873     CONTRACTL
6874     {
6875         NOTHROW;
6876         GC_NOTRIGGER;
6877         MODE_ANY;
6878         EE_THREAD_NOT_REQUIRED;
6879         CANNOT_TAKE_LOCK;
6880     }
6881     CONTRACTL_END;
6882
6883     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6884         kP2EEAllowableAfterAttach,
6885         (LF_CORPROF,
6886         LL_INFO1000,
6887         "**PROF: IsFrozenObject 0x%p.\n",
6888         objectId));
6889
6890     *pbFrozen = GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)objectId) ? TRUE : FALSE;
6891
6892     return S_OK;
6893 }
6894
6895 /*
6896  * GetLOHObjectSizeThreshold
6897  * 
6898  * Gets the value of the configured LOH Threshold.
6899  * 
6900  * Parameters:
6901  *      pThreshold        - value of the threshold in bytes
6902  *
6903  * Returns:
6904  *   S_OK if successful
6905  *
6906  */
6907 HRESULT ProfToEEInterfaceImpl::GetLOHObjectSizeThreshold(DWORD *pThreshold)
6908 {
6909     CONTRACTL
6910     {
6911         NOTHROW;
6912         GC_NOTRIGGER;
6913         MODE_ANY;
6914         EE_THREAD_NOT_REQUIRED;
6915         CANNOT_TAKE_LOCK;
6916     }
6917     CONTRACTL_END;
6918
6919     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6920         kP2EEAllowableAfterAttach,
6921         (LF_CORPROF,
6922         LL_INFO1000,
6923         "**PROF: GetLOHObjectSizeThreshold\n"));
6924
6925     if (pThreshold == nullptr)
6926     {
6927         return E_INVALIDARG;
6928     }
6929
6930     *pThreshold = g_pConfig->GetGCLOHThreshold();
6931
6932     return S_OK;
6933 }
6934
6935 /*
6936  * GetStringLayout
6937  *
6938  * This function describes to a profiler the internal layout of a string.
6939  *
6940  * Parameters:
6941  *   pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
6942  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
6943  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
6944  *
6945  * Returns:
6946  *   S_OK if successful.
6947  */
6948 HRESULT ProfToEEInterfaceImpl::GetStringLayout(ULONG *pBufferLengthOffset,
6949                                              ULONG *pStringLengthOffset,
6950                                              ULONG *pBufferOffset)
6951 {
6952     CONTRACTL
6953     {
6954         // Yay!
6955         NOTHROW;
6956
6957         // Yay!
6958         GC_NOTRIGGER;
6959
6960         // Yay!
6961         MODE_ANY;
6962
6963         // Yay!
6964         EE_THREAD_NOT_REQUIRED;
6965
6966         // Yay!
6967         CANNOT_TAKE_LOCK;
6968
6969
6970         PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
6971         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
6972         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
6973     }
6974     CONTRACTL_END;
6975
6976     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
6977         (LF_CORPROF, 
6978         LL_INFO1000, 
6979         "**PROF: GetStringLayout.\n"));
6980
6981     return this->GetStringLayoutHelper(pBufferLengthOffset, pStringLengthOffset, pBufferOffset);
6982 }
6983
6984 /*
6985  * GetStringLayout2
6986  *
6987  * This function describes to a profiler the internal layout of a string.
6988  *
6989  * Parameters:
6990  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
6991  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
6992  *
6993  * Returns:
6994  *   S_OK if successful.
6995  */
6996 HRESULT ProfToEEInterfaceImpl::GetStringLayout2(ULONG *pStringLengthOffset,
6997                                              ULONG *pBufferOffset)
6998 {
6999     CONTRACTL
7000     {
7001         // Yay!
7002         NOTHROW;
7003
7004         // Yay!
7005         GC_NOTRIGGER;
7006
7007         // Yay!
7008         MODE_ANY;
7009
7010         // Yay!
7011         EE_THREAD_NOT_REQUIRED;
7012
7013         // Yay!
7014         CANNOT_TAKE_LOCK;
7015
7016
7017         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7018         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
7019     }
7020     CONTRACTL_END;
7021
7022     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7023         (LF_CORPROF, 
7024         LL_INFO1000, 
7025         "**PROF: GetStringLayout2.\n"));
7026
7027     ULONG dummyBufferLengthOffset;
7028     return this->GetStringLayoutHelper(&dummyBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7029 }
7030
7031 /*
7032  * GetStringLayoutHelper
7033  *
7034  * This function describes to a profiler the internal layout of a string.
7035  *
7036  * Parameters:
7037  *   pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7038  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7039  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7040  *
7041  * Returns:
7042  *   S_OK if successful.
7043  */
7044 HRESULT ProfToEEInterfaceImpl::GetStringLayoutHelper(ULONG *pBufferLengthOffset,
7045                                              ULONG *pStringLengthOffset,
7046                                              ULONG *pBufferOffset)
7047 {
7048     CONTRACTL
7049     {
7050         // Yay!
7051         NOTHROW;
7052
7053         // Yay!
7054         GC_NOTRIGGER;
7055
7056         // Yay!
7057         MODE_ANY;
7058
7059         // Yay!
7060         EE_THREAD_NOT_REQUIRED;
7061
7062         // Yay!
7063         CANNOT_TAKE_LOCK;
7064
7065
7066         PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7067         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7068         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
7069     }
7070     CONTRACTL_END;
7071
7072     // The String class no longer has a bufferLength field in it.
7073     // We are returning the offset of the stringLength because that is the closest we can get
7074     // This is most certainly a breaking change and a new method 
7075     // ICorProfilerInfo3::GetStringLayout2 has been added on the interface ICorProfilerInfo3
7076     if (pBufferLengthOffset != NULL)
7077     {
7078         *pBufferLengthOffset = StringObject::GetStringLengthOffset();
7079     }
7080
7081     if (pStringLengthOffset != NULL)
7082     {
7083         *pStringLengthOffset = StringObject::GetStringLengthOffset();
7084     }
7085
7086     if (pBufferOffset != NULL)
7087     {
7088         *pBufferOffset = StringObject::GetBufferOffset();
7089     }
7090
7091     return S_OK;
7092 }
7093
7094 /*
7095  * GetClassLayout
7096  *
7097  * This function describes to a profiler the internal layout of a class.
7098  *
7099  * Parameters:
7100  *   classID - The class that is being queried.  It is really a TypeHandle.
7101  *   rFieldOffset - An array to store information about each field in the class.
7102  *   cFieldOffset - Count of the number of elements in rFieldOffset.
7103  *   pcFieldOffset - Upon return contains the number of elements filled in, or if
7104  *         cFieldOffset is zero, the number of elements needed.
7105  *   pulClassSize - Optional parameter for containing the size in bytes of the underlying
7106  *         internal class structure.
7107  *
7108  * Returns:
7109  *   S_OK if successful.
7110  */
7111 HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID,
7112                                              COR_FIELD_OFFSET rFieldOffset[],
7113                                              ULONG cFieldOffset,
7114                                              ULONG *pcFieldOffset,
7115                                              ULONG *pulClassSize)
7116 {
7117     CONTRACTL
7118     {
7119         // Yay!
7120         NOTHROW;
7121
7122         // Yay!
7123         GC_NOTRIGGER;
7124
7125         // Yay!
7126         MODE_ANY;
7127
7128         // Yay!
7129         EE_THREAD_NOT_REQUIRED;
7130
7131         // Yay!
7132         CANNOT_TAKE_LOCK;
7133
7134
7135         PRECONDITION(CheckPointer(rFieldOffset, NULL_OK));
7136         PRECONDITION(CheckPointer(pcFieldOffset));
7137         PRECONDITION(CheckPointer(pulClassSize,  NULL_OK));
7138     }
7139     CONTRACTL_END;
7140     
7141     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7142         (LF_CORPROF, 
7143         LL_INFO1000, 
7144         "**PROF: GetClassLayout 0x%p.\n", 
7145         classID));
7146     
7147     //
7148     // Verify parameters
7149     //
7150     if ((pcFieldOffset == NULL) || (classID == NULL))
7151     {
7152          return E_INVALIDARG;
7153     }
7154
7155     if ((cFieldOffset != 0) && (rFieldOffset == NULL))
7156     {
7157         return E_INVALIDARG;
7158     }
7159
7160     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classID);
7161
7162     //
7163     // This is the incorrect API for arrays or strings.  Use GetArrayObjectInfo, and GetStringLayout
7164     //
7165     if (typeHandle.IsTypeDesc() || typeHandle.AsMethodTable()->IsArray())
7166     {
7167         return E_INVALIDARG;
7168     }
7169
7170     //
7171     // We used to have a bug where this API incorrectly succeeded for strings during startup. Profilers
7172     // took dependency on this bug. Let the API to succeed for strings during startup for backward compatibility.
7173     //
7174     if (typeHandle.AsMethodTable()->IsString() && g_profControlBlock.fBaseSystemClassesLoaded)
7175     {
7176         return E_INVALIDARG;
7177     }
7178
7179     //
7180     // If this class is not fully restored, that is all the information we can get at this time.
7181     //
7182     if (!typeHandle.IsRestored())
7183     {
7184         return CORPROF_E_DATAINCOMPLETE;
7185     }
7186
7187     // Types can be pre-restored, but they still aren't expected to handle queries before
7188     // eager fixups have run. This is a targetted band-aid for a bug intellitrace was
7189     // running into - attempting to get the class layout for all types at module load time.
7190     // If we don't detect this the runtime will AV during the field iteration below. Feel
7191     // free to eliminate this check when a more complete solution is available.
7192     if (MethodTable::IsParentMethodTableTagged(typeHandle.AsMethodTable()))
7193     {
7194         return CORPROF_E_DATAINCOMPLETE;
7195     }
7196
7197     // !IsValueType = IsArray || IsReferenceType   Since IsArry has been ruled out above, it must 
7198     // be a reference type if !IsValueType.
7199     BOOL fReferenceType = !typeHandle.IsValueType();
7200
7201     //
7202     // Fill in class size now
7203     //
7204     // Move after the check for typeHandle.GetMethodTable()->IsRestored() 
7205     // because an unrestored MethodTable may have a bad EE class pointer
7206     // which will be used by MethodTable::GetNumInstanceFieldBytes
7207     //
7208     if (pulClassSize != NULL)
7209     {
7210         if (fReferenceType)
7211         {
7212             // aligned size including the object header for reference types
7213             *pulClassSize = typeHandle.GetMethodTable()->GetBaseSize();
7214         }
7215         else
7216         {
7217             // unboxed and unaligned size for value types
7218             *pulClassSize = typeHandle.GetMethodTable()->GetNumInstanceFieldBytes();
7219         }
7220     }
7221
7222     ApproxFieldDescIterator fieldDescIterator(typeHandle.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
7223
7224     ULONG cFields = fieldDescIterator.Count();
7225
7226     //
7227     // If they are looking to just get the count, return that.
7228     //
7229     if ((cFieldOffset == 0)  || (rFieldOffset == NULL))
7230     {
7231         *pcFieldOffset = cFields;
7232         return S_OK;
7233     }
7234
7235     //
7236     // Dont put too many in the array.
7237     //
7238     if (cFields > cFieldOffset)
7239     {
7240         cFields = cFieldOffset;
7241     }
7242
7243     *pcFieldOffset = cFields;
7244
7245     //
7246     // Now fill in the array
7247     //
7248     ULONG i;
7249     FieldDesc *pField;
7250
7251     for (i = 0; i < cFields; i++)
7252     {
7253         pField = fieldDescIterator.Next();
7254         rFieldOffset[i].ridOfField = (ULONG)pField->GetMemberDef();
7255         rFieldOffset[i].ulOffset = (ULONG)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
7256     }
7257
7258     return S_OK;
7259 }
7260
7261
7262 typedef struct _PROFILER_STACK_WALK_DATA
7263 {
7264     StackSnapshotCallback *callback;
7265     ULONG32 infoFlags;
7266     ULONG32 contextFlags;
7267     void *clientData;
7268     
7269 #ifdef WIN64EXCEPTIONS
7270     StackFrame sfParent;
7271 #endif
7272 } PROFILER_STACK_WALK_DATA;
7273
7274
7275 /*
7276  * ProfilerStackWalkCallback
7277  *
7278  * This routine is used as the callback from the general stack walker for
7279  * doing snapshot stack walks
7280  *
7281  */
7282 StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_DATA *pData)
7283 {
7284     CONTRACTL
7285     {
7286         NOTHROW;  // throw is RIGHT out... the throw at minimum allocates the thrown object which we *must* not do
7287         GC_NOTRIGGER; // the stack is not necessarily crawlable at this state !!!) we must not induce a GC 
7288     } 
7289     CONTRACTL_END;
7290
7291     MethodDesc *pFunc = pCf->GetFunction();
7292
7293     COR_PRF_FRAME_INFO_INTERNAL frameInfo;
7294     ULONG32 contextSize = 0;
7295     BYTE *context = NULL;
7296
7297     UINT_PTR currentIP = 0;
7298     REGDISPLAY *pRegDisplay = pCf->GetRegisterSet();
7299 #if defined(_TARGET_X86_)
7300     CONTEXT builtContext;
7301 #endif
7302
7303     //
7304     // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want
7305     // to return to the profiler as the context seed if it wants to walk the unmanaged
7306     // stack frame, so we report the functionId as NULL to indicate this.
7307     //
7308     if (pCf->IsNativeMarker())
7309     {
7310         pFunc = NULL;
7311     }
7312
7313     //
7314     // Skip all Lightweight reflection/emit functions
7315     //
7316     if ((pFunc != NULL) && pFunc->IsNoMetadata())
7317     {
7318         return SWA_CONTINUE;
7319     }
7320
7321     //
7322     // If this is not a transition of any sort and not a managed
7323     // method, ignore it.
7324     //
7325     if (!pCf->IsNativeMarker() && !pCf->IsFrameless())
7326     {
7327         return SWA_CONTINUE;
7328     }
7329
7330     currentIP = (UINT_PTR)pRegDisplay->ControlPC;
7331
7332     frameInfo.size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
7333     frameInfo.version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
7334
7335     if (pFunc != NULL)
7336     {
7337         frameInfo.funcID = MethodDescToFunctionID(pFunc);
7338         frameInfo.extraArg = NULL;
7339     }
7340     else
7341     {
7342         frameInfo.funcID = NULL;
7343         frameInfo.extraArg = NULL;
7344     }
7345
7346     frameInfo.IP = currentIP;
7347     frameInfo.thisArg = NULL;
7348
7349     if (pData->infoFlags & COR_PRF_SNAPSHOT_REGISTER_CONTEXT)
7350     {
7351 #if defined(_TARGET_X86_)
7352         //
7353         // X86 stack walking does not keep the context up-to-date during the
7354         // walk.  Instead it keeps the REGDISPLAY up-to-date.  Thus, we need to
7355         // build a CONTEXT from the REGDISPLAY.
7356         //
7357
7358         memset(&builtContext, 0, sizeof(builtContext));
7359         builtContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
7360         CopyRegDisplay(pRegDisplay, NULL, &builtContext);
7361         context = (BYTE *)(&builtContext);
7362 #else
7363         context = (BYTE *)pRegDisplay->pCurrentContext;
7364 #endif
7365         contextSize = sizeof(CONTEXT);
7366     }
7367     
7368     // NOTE:  We are intentionally not setting any callback state flags here (i.e., not using
7369     // SetCallbackStateFlagsHolder), as we want the DSS callback to "inherit" the
7370     // same callback state that DSS has:  if DSS was called asynchronously, then consider
7371     // the DSS callback to be called asynchronously.
7372     if (pData->callback(frameInfo.funcID,
7373                         frameInfo.IP,
7374                         (COR_PRF_FRAME_INFO)&frameInfo,
7375                         contextSize,
7376                         context,
7377                         pData->clientData) == S_OK)
7378     {
7379         return SWA_CONTINUE;
7380     }
7381
7382     return SWA_ABORT;
7383 }
7384
7385 #ifdef _TARGET_X86_
7386
7387 //---------------------------------------------------------------------------------------
7388 // Normally, calling GetFunction() on the frame is sufficient to ensure
7389 // HelperMethodFrames are intialized. However, sometimes we need to be able to specify
7390 // that we should not enter the host while initializing, so we need to initialize such
7391 // frames more directly. This small helper function directly forces the initialization,
7392 // and ensures we don't enter the host as a result if we're executing in an asynchronous
7393 // call (i.e., hijacked thread)
7394 //
7395 // Arguments:
7396 //      pFrame - Frame to initialize.
7397 //
7398 // Return Value:
7399 //     TRUE iff pFrame was successfully initialized (or was already initialized). If
7400 //     pFrame is not a HelperMethodFrame (or derived type), this returns TRUE
7401 //     immediately. FALSE indicates we tried to initialize w/out entering the host, and
7402 //     had to abort as a result when a reader lock was needed but unavailable.
7403 //
7404
7405 static BOOL EnsureFrameInitialized(Frame * pFrame)
7406 {
7407     CONTRACTL
7408     {
7409         NOTHROW;
7410         GC_NOTRIGGER;
7411
7412         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7413         // host (SQL).  Corners will be cut to ensure this is the case
7414         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7415
7416         SUPPORTS_DAC;
7417     }
7418     CONTRACTL_END;
7419
7420     if (pFrame->GetFrameType() != Frame::TYPE_HELPER_METHOD_FRAME)
7421     {
7422         // This frame is not a HelperMethodFrame or a frame derived from
7423         // HelperMethodFrame, so HMF-specific lazy initialization is not an issue.
7424         return TRUE;
7425     }
7426
7427     HelperMethodFrame * pHMF = (HelperMethodFrame *) pFrame;
7428
7429     if (pHMF->InsureInit(
7430         false,                      // initialInit
7431         NULL,                       // unwindState
7432         (ShouldAvoidHostCalls() ?
7433             NoHostCalls :
7434             AllowHostCalls)
7435         ) != NULL)
7436     {
7437         // InsureInit() succeeded and found the return address
7438         return TRUE;
7439     }
7440
7441     // No return address was found. It must be because we asked InsureInit() to bail if
7442     // it would have entered the host
7443     _ASSERTE(ShouldAvoidHostCalls());
7444     return FALSE;
7445 }
7446
7447 //---------------------------------------------------------------------------------------
7448 //
7449 // Implements the COR_PRF_SNAPSHOT_X86_OPTIMIZED algorithm called by DoStackSnapshot. 
7450 // Does a simple EBP walk, rather than invoking all of StackWalkFramesEx.
7451 //
7452 // Arguments:
7453 //      pThreadToSnapshot - Thread whose stack should be walked
7454 //      pctxSeed - Register context with which to seed the walk
7455 //      callback - Function to call at each frame found during the walk
7456 //      clientData - Parameter to pass through to callback
7457 //
7458 // Return Value:
7459 //     HRESULT indicating success or failure.
7460 //
7461
7462 HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
7463     Thread * pThreadToSnapshot, 
7464     LPCONTEXT pctxSeed, 
7465     StackSnapshotCallback * callback, 
7466     void * clientData)
7467 {
7468     CONTRACTL
7469     {
7470         GC_NOTRIGGER;
7471         NOTHROW;
7472         MODE_ANY;
7473         EE_THREAD_NOT_REQUIRED;
7474
7475         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7476         // host (SQL).  Corners will be cut to ensure this is the case
7477         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7478     }
7479     CONTRACTL_END;
7480
7481     HRESULT hr;
7482
7483     // We haven't set the stackwalker thread type flag yet (see next line), so it shouldn't be set. Only
7484     // exception to this is if the current call is made by a hijacking profiler which
7485     // redirected this thread while it was previously in the middle of another stack walk
7486     _ASSERTE(IsCalledAsynchronously() || !IsStackWalkerThread());
7487
7488     // Remember that we're walking the stack.  This holder will reinstate the original
7489     // value of the stackwalker flag (from the thread type mask) in its destructor.
7490     ClrFlsValueSwitch _threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThreadToSnapshot);
7491    
7492     // This flag remembers if we reported a managed frame since the last unmanaged block
7493     // we reported. It's used to avoid reporting two unmanaged blocks in a row.
7494     BOOL fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7495
7496     Frame * pFrameCur = pThreadToSnapshot->GetFrame();
7497
7498     CONTEXT ctxCur;
7499     ZeroMemory(&ctxCur, sizeof(ctxCur));
7500
7501     // Use seed if we got one.  Otherwise, EE explicit Frame chain will seed the walk.
7502     if (pctxSeed != NULL)
7503     {
7504         ctxCur.Ebp = pctxSeed->Ebp;
7505         ctxCur.Eip = pctxSeed->Eip;
7506         ctxCur.Esp = pctxSeed->Esp;
7507     }
7508
7509     while (TRUE)
7510     {
7511         // At each iteration of the loop:
7512         //     * Analyze current frame (get managed data if it's a managed frame)
7513         //     * Report current frame via callback()
7514         //     * Walk down to next frame
7515         
7516         // **** Managed or unmanaged frame? ****
7517         
7518         EECodeInfo codeInfo;
7519         MethodDesc * pMethodDescCur = NULL;
7520
7521         if (ctxCur.Eip != 0)
7522         {
7523             hr = GetFunctionInfoInternal(
7524                 (LPCBYTE) ctxCur.Eip, 
7525                 &codeInfo);
7526             if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
7527             {
7528                 _ASSERTE(ShouldAvoidHostCalls());
7529                 return hr;
7530             }
7531             if (SUCCEEDED(hr))
7532             {
7533                 pMethodDescCur = codeInfo.GetMethodDesc();
7534             }
7535         }
7536
7537         // **** Report frame to profiler ****
7538
7539         if (
7540             // Make sure the frame gave us an IP
7541             (ctxCur.Eip != 0) &&              
7542
7543             // Make sure any managed frame isn't for an IL stub or LCG
7544             ((pMethodDescCur == NULL) || !pMethodDescCur->IsNoMetadata()) &&
7545
7546             // Only report unmanaged frames if the last frame we reported was managed
7547             // (avoid reporting two unmanaged blocks in a row)
7548             ((pMethodDescCur != NULL) || fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock))
7549         {
7550             // Around the call to the profiler, temporarily clear the
7551             // ThreadType_StackWalker type flag, as we have no control over what the
7552             // profiler may do inside its callback (it could theoretically attempt to
7553             // load other types, though I don't personally know of profilers that
7554             // currently do this).
7555             
7556             CLEAR_THREAD_TYPE_STACKWALKER();
7557             hr = callback(
7558                 (FunctionID) pMethodDescCur, 
7559                 ctxCur.Eip, 
7560                 NULL,               // COR_PRF_FRAME_INFO
7561                 sizeof(ctxCur),     // contextSize,
7562                 (LPBYTE) &ctxCur,   // context,
7563                 clientData);
7564             SET_THREAD_TYPE_STACKWALKER(pThreadToSnapshot);
7565             
7566             if (hr != S_OK)
7567             {
7568                 return hr;
7569             }
7570             if (pMethodDescCur == NULL)
7571             {
7572                 // Just reported an unmanaged block, so reset the flag
7573                 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7574             }
7575             else
7576             {
7577                 // Just reported a managed block, so remember it
7578                 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = TRUE;
7579             }
7580         }
7581
7582         // **** Walk down to next frame ****
7583
7584         // Is current frame managed or unmanaged?
7585         if (pMethodDescCur == NULL)
7586         {
7587             // Unmanaged frame.  Use explicit EE Frame chain to help
7588
7589             REGDISPLAY frameRD;
7590             ZeroMemory(&frameRD, sizeof(frameRD));
7591
7592             while (pFrameCur != FRAME_TOP)
7593             {
7594                 // Frame is only useful if it will contain register context info
7595                 if (!pFrameCur->NeedsUpdateRegDisplay())
7596                 {
7597                     goto Loop;
7598                 }
7599
7600
7601                 // This should be the first call we make to the Frame, as it will
7602                 // ensure we force lazy initialize of HelperMethodFrames
7603                 if (!EnsureFrameInitialized(pFrameCur))
7604                 {
7605                     return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7606                 }
7607                     
7608                 // This frame is only useful if it gives us an actual return address,
7609                 // and is situated on the stack at or below our current ESP (stack
7610                 // grows up)
7611                 if ((pFrameCur->GetReturnAddress() != NULL) &&
7612                     (dac_cast<TADDR>(pFrameCur) >= dac_cast<TADDR>(ctxCur.Esp)))
7613                 {
7614                     pFrameCur->UpdateRegDisplay(&frameRD);
7615                     break;
7616                 }
7617
7618 Loop:
7619                 pFrameCur = pFrameCur->PtrNextFrame();
7620             }
7621
7622             if (pFrameCur == FRAME_TOP)
7623             {
7624                 // No more frames.  Stackwalk is over
7625                 return S_OK;
7626             }
7627
7628             // Update ctxCur based on frame
7629             ctxCur.Eip = pFrameCur->GetReturnAddress();
7630             ctxCur.Ebp = GetRegdisplayFP(&frameRD);
7631             ctxCur.Esp = GetRegdisplaySP(&frameRD);
7632         }
7633         else
7634         {
7635             // Managed frame.
7636
7637             // GC info will assist us in determining whether this is a non-EBP frame and
7638             // info about pushed arguments.
7639             GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
7640             PTR_VOID gcInfo = gcInfoToken.Info;
7641             InfoHdr header;
7642             unsigned uiMethodSizeDummy;
7643             PTR_CBYTE table = PTR_CBYTE(gcInfo);
7644             table += decodeUnsigned(table, &uiMethodSizeDummy);
7645             table = decodeHeader(table, gcInfoToken.Version, &header);
7646
7647             // Ok, GCInfo, can we do a simple EBP walk or what?
7648
7649             if ((codeInfo.GetRelOffset() < header.prologSize) || 
7650                 (!header.ebpFrame && !header.doubleAlign))
7651             {
7652                 // We're either in the prolog or we're not in an EBP frame, in which case
7653                 // we'll just defer to the code manager to unwind for us. This condition
7654                 // is relatively rare, but can occur if:
7655                 // 
7656                 //     * The profiler did a DSS from its Enter hook, in which case we're
7657                 //         still inside the prolog, OR
7658                 //     * The seed context or explicit EE Frame chain seeded us with a
7659                 //         non-EBP frame function. In this case, using a naive EBP
7660                 //         unwinding algorithm would actually skip over the next EBP
7661                 //         frame, and would get SP all wrong as we try skipping over
7662                 //         the pushed parameters. So let's just ask the code manager for
7663                 //         help.
7664                 // 
7665                 // Note that there are yet more conditions (much more rare) where the EBP
7666                 // walk could get lost (e.g., we're inside an epilog). But we only care
7667                 // about the most likely cases, and it's ok if the unlikely cases result
7668                 // in truncated stacks, as unlikely cases will be statistically
7669                 // irrelevant to CPU performance sampling profilers
7670                 CodeManState codeManState;
7671                 codeManState.dwIsSet = 0;
7672                 REGDISPLAY rd;
7673                 ZeroMemory(&rd, sizeof(rd));
7674
7675                 rd.SetEbpLocation(&ctxCur.Ebp);
7676                 rd.SP = ctxCur.Esp;
7677                 rd.ControlPC = ctxCur.Eip;
7678
7679                 codeInfo.GetCodeManager()->UnwindStackFrame(
7680                     &rd, 
7681                     &codeInfo, 
7682                     SpeculativeStackwalk, 
7683                     &codeManState, 
7684                     NULL);
7685
7686                 ctxCur.Ebp = *rd.GetEbpLocation();
7687                 ctxCur.Esp = rd.SP;
7688                 ctxCur.Eip = rd.ControlPC;
7689             }
7690             else
7691             {
7692                 // We're in an actual EBP frame, so we can simplistically walk down to
7693                 // the next frame using EBP.
7694                 
7695                 // Return address is stored just below saved EBP (stack grows up)
7696                 ctxCur.Eip = *(DWORD *) (ctxCur.Ebp + sizeof(DWORD));
7697                 
7698                 ctxCur.Esp = 
7699                     // Stack location where current function pushed its EBP
7700                     ctxCur.Ebp +
7701
7702                     // Skip past that EBP
7703                     sizeof(DWORD) +
7704                     
7705                     // Skip past return address pushed by caller
7706                     sizeof(DWORD) + 
7707                     
7708                     // Skip past arguments to current function that were pushed by caller. 
7709                     // (Caller will pop varargs, so don't count those.)
7710                     (header.varargs ? 0 : (header.argCount * sizeof(DWORD)));
7711
7712                 // EBP for frame below us (stack grows up) has been saved onto our own
7713                 // frame. Dereference it now.
7714                 ctxCur.Ebp = *(DWORD *) ctxCur.Ebp;
7715             }
7716         }
7717     }
7718 }
7719 #endif // _TARGET_X86_
7720
7721 //*****************************************************************************
7722 //  The profiler stackwalk Wrapper
7723 //*****************************************************************************
7724 HRESULT ProfToEEInterfaceImpl::ProfilerStackWalkFramesWrapper(Thread * pThreadToSnapshot, PROFILER_STACK_WALK_DATA * pData, unsigned flags)
7725 {
7726     STATIC_CONTRACT_WRAPPER;
7727
7728     StackWalkAction swaRet = pThreadToSnapshot->StackWalkFrames(
7729         (PSTACKWALKFRAMESCALLBACK)ProfilerStackWalkCallback,
7730          pData,
7731          flags,
7732          NULL);
7733
7734     switch (swaRet)
7735     {
7736     default:
7737         _ASSERTE(!"Unexpected StackWalkAction returned from Thread::StackWalkFrames");
7738         return E_FAIL;
7739         
7740     case SWA_FAILED:
7741         return E_FAIL;
7742         
7743     case SWA_ABORT:
7744         return CORPROF_E_STACKSNAPSHOT_ABORTED;
7745
7746     case SWA_DONE:
7747         return S_OK;
7748     }
7749 }
7750
7751 //---------------------------------------------------------------------------------------
7752 //
7753 // DoStackSnapshot helper to call FindJitMan to determine if the specified
7754 // context is in managed code.
7755 //
7756 // Arguments:
7757 //      pCtx - Context to look at
7758 //      hostCallPreference - Describes how to acquire the reader lock--either AllowHostCalls
7759 //          or NoHostCalls (see code:HostCallPreference).
7760 //
7761 // Return Value:
7762 //      S_OK: The context is in managed code
7763 //      S_FALSE: The context is not in managed code.
7764 //      Error: Unable to determine (typically because hostCallPreference was NoHostCalls
7765 //         and the reader lock was unattainable without yielding)
7766 //
7767
7768 HRESULT IsContextInManagedCode(const CONTEXT * pCtx, HostCallPreference hostCallPreference)
7769 {
7770     WRAPPER_NO_CONTRACT;
7771     BOOL fFailedReaderLock = FALSE;
7772
7773     // if there's no Jit Manager for the IP, it's not managed code.
7774     BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(pCtx), hostCallPreference, &fFailedReaderLock);
7775     if (fFailedReaderLock)
7776     {
7777         return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7778     }
7779     
7780     return fIsManagedCode ? S_OK : S_FALSE;
7781 }
7782
7783 //*****************************************************************************
7784 // Perform a stack walk, calling back to callback at each managed frame.
7785 //*****************************************************************************
7786 HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread,
7787                                               StackSnapshotCallback *callback,
7788                                               ULONG32 infoFlags,
7789                                               void *clientData,
7790                                                BYTE * pbContext,
7791                                               ULONG32 contextSize)
7792 {
7793
7794 #if !defined(FEATURE_HIJACK)
7795
7796     // DoStackSnapshot needs Thread::Suspend/ResumeThread functionality.
7797     // On platforms w/o support for these APIs return E_NOTIMPL.
7798     return E_NOTIMPL;
7799
7800 #else // !defined(FEATURE_HIJACK)
7801
7802     CONTRACTL
7803     {
7804         // Yay!  (Note: NOTHROW is vital.  The throw at minimum allocates
7805         // the thrown object which we *must* not do.)
7806         NOTHROW;
7807
7808         // Yay!  (Note: this is called asynchronously to view the stack at arbitrary times,
7809         // so the stack is not necessarily crawlable for GC at this state!)
7810         GC_NOTRIGGER;
7811
7812         // Yay!
7813         MODE_ANY;
7814
7815         // Yay!
7816         EE_THREAD_NOT_REQUIRED;
7817
7818         // #DisableLockOnAsyncCalls
7819         // This call is allowed asynchronously, however it does take locks.  Therefore,
7820         // we will hit contract asserts if we happen to be in a CANNOT_TAKE_LOCK zone when
7821         // a hijacking profiler hijacks this thread to run DoStackSnapshot.  CANNOT_RETAKE_LOCK
7822         // is a more granular locking contract that says "I promise that if I take locks, I 
7823         // won't reenter any locks that were taken before this function was called".  
7824         DISABLED(CAN_TAKE_LOCK);
7825
7826         // Asynchronous functions can be called at arbitrary times when runtime 
7827         // is holding locks that cannot be reentered without causing deadlock.
7828         // This contract detects any attempts to reenter locks held at the time 
7829         // this function was called.  
7830         CANNOT_RETAKE_LOCK;
7831
7832     }
7833     CONTRACTL_END;
7834
7835     // This CONTRACT_VIOLATION is still needed because DISABLED(CAN_TAKE_LOCK) does not 
7836     // turn off contract violations.
7837     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
7838
7839     LPCONTEXT pctxSeed = reinterpret_cast<LPCONTEXT> (pbContext);
7840
7841     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7842         (LF_CORPROF, 
7843         LL_INFO1000, 
7844         "**PROF: DoStackSnapshot 0x%p, 0x%p, 0x%08x, 0x%p, 0x%p, 0x%08x.\n", 
7845         thread, 
7846         callback, 
7847         infoFlags, 
7848         clientData, 
7849         pctxSeed, 
7850         contextSize));
7851    
7852     HRESULT hr = E_UNEXPECTED;
7853     // (hr assignment is to appease the compiler; we won't actually return without explicitly setting hr again)
7854     
7855     Thread *pThreadToSnapshot = NULL;
7856     Thread * pCurrentThread = GetThreadNULLOk();
7857     BOOL fResumeThread = FALSE;
7858     INDEBUG(ULONG ulForbidTypeLoad = 0;)
7859     BOOL fResetSnapshotThreadExternalCount = FALSE;
7860     int cRefsSnapshotThread = 0;
7861     
7862     // Remember whether we've already determined the current context of the target thread
7863     // is in managed (S_OK), not in managed (S_FALSE), or unknown (error).
7864     HRESULT hrCurrentContextIsManaged = E_FAIL;
7865
7866     CONTEXT ctxCurrent;
7867     memset(&ctxCurrent, 0, sizeof(ctxCurrent));
7868
7869     REGDISPLAY rd;
7870
7871     PROFILER_STACK_WALK_DATA data;
7872
7873     if (!g_fEEStarted )
7874     {
7875         // no managed code has run and things are likely in a very bad have loaded state
7876         // this is a bad time to try to walk the stack
7877         
7878         // Returning directly as there is nothing to cleanup yet
7879         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7880     }
7881
7882     if (!CORProfilerStackSnapshotEnabled())
7883     {
7884         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7885         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
7886     }
7887
7888     if (thread == NULL)
7889     {
7890         pThreadToSnapshot = pCurrentThread;
7891     }
7892     else
7893     {
7894         pThreadToSnapshot = (Thread *)thread;
7895     }
7896
7897 #ifdef _TARGET_X86_
7898     if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT | COR_PRF_SNAPSHOT_X86_OPTIMIZED)) != 0)
7899 #else
7900     if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT)) != 0)
7901 #endif
7902     {
7903         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7904         return E_INVALIDARG;
7905     }
7906
7907     if (!IsManagedThread(pThreadToSnapshot) || !IsGarbageCollectorFullyInitialized())
7908     {
7909         //
7910         // No managed frames, return now.
7911         //
7912         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7913         return S_OK;
7914     }
7915
7916     // We must make sure no other thread tries to hijack the thread we're about to walk
7917     // Hijacking means Thread::HijackThread, i.e. bashing return addresses which would break the stack walk
7918     Thread::HijackLockHolder hijackLockHolder(pThreadToSnapshot);
7919     if (!hijackLockHolder.Acquired())
7920     {
7921         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7922         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7923     }
7924
7925     if (pThreadToSnapshot != pCurrentThread         // Walking separate thread
7926         && pCurrentThread != NULL                         // Walker (current) thread is a managed / VM thread
7927         && ThreadSuspend::SysIsSuspendInProgress())          // EE is trying suspend itself
7928     {
7929         // Since we're walking a separate thread, we'd have to suspend it first (see below).
7930         // And since the current thread is a VM thread, that means the current thread's
7931         // m_dwForbidSuspendThread count will go up while it's trying to suspend the
7932         // target thread (see Thread::SuspendThread).  THAT means no one will be able
7933         // to suspend the current thread until its m_dwForbidSuspendThread is decremented
7934         // (which happens as soon as the target thread of DoStackSnapshot has been suspended).
7935         // Since we're in the process of suspending the entire runtime, now would be a bad time to
7936         // make the walker thread un-suspendable (see VsWhidbey bug 454936).  So let's just abort
7937         // now.  Note that there is no synchronization around calling Thread::SysIsSuspendInProgress().
7938         // So we will get occasional false positives or false negatives.  But that's benign, as the worst
7939         // that might happen is we might occasionally delay the EE suspension a little bit, or we might
7940         // too eagerly fail from ProfToEEInterfaceImpl::DoStackSnapshot sometimes.  But there won't
7941         // be any corruption or AV.  
7942         //
7943         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7944         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7945     }
7946
7947     // We only allow stackwalking if:
7948     // 1) Target thread to walk == current thread OR Target thread is suspended, AND
7949     // 2) Target thread to walk is currently executing JITted / NGENd code, AND
7950     // 3) Target thread to walk is seeded OR currently NOT unwinding the stack, AND
7951     // 4) Target thread to walk != current thread OR current thread is NOT in a can't stop or forbid suspend region
7952
7953     // If the thread is in a forbid suspend region, it's dangerous to do anything:
7954     // - The code manager datastructures accessed during the stackwalk may be in inconsistent state.
7955     // - Thread::Suspend won't be able to suspend the thread.
7956     if (pThreadToSnapshot->IsInForbidSuspendRegion())
7957     {
7958         hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
7959         goto Cleanup;
7960     }
7961
7962     HostCallPreference hostCallPreference;
7963     
7964     // First, check "1) Target thread to walk == current thread OR Target thread is suspended"
7965     if (pThreadToSnapshot != pCurrentThread)
7966     {
7967 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
7968         hr = E_NOTIMPL;
7969         goto Cleanup;
7970 #else
7971         // Walking separate thread, so it must be suspended.  First, ensure that
7972         // target thread exists.
7973         //
7974         // NOTE: We're using the "dangerous" variant of this refcount function, because we
7975         // rely on the profiler to ensure it never tries to walk a thread being destroyed.
7976         // (Profiler must block in its ThreadDestroyed() callback until all uses of that thread,
7977         // such as walking its stack, are complete.)
7978         cRefsSnapshotThread = pThreadToSnapshot->IncExternalCountDANGEROUSProfilerOnly();
7979         fResetSnapshotThreadExternalCount = TRUE;
7980
7981         if (cRefsSnapshotThread == 1 || !pThreadToSnapshot->HasValidThreadHandle())
7982         {
7983             // At this point, we've modified the VM state based on bad input
7984             // (pThreadToSnapshot) from the profiler.  This could cause
7985             // memory corruption and leave us vulnerable to security problems.
7986             // So destroy the process.
7987             _ASSERTE(!"Profiler trying to walk destroyed thread");
7988             EEPOLICY_HANDLE_FATAL_ERROR(CORPROF_E_STACKSNAPSHOT_INVALID_TGT_THREAD);
7989         }
7990
7991         // Thread::SuspendThread() ensures that no one else should try to suspend us
7992         // while we're suspending pThreadToSnapshot.
7993         //
7994         // TRUE: OneTryOnly.  Don't loop waiting for others to get out of our way in
7995         // order to suspend the thread.  If it's not safe, just return an error immediately.
7996         Thread::SuspendThreadResult str = pThreadToSnapshot->SuspendThread(TRUE);
7997         if (str == Thread::STR_Success)
7998         {
7999             fResumeThread = TRUE;
8000         }
8001         else
8002         {
8003             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8004             goto Cleanup;            
8005         }
8006 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8007     }
8008
8009     hostCallPreference =
8010         ShouldAvoidHostCalls() ?
8011             NoHostCalls :       // Async call: Ensure this thread won't yield & re-enter host
8012             AllowHostCalls;     // Synchronous calls may re-enter host just fine
8013
8014     // If target thread is in pre-emptive mode, the profiler's seed context is unnecessary
8015     // because our frame chain is good enough: it will give us at least as accurate a
8016     // starting point as the profiler could.  Also, since profiler contexts cannot be
8017     // trusted, we don't want to set the thread's profiler filter context to this, as a GC
8018     // that interrupts the profiler's stackwalk will end up using the profiler's (potentially
8019     // bogus) filter context.
8020     if (!pThreadToSnapshot->PreemptiveGCDisabledOther())
8021     {
8022         // Thread to be walked is in preemptive mode.  Throw out seed.
8023         pctxSeed = NULL;
8024     }
8025     else if (pThreadToSnapshot != pCurrentThread)
8026     {
8027     // With cross-thread stack-walks, the target thread's context could be unreliable.
8028     // That would shed doubt on either a profiler-provided context, or a default
8029     // context we chose.  So check if we're in a potentially unreliable case, and return
8030     // an error if so.
8031     // 
8032     // These heurisitics are based on an actual bug where GetThreadContext returned a
8033     // self-consistent, but stale, context for a thread suspended after being redirected by
8034     // the GC (TFS Dev 10 bug # 733263).
8035         //
8036         // (Note that this whole block is skipped if pThreadToSnapshot is in preemptive mode (the IF
8037         // above), as the context is unused in such a case--the EE Frame chain is used
8038         // to seed the walk instead.)
8039 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8040         hr = E_NOTIMPL;
8041         goto Cleanup;
8042 #else
8043         if (!pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8044         {
8045             LOG((LF_CORPROF, LL_INFO100, "**PROF: GetSafelyRedirectableThreadContext failure leads to CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8046             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8047             goto Cleanup;
8048         }
8049
8050         hrCurrentContextIsManaged = IsContextInManagedCode(&ctxCurrent, hostCallPreference);
8051         if (FAILED(hrCurrentContextIsManaged))
8052         {
8053             // Couldn't get the info.  Try again later
8054             _ASSERTE(ShouldAvoidHostCalls());
8055             hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8056             goto Cleanup;
8057         }
8058
8059         if ((hrCurrentContextIsManaged == S_OK) &&
8060             (!pThreadToSnapshot->PreemptiveGCDisabledOther()))
8061         {
8062             // Thread is in preemptive mode while executing managed code?!  This lie is
8063             // an early warning sign that the context is bogus.  Bail.
8064             LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus.  Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8065             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8066             goto Cleanup;
8067         }
8068
8069         Frame * pFrame = pThreadToSnapshot->GetFrame();
8070         if (pFrame != FRAME_TOP)
8071         {
8072             TADDR spTargetThread = GetSP(&ctxCurrent);
8073             if (dac_cast<TADDR>(pFrame) < spTargetThread)
8074             {
8075                 // An Explicit EE Frame is more recent on the stack than the current
8076                 // stack pointer itself?  This lie is an early warning sign that the
8077                 // context is bogus. Bail.
8078                 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus.  Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8079                 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8080                 goto Cleanup;
8081             }
8082         }
8083
8084         // If the profiler did not specify a seed context of its own, use the current one we
8085         // just produced.
8086         //            
8087         // Failing to seed the walk can cause us to to "miss" functions on the stack.  This is
8088         // because StackWalkFrames(), when doing an unseeded stackwalk, sets the
8089         // starting regdisplay's IP/SP to 0.  This, in turn causes StackWalkFramesEx
8090         // to set cf.isFrameless = (pEEJM != NULL); (which is FALSE, since we have no
8091         // jit manager, since we have no IP).  Once frameless is false, we look solely to
8092         // the Frame chain for our goodies, rather than looking at the code actually
8093         // being executed by the thread.  The problem with the frame chain is that some
8094         // frames (e.g., GCFrame) don't point to any functions being executed.  So
8095         // StackWalkFramesEx just skips such frames and moves to the next one.  That
8096         // can cause a chunk of calls to be skipped.  To prevent this from happening, we
8097         // "fake" a seed by just seeding the thread with its current context.  This forces
8098         // StackWalkFramesEx() to look at the IP rather than just the frame chain.
8099         if (pctxSeed == NULL)
8100         {
8101             pctxSeed = &ctxCurrent;
8102         }
8103 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8104     }
8105
8106     // Second, check "2) Target thread to walk is currently executing JITted / NGENd code"
8107     // To do this, we need to find the proper context to investigate.  Start with
8108     // the seeded context, if available.  If not, use the target thread's current context.
8109     if (pctxSeed != NULL)
8110     {
8111         BOOL fSeedIsManaged;
8112
8113         // Short cut: If we're just using the current context as the seed, we may
8114         // already have determined whether it's in managed code.  If so, just use that
8115         // result rather than calculating it again
8116         if ((pctxSeed == &ctxCurrent) && SUCCEEDED(hrCurrentContextIsManaged))
8117         {
8118             fSeedIsManaged = (hrCurrentContextIsManaged == S_OK);
8119         }
8120         else
8121         {
8122             hr = IsContextInManagedCode(pctxSeed, hostCallPreference);
8123             if (FAILED(hr))
8124             {
8125                 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8126                 goto Cleanup;
8127             }
8128             fSeedIsManaged = (hr == S_OK);
8129         }
8130
8131         if (!fSeedIsManaged)
8132         {
8133             hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8134             goto Cleanup;
8135         }
8136     }
8137
8138 #ifdef _DEBUG
8139     //
8140     // Sanity check: If we are doing a cross-thread walk and there is no seed context, then
8141     // we better not be in managed code, otw we do not have a Frame on the stack from which to start
8142     // walking and we may miss the leaf-most chain of managed calls due to the way StackWalkFrames 
8143     // is implemented.  However, there is an exception when the leaf-most EE frame of pThreadToSnapshot
8144     // is an InlinedCallFrame, which has an active call, implying pThreadToShanpshot is inside an 
8145     // inlined P/Invoke.  In this case, the InlinedCallFrame will be used to help start off our
8146     // stackwalk at the top of the stack.
8147     //
8148     if (pThreadToSnapshot != pCurrentThread)
8149     {
8150 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8151         hr = E_NOTIMPL;
8152         goto Cleanup;
8153 #else
8154         if (pctxSeed == NULL)
8155         {
8156             if (pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8157             {
8158                 BOOL fFailedReaderLock = FALSE;
8159                 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(&ctxCurrent), hostCallPreference, &fFailedReaderLock);
8160
8161                 if (!fFailedReaderLock)
8162                 {
8163                     // not in jitted or ngend code or inside an inlined P/Invoke (the leaf-most EE Frame is
8164                     // an InlinedCallFrame with an active call)
8165                     _ASSERTE(!fIsManagedCode ||
8166                              (InlinedCallFrame::FrameHasActiveCall(pThreadToSnapshot->GetFrame())));
8167                 }
8168             }
8169         }
8170 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8171     }
8172 #endif //_DEBUG
8173     // Third, verify the target thread is seeded or not in the midst of an unwind.
8174     if (pctxSeed == NULL)
8175     {
8176         ThreadExceptionState* pExState = pThreadToSnapshot->GetExceptionState();
8177
8178         // this tests to see if there is an exception in flight
8179         if (pExState->IsExceptionInProgress() && pExState->GetFlags()->UnwindHasStarted())
8180         {
8181             EHClauseInfo *pCurrentEHClauseInfo = pThreadToSnapshot->GetExceptionState()->GetCurrentEHClauseInfo();
8182
8183             // if the exception code is telling us that we have entered a managed context then all is well
8184             if (!pCurrentEHClauseInfo->IsManagedCodeEntered())
8185             {
8186                 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8187                 goto Cleanup;
8188             }
8189         }
8190     }
8191
8192     // Check if the exception state is consistent.  See the comment for ThreadExceptionFlag for more information. 
8193     if (pThreadToSnapshot->GetExceptionState()->HasThreadExceptionFlag(ThreadExceptionState::TEF_InconsistentExceptionState))
8194     {
8195         hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8196         goto Cleanup;
8197     }
8198
8199     data.callback = callback;
8200     data.infoFlags = infoFlags;
8201     data.contextFlags = 0;
8202     data.clientData = clientData;
8203 #ifdef WIN64EXCEPTIONS
8204     data.sfParent.Clear();
8205 #endif
8206
8207     // workaround: The ForbidTypeLoad book keeping in the stackwalker is not robust against exceptions.
8208     // Unfortunately, it is hard to get it right in the stackwalker since it has to be exception 
8209     // handling free (frame unwinding may never return). We restore the ForbidTypeLoad counter here
8210     // in case it got messed up by exception thrown during the stackwalk.
8211     INDEBUG(if (pCurrentThread) ulForbidTypeLoad = pCurrentThread->m_ulForbidTypeLoad;)
8212
8213     {
8214         // An AV during a profiler stackwalk is an isolated event and shouldn't bring
8215         // down the runtime.  Need to place the holder here, outside of ProfilerStackWalkFramesWrapper
8216         // since ProfilerStackWalkFramesWrapper uses __try, which doesn't like objects
8217         // with destructors.
8218         AVInRuntimeImplOkayHolder AVOkay;
8219
8220         hr = DoStackSnapshotHelper(
8221                  pThreadToSnapshot, 
8222                  &data, 
8223                  HANDLESKIPPEDFRAMES |
8224                      FUNCTIONSONLY |
8225                      NOTIFY_ON_U2M_TRANSITIONS |
8226                      ((pThreadToSnapshot == pCurrentThread) ?
8227                          0 : 
8228                          ALLOW_ASYNC_STACK_WALK | THREAD_IS_SUSPENDED) |
8229                      THREAD_EXECUTING_MANAGED_CODE |
8230                      PROFILER_DO_STACK_SNAPSHOT |
8231                      ALLOW_INVALID_OBJECTS, // stack walk logic should not look at objects - we could be in the middle of a gc.
8232                  pctxSeed);
8233     }
8234
8235     INDEBUG(if (pCurrentThread) pCurrentThread->m_ulForbidTypeLoad = ulForbidTypeLoad;)
8236
8237 Cleanup:
8238 #if defined(PLATFORM_SUPPORTS_SAFE_THREADSUSPEND)
8239     if (fResumeThread)
8240     {
8241         pThreadToSnapshot->ResumeThread();
8242     }
8243 #endif // PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8244     if (fResetSnapshotThreadExternalCount)
8245     {
8246         pThreadToSnapshot->DecExternalCountDANGEROUSProfilerOnly();
8247     }
8248
8249     return hr;
8250
8251 #endif // !defined(FEATURE_HIJACK)
8252 }
8253
8254
8255 //---------------------------------------------------------------------------------------
8256 //
8257 // Exception swallowing wrapper around the profiler stackwalk
8258 //
8259 // Arguments:
8260 //      pThreadToSnapshot - Thread whose stack should be walked
8261 //      pData - data for stack walker
8262 //      flags - flags parameter to pass to StackWalkFramesEx, and StackFrameIterator 
8263 //      pctxSeed - Register context with which to seed the walk
8264 //
8265 // Return Value:
8266 //     HRESULT indicating success or failure.
8267 //
8268 HRESULT ProfToEEInterfaceImpl::DoStackSnapshotHelper(Thread * pThreadToSnapshot,
8269                                                      PROFILER_STACK_WALK_DATA * pData,
8270                                                      unsigned flags,
8271                                                      LPCONTEXT pctxSeed)
8272 {
8273     STATIC_CONTRACT_NOTHROW;
8274
8275     // We want to catch and swallow AVs here. For example, if the profiler gives 
8276     // us a bogus seed context (this happens), we could AV when inspecting memory pointed to 
8277     // by the (bogus) EBP register.
8278     //
8279     // EX_TRY/EX_CATCH does a lot of extras that we do not need and that can go wrong for us. 
8280     // E.g. It asserts in debug build for AVs in mscorwks or it synthetizes an object for the exception.
8281     // We use a plain PAL_TRY/PAL_EXCEPT since it is all we need.
8282     struct Param {
8283         HRESULT                     hr;
8284         Thread *                    pThreadToSnapshot;
8285         PROFILER_STACK_WALK_DATA *  pData;
8286         unsigned                    flags;
8287         ProfToEEInterfaceImpl *     pProfToEE;
8288         LPCONTEXT                   pctxSeed;
8289         BOOL                        fResetProfilerFilterContext;
8290     };
8291
8292     Param param;
8293     param.hr = E_UNEXPECTED;
8294     param.pThreadToSnapshot = pThreadToSnapshot;
8295     param.pData = pData;
8296     param.flags = flags; 
8297     param.pProfToEE = this;
8298     param.pctxSeed = pctxSeed;
8299     param.fResetProfilerFilterContext = FALSE;
8300
8301     PAL_TRY(Param *, pParam, &param)
8302     {
8303         if ((pParam->pData->infoFlags & COR_PRF_SNAPSHOT_X86_OPTIMIZED) != 0)
8304         {
8305 #ifndef _TARGET_X86_
8306             // If check in the begining of DoStackSnapshot (to return E_INVALIDARG) should 
8307             // make this unreachable
8308             _ASSERTE(!"COR_PRF_SNAPSHOT_X86_OPTIMIZED on non-X86 should be unreachable!");
8309 #else
8310             // New, simple EBP walker
8311             pParam->hr = pParam->pProfToEE->ProfilerEbpWalker(
8312                              pParam->pThreadToSnapshot,
8313                              pParam->pctxSeed,
8314                              pParam->pData->callback,
8315                              pParam->pData->clientData);
8316 #endif  // _TARGET_X86_
8317         }
8318         else
8319         {
8320             // We're now fairly confident the stackwalk should be ok, so set
8321             // the context seed, if one was provided or cooked up.
8322             if (pParam->pctxSeed != NULL)
8323             {
8324                 pParam->pThreadToSnapshot->SetProfilerFilterContext(pParam->pctxSeed);
8325                 pParam->fResetProfilerFilterContext = TRUE;
8326             }
8327
8328             // Whidbey-style walker, uses StackWalkFramesEx
8329             pParam->hr = pParam->pProfToEE->ProfilerStackWalkFramesWrapper(
8330                              pParam->pThreadToSnapshot,
8331                              pParam->pData,
8332                              pParam->flags);
8333         }
8334     }
8335     PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8336     {
8337         param.hr = E_UNEXPECTED;
8338     }
8339     PAL_ENDTRY;
8340
8341     // Undo the context seeding & thread suspend we did (if any)
8342     // to ensure that the thread we walked stayed suspended
8343     if (param.fResetProfilerFilterContext)
8344     {
8345         pThreadToSnapshot->SetProfilerFilterContext(NULL);
8346     }
8347
8348     return param.hr;
8349 }
8350
8351
8352 HRESULT ProfToEEInterfaceImpl::GetGenerationBounds(ULONG cObjectRanges,
8353                                                    ULONG *pcObjectRanges,
8354                                                    COR_PRF_GC_GENERATION_RANGE ranges[])
8355 {
8356     CONTRACTL
8357     {
8358         // Yay!
8359         NOTHROW;
8360
8361         // Yay!
8362         GC_NOTRIGGER;
8363
8364         // Yay!
8365         MODE_ANY;
8366
8367         // Yay!
8368         EE_THREAD_NOT_REQUIRED;
8369
8370         // Yay!
8371         CANNOT_TAKE_LOCK;
8372
8373
8374         PRECONDITION(CheckPointer(pcObjectRanges));
8375         PRECONDITION(cObjectRanges <= 0 || ranges != NULL);
8376         PRECONDITION(s_generationTableLock >= 0);
8377     }
8378     CONTRACTL_END;
8379
8380     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8381         (LF_CORPROF, 
8382         LL_INFO1000, 
8383         "**PROF: GetGenerationBounds.\n"));
8384     
8385     // Announce we are using the generation table now
8386     CounterHolder genTableLock(&s_generationTableLock);
8387
8388     GenerationTable *generationTable = s_currentGenerationTable;
8389
8390     if (generationTable == NULL)
8391     {
8392         return E_FAIL;
8393     }
8394
8395     _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8396
8397     GenerationDesc *genDescTable = generationTable->genDescTable;
8398     ULONG count = min(generationTable->count, cObjectRanges);
8399     for (ULONG i = 0; i < count; i++)
8400     {
8401         ranges[i].generation          = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8402         ranges[i].rangeStart          = (ObjectID)genDescTable[i].rangeStart;
8403         ranges[i].rangeLength         = genDescTable[i].rangeEnd         - genDescTable[i].rangeStart;
8404         ranges[i].rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8405     }
8406
8407     *pcObjectRanges = generationTable->count;
8408
8409     return S_OK;
8410 }
8411
8412
8413 HRESULT ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo(COR_PRF_EX_CLAUSE_INFO * pinfo)
8414 {
8415     CONTRACTL
8416     {
8417         // Yay!
8418         NOTHROW;
8419
8420         // Yay!
8421         GC_NOTRIGGER;
8422
8423         // Yay!
8424         MODE_ANY;
8425
8426         // Yay!
8427         CANNOT_TAKE_LOCK;
8428
8429
8430         PRECONDITION(CheckPointer(pinfo));
8431     }
8432     CONTRACTL_END;
8433
8434     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
8435                                      LL_INFO1000, 
8436                                      "**PROF: GetNotifiedExceptionClauseInfo.\n"));    
8437     
8438     HRESULT hr = S_OK;
8439
8440     ThreadExceptionState* pExState             = NULL;
8441     EHClauseInfo*         pCurrentEHClauseInfo = NULL;
8442
8443     // notification requires that we are on a managed thread with an exception in flight
8444     Thread *pThread = GetThread();
8445
8446     // If pThread is null, then the thread has never run managed code 
8447     if (pThread == NULL)
8448     {
8449         hr = CORPROF_E_NOT_MANAGED_THREAD;
8450         goto NullReturn;
8451     }
8452
8453     pExState = pThread->GetExceptionState();
8454     if (!pExState->IsExceptionInProgress())
8455     {
8456         // no exception is in flight -- successful failure
8457         hr = S_FALSE;
8458         goto NullReturn;
8459     }
8460
8461     pCurrentEHClauseInfo = pExState->GetCurrentEHClauseInfo();
8462     if (pCurrentEHClauseInfo->GetClauseType() == COR_PRF_CLAUSE_NONE)
8463     {
8464         // no exception is in flight -- successful failure
8465         hr = S_FALSE;
8466         goto NullReturn;
8467     }
8468
8469     pinfo->clauseType     = pCurrentEHClauseInfo->GetClauseType();
8470     pinfo->programCounter = pCurrentEHClauseInfo->GetIPForEHClause();
8471     pinfo->framePointer   = pCurrentEHClauseInfo->GetFramePointerForEHClause();
8472     pinfo->shadowStackPointer = 0;
8473
8474     return S_OK;
8475
8476 NullReturn:
8477     memset(pinfo, 0, sizeof(*pinfo));
8478     return hr;
8479 }
8480
8481
8482 HRESULT ProfToEEInterfaceImpl::GetObjectGeneration(ObjectID objectId,
8483                                                    COR_PRF_GC_GENERATION_RANGE *range)
8484 {
8485     CONTRACTL
8486     {
8487         // Yay!
8488         NOTHROW;
8489
8490         // Yay!
8491         GC_NOTRIGGER;
8492
8493         // Yay!
8494         MODE_ANY;
8495
8496         // Yay!
8497         EE_THREAD_NOT_REQUIRED;
8498
8499         // Yay!
8500         CANNOT_TAKE_LOCK;
8501
8502
8503         PRECONDITION(objectId != NULL);
8504         PRECONDITION(CheckPointer(range));
8505         PRECONDITION(s_generationTableLock >= 0);
8506     }
8507     CONTRACTL_END;
8508
8509     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8510                                        (LF_CORPROF, 
8511                                        LL_INFO1000, 
8512                                        "**PROF: GetObjectGeneration 0x%p.\n",
8513                                        objectId));        
8514
8515     BEGIN_GETTHREAD_ALLOWED;
8516     _ASSERTE((GetThread() == NULL) || (GetThread()->PreemptiveGCDisabled()));
8517     END_GETTHREAD_ALLOWED;
8518     
8519     // Announce we are using the generation table now
8520     CounterHolder genTableLock(&s_generationTableLock);
8521
8522     GenerationTable *generationTable = s_currentGenerationTable;
8523
8524     if (generationTable == NULL)
8525     {
8526         return E_FAIL;
8527     }
8528
8529     _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8530
8531     GenerationDesc *genDescTable = generationTable->genDescTable;
8532     ULONG count = generationTable->count;
8533     for (ULONG i = 0; i < count; i++)
8534     {
8535         if (genDescTable[i].rangeStart <= (BYTE *)objectId && (BYTE *)objectId < genDescTable[i].rangeEndReserved)
8536         {
8537             range->generation          = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8538             range->rangeStart          = (ObjectID)genDescTable[i].rangeStart;
8539             range->rangeLength         = genDescTable[i].rangeEnd         - genDescTable[i].rangeStart;
8540             range->rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8541
8542             return S_OK;
8543         }
8544     }
8545
8546     return E_FAIL;
8547 }
8548
8549 HRESULT ProfToEEInterfaceImpl::GetReJITIDs(
8550                            FunctionID          functionId,  // in
8551                            ULONG               cReJitIds,   // in
8552                            ULONG *             pcReJitIds,  // out
8553                            ReJITID             reJitIds[])  // out
8554 {
8555     CONTRACTL
8556     {
8557         // Yay!
8558         NOTHROW;
8559
8560         // taking a lock causes a GC
8561         GC_TRIGGERS;
8562
8563         // Yay!
8564         MODE_ANY;
8565
8566         // The rejit tables use a lock
8567         CAN_TAKE_LOCK;
8568
8569
8570         PRECONDITION(CheckPointer(pcReJitIds, NULL_OK));
8571         PRECONDITION(CheckPointer(reJitIds, NULL_OK));
8572
8573     }
8574     CONTRACTL_END;
8575
8576     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8577         kP2EEAllowableAfterAttach,
8578         (LF_CORPROF, 
8579         LL_INFO1000, 
8580         "**PROF: GetReJITIDs 0x%p.\n", 
8581          functionId));     
8582
8583     if (functionId == 0)
8584     {
8585         return E_INVALIDARG;
8586     }
8587
8588     if ((cReJitIds == 0) || (pcReJitIds == NULL) || (reJitIds == NULL))
8589     {
8590         return E_INVALIDARG;
8591     }
8592
8593     MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
8594
8595     return ReJitManager::GetReJITIDs(pMD, cReJitIds, pcReJitIds, reJitIds);
8596 }
8597
8598 HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG       cFunctions,   // in
8599                                             ModuleID    moduleIds[],  // in
8600                                             mdMethodDef methodIds[])  // in
8601 {
8602     CONTRACTL
8603     {
8604         // Yay!
8605         NOTHROW;
8606
8607         // When we suspend the runtime we drop into premptive mode
8608         GC_TRIGGERS;
8609
8610         // Yay!
8611         MODE_ANY;
8612
8613         // We need to suspend the runtime, this takes a lot of locks!
8614         CAN_TAKE_LOCK;
8615
8616
8617         PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8618         PRECONDITION(CheckPointer(methodIds, NULL_OK));
8619     }
8620     CONTRACTL_END;
8621
8622     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8623         kP2EETriggers | kP2EEAllowableAfterAttach,
8624         (LF_CORPROF, 
8625          LL_INFO1000, 
8626          "**PROF: RequestReJIT.\n"));
8627
8628     if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
8629     {
8630         return CORPROF_E_CALLBACK4_REQUIRED;
8631     }
8632
8633     if (!CORProfilerEnableRejit())
8634     {
8635         return CORPROF_E_REJIT_NOT_ENABLED;
8636     }
8637
8638     // Request at least 1 method to reJIT!
8639     if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8640     {
8641         return E_INVALIDARG;
8642     }
8643
8644     // Remember the profiler is doing this, as that means we must never detach it!
8645     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8646     
8647     GCX_PREEMP();
8648     return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds);
8649 }
8650
8651 HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG       cFunctions,  // in
8652                                              ModuleID    moduleIds[], // in
8653                                              mdMethodDef methodIds[], // in
8654                                              HRESULT     rgHrStatuses[])    // out
8655 {
8656     CONTRACTL
8657     {
8658         // Yay!
8659         NOTHROW;
8660
8661         // The rejit manager requires a lock to iterate through methods to revert, and
8662         // taking the lock can drop us into preemptive mode.
8663         GC_TRIGGERS;
8664
8665         // Yay!
8666         MODE_ANY;
8667
8668         // The rejit manager requires a lock to iterate through methods to revert
8669         CAN_TAKE_LOCK;
8670
8671
8672         PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8673         PRECONDITION(CheckPointer(methodIds, NULL_OK));
8674         PRECONDITION(CheckPointer(rgHrStatuses, NULL_OK));
8675     }
8676     CONTRACTL_END;
8677
8678     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8679         kP2EEAllowableAfterAttach | kP2EETriggers,
8680         (LF_CORPROF, 
8681          LL_INFO1000, 
8682          "**PROF: RequestRevert.\n"));
8683
8684     if (!CORProfilerEnableRejit())
8685     {
8686         return CORPROF_E_REJIT_NOT_ENABLED;
8687     }
8688
8689     // Request at least 1 method to revert!
8690     if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8691     {
8692         return E_INVALIDARG;
8693     }
8694
8695     // Remember the profiler is doing this, as that means we must never detach it!
8696     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8697
8698     // Initialize the status array
8699     if (rgHrStatuses != NULL)
8700     {
8701         memset(rgHrStatuses, 0, sizeof(HRESULT) * cFunctions);
8702         _ASSERTE(S_OK == rgHrStatuses[0]);
8703     }
8704
8705     GCX_PREEMP();
8706     return ReJitManager::RequestRevert(cFunctions, moduleIds, methodIds, rgHrStatuses);
8707 }
8708
8709
8710 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions(ICorProfilerFunctionEnum ** ppEnum)
8711 {
8712     CONTRACTL
8713     {
8714         // Yay!
8715         NOTHROW;
8716
8717         // Yay!
8718         GC_NOTRIGGER;
8719
8720         // Yay!
8721         MODE_ANY;
8722
8723         // If we're in preemptive mode we need to take a read lock to safely walk
8724         // the JIT data structures.
8725         CAN_TAKE_LOCK;
8726
8727
8728         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8729
8730     }
8731     CONTRACTL_END;
8732
8733     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8734         (LF_CORPROF, 
8735         LL_INFO10, 
8736         "**PROF: EnumJITedFunctions.\n"));
8737
8738     if (ppEnum == NULL)
8739     {
8740         return E_INVALIDARG;
8741     }
8742
8743     *ppEnum = NULL;
8744
8745     NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8746     if (pJitEnum == NULL)
8747     {
8748         return E_OUTOFMEMORY;
8749     }
8750
8751     if (!pJitEnum->Init())
8752     {
8753         return E_OUTOFMEMORY;
8754     }
8755
8756     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8757     *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8758
8759     return S_OK;
8760 }
8761
8762 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions2(ICorProfilerFunctionEnum ** ppEnum)
8763 {
8764     CONTRACTL
8765     {
8766         // Yay!
8767         NOTHROW;
8768
8769         // Gathering rejitids requires taking a lock and that lock might switch to
8770         // preemptimve mode... 
8771         GC_TRIGGERS;
8772
8773         // Yay!
8774         MODE_ANY;
8775
8776         // If we're in preemptive mode we need to take a read lock to safely walk
8777         // the JIT data structures.
8778         // Gathering RejitIDs also takes a lock.
8779         CAN_TAKE_LOCK;
8780
8781
8782         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8783
8784     }
8785     CONTRACTL_END;
8786
8787     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8788         kP2EEAllowableAfterAttach | kP2EETriggers,
8789         (LF_CORPROF, 
8790         LL_INFO10, 
8791         "**PROF: EnumJITedFunctions.\n"));
8792
8793     if (ppEnum == NULL)
8794     {
8795         return E_INVALIDARG;
8796     }
8797
8798     *ppEnum = NULL;
8799
8800     NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8801     if (pJitEnum == NULL)
8802     {
8803         return E_OUTOFMEMORY;
8804     }
8805
8806     if (!pJitEnum->Init(TRUE /* fWithReJITIDs */))
8807     {
8808         // If it fails, it's because of OOM.
8809         return E_OUTOFMEMORY;
8810     }
8811
8812     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8813     *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8814
8815     return S_OK;
8816 }
8817
8818 HRESULT ProfToEEInterfaceImpl::EnumModules(ICorProfilerModuleEnum ** ppEnum)
8819 {
8820     CONTRACTL
8821     {
8822         // Yay!
8823         NOTHROW;
8824
8825         // This method populates the enumerator, which requires iterating over
8826         // AppDomains, which adds, then releases, a reference on each AppDomain iterated.
8827         // This causes locking, and can cause triggering if the AppDomain gets destroyed
8828         // as a result of the release. (See code:AppDomainIterator::Next and its call to
8829         // code:AppDomain::Release.)
8830         GC_TRIGGERS;
8831
8832         // Yay!
8833         MODE_ANY;
8834
8835         // (See comment above GC_TRIGGERS.)
8836         CAN_TAKE_LOCK;
8837
8838
8839         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8840
8841     }
8842     CONTRACTL_END;
8843
8844     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8845         kP2EEAllowableAfterAttach | kP2EETriggers,
8846         (LF_CORPROF, 
8847         LL_INFO10, 
8848         "**PROF: EnumModules.\n"));
8849
8850     HRESULT hr;
8851
8852     if (ppEnum == NULL)
8853     {
8854         return E_INVALIDARG;
8855     }
8856
8857     *ppEnum = NULL;
8858
8859     // ProfilerModuleEnum uese AppDomainIterator, which cannot be called while the current thead
8860     // is holding the ThreadStore lock.
8861     if (ThreadStore::HoldingThreadStore())
8862     {
8863         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
8864     }
8865
8866     NewHolder<ProfilerModuleEnum> pModuleEnum(new (nothrow) ProfilerModuleEnum);
8867     if (pModuleEnum == NULL)
8868     {
8869         return E_OUTOFMEMORY;
8870     }
8871
8872     hr = pModuleEnum->Init();
8873     if (FAILED(hr))
8874     {
8875         return hr;
8876     }
8877
8878     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8879     *ppEnum = (ICorProfilerModuleEnum *) pModuleEnum.Extract();
8880
8881     return S_OK;
8882 }
8883
8884 HRESULT ProfToEEInterfaceImpl::GetRuntimeInformation(USHORT * pClrInstanceId,
8885                                                      COR_PRF_RUNTIME_TYPE * pRuntimeType,
8886                                                      USHORT * pMajorVersion,
8887                                                      USHORT * pMinorVersion,
8888                                                      USHORT * pBuildNumber,
8889                                                      USHORT * pQFEVersion,
8890                                                      ULONG  cchVersionString,
8891                                                      ULONG  * pcchVersionString,
8892                                                      __out_ecount_part_opt(cchVersionString, *pcchVersionString) WCHAR  szVersionString[])
8893 {
8894     CONTRACTL
8895     {
8896         // Yay!
8897         NOTHROW;
8898
8899         // Yay!
8900         GC_NOTRIGGER;
8901
8902         // Yay!
8903         MODE_ANY;
8904
8905         // Yay!
8906         EE_THREAD_NOT_REQUIRED;
8907
8908         // Yay!
8909         CANNOT_TAKE_LOCK;
8910
8911     }
8912     CONTRACTL_END;
8913
8914     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8915         (LF_CORPROF, 
8916         LL_INFO1000, 
8917         "**PROF: GetRuntimeInformation.\n"));
8918
8919     if ((szVersionString != NULL) && (pcchVersionString == NULL))
8920     {
8921         return E_INVALIDARG;
8922     }
8923
8924     if (pcchVersionString != NULL)
8925     {
8926         HRESULT hr = GetCORVersionInternal(szVersionString, (DWORD)cchVersionString, (DWORD *)pcchVersionString);
8927         if (FAILED(hr))
8928             return hr;
8929     }    
8930
8931     if (pClrInstanceId != NULL)
8932         *pClrInstanceId = static_cast<USHORT>(GetClrInstanceId());
8933
8934     if (pRuntimeType != NULL)
8935     {
8936         *pRuntimeType = COR_PRF_CORE_CLR;
8937     }
8938
8939     if (pMajorVersion != NULL)
8940         *pMajorVersion = CLR_MAJOR_VERSION;
8941
8942     if (pMinorVersion != NULL)
8943         *pMinorVersion = CLR_MINOR_VERSION;
8944
8945     if (pBuildNumber != NULL)
8946         *pBuildNumber = CLR_BUILD_VERSION;
8947
8948     if (pQFEVersion != NULL)
8949         *pQFEVersion = CLR_BUILD_VERSION_QFE;
8950
8951     return S_OK;
8952 }
8953
8954
8955 HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds)
8956 {
8957     CONTRACTL
8958     {
8959        // Yay!
8960         NOTHROW;
8961
8962         // Crst is used in ProfilingAPIDetach::RequestProfilerDetach so GC may be triggered
8963         GC_TRIGGERS;
8964
8965         // Yay!
8966         MODE_ANY;
8967
8968         // Yay!
8969         EE_THREAD_NOT_REQUIRED;
8970
8971         // Crst is used in ProfilingAPIDetach::RequestProfilerDetach
8972         CAN_TAKE_LOCK;
8973     }
8974     CONTRACTL_END;
8975
8976     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8977         kP2EEAllowableAfterAttach | kP2EETriggers,
8978         (LF_CORPROF, 
8979         LL_INFO1000, 
8980         "**PROF: RequestProfilerDetach.\n"));    
8981
8982 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
8983     return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds);
8984 #else // FEATURE_PROFAPI_ATTACH_DETACH
8985     return E_NOTIMPL;
8986 #endif // FEATURE_PROFAPI_ATTACH_DETACH
8987 }
8988
8989 typedef struct _COR_PRF_ELT_INFO_INTERNAL
8990 {
8991     // Point to a platform dependent structure ASM helper push on the stack
8992     void * platformSpecificHandle;
8993
8994     // startAddress of COR_PRF_FUNCTION_ARGUMENT_RANGE structure needs to point 
8995     // TO the argument value, not BE the argument value.  So, when the argument 
8996     // is this, we need to point TO this.  Because of the calling sequence change
8997     // in ELT3, we need to reserve the pointer here instead of using one of our 
8998     // stack variables.
8999     void * pThis;
9000
9001     // Reserve space for output parameter COR_PRF_FRAME_INFO of 
9002     // GetFunctionXXXX3Info functions
9003     COR_PRF_FRAME_INFO_INTERNAL frameInfo;
9004
9005 } COR_PRF_ELT_INFO_INTERNAL;
9006
9007 //---------------------------------------------------------------------------------------
9008 //
9009 // ProfilingGetFunctionEnter3Info provides frame information and argument infomation of 
9010 // the function ELT callback is inspecting.  It is called either by the profiler or the 
9011 // C helper function.
9012 // 
9013 // Arguments:
9014 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9015 //      * eltInfo - [in] The opaque pointer FunctionEnter3WithInfo callback passed to the profiler
9016 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9017 //                     generic types
9018 //      * pcbArgumentInfo - [in, out] Pointer to ULONG that specifies the size of structure 
9019 //                          pointed by pArgumentInfo
9020 //      * pArgumentInfo - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_INFO structure the profiler
9021 //                        must preserve enough space for the function it is inspecting
9022 //          
9023 // Return Value:
9024 //    HRESULT indicating success or failure.
9025 //    
9026
9027 HRESULT ProfilingGetFunctionEnter3Info(FunctionID functionId,                              // in
9028                                        COR_PRF_ELT_INFO eltInfo,                           // in
9029                                        COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9030                                        ULONG * pcbArgumentInfo,                            // in, out
9031                                        COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo)     // out
9032 {
9033     CONTRACTL
9034     {
9035         // Yay!
9036         NOTHROW;
9037
9038         // Yay!
9039         GC_NOTRIGGER;
9040
9041         // Yay!
9042         MODE_ANY;
9043
9044         // ProfileArgIterator::ProfileArgIterator may take locks
9045         CAN_TAKE_LOCK;
9046
9047
9048     }
9049     CONTRACTL_END;
9050
9051     if ((functionId == NULL) || (eltInfo == NULL))
9052     {
9053         return E_INVALIDARG;
9054     }
9055
9056     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9057     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9058
9059     // The loader won't trigger a GC or throw for already loaded argument types.
9060     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9061
9062     //
9063     // Find the method this is referring to, so we can get the signature
9064     //
9065     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9066     MetaSig metaSig(pMethodDesc);
9067
9068     NewHolder<ProfileArgIterator> pProfileArgIterator;
9069
9070     {
9071         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9072         FAULT_NOT_FATAL();
9073
9074         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9075
9076         if (pProfileArgIterator == NULL)
9077         {
9078             return E_UNEXPECTED;
9079         }
9080     }
9081
9082     if (CORProfilerFrameInfoEnabled())
9083     {
9084         if (pFrameInfo == NULL)
9085         {
9086             return E_INVALIDARG;
9087         }
9088
9089         //
9090         // Setup the COR_PRF_FRAME_INFO structure first.
9091         //
9092         COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9093
9094         pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9095         pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9096         pCorPrfFrameInfo->funcID = functionId;
9097         pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9098         pCorPrfFrameInfo->extraArg = pProfileArgIterator->GetHiddenArgValue();
9099         pCorPrfFrameInfo->thisArg = pProfileArgIterator->GetThis();
9100
9101         *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9102     }
9103
9104     //
9105     // Do argument processing if desired.
9106     //
9107     if (CORProfilerFunctionArgsEnabled())
9108     {
9109         if (pcbArgumentInfo == NULL)
9110         {
9111             return E_INVALIDARG;
9112         }
9113
9114         if ((*pcbArgumentInfo != 0) && (pArgumentInfo == NULL))
9115         {
9116             return E_INVALIDARG;
9117         }
9118
9119         ULONG32 count = pProfileArgIterator->GetNumArgs();
9120
9121         if (metaSig.HasThis())
9122         {
9123             count++;
9124         }
9125
9126         ULONG ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + (count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE));
9127
9128         if (*pcbArgumentInfo < ulArgInfoSize)
9129         {
9130             *pcbArgumentInfo = ulArgInfoSize;
9131             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
9132         }
9133
9134         _ASSERTE(pArgumentInfo != NULL);
9135
9136         pArgumentInfo->numRanges         = count;
9137         pArgumentInfo->totalArgumentSize = 0;
9138
9139         count = 0;
9140
9141         if (metaSig.HasThis())
9142         {
9143             pELTInfo->pThis = pProfileArgIterator->GetThis();
9144             pArgumentInfo->ranges[count].startAddress = (UINT_PTR) (&(pELTInfo->pThis));
9145
9146             UINT length = sizeof(pELTInfo->pThis);
9147             pArgumentInfo->ranges[count].length = length;
9148             pArgumentInfo->totalArgumentSize += length;
9149             count++;
9150         }
9151
9152         while (count < pArgumentInfo->numRanges)
9153         {
9154             pArgumentInfo->ranges[count].startAddress = (UINT_PTR)(pProfileArgIterator->GetNextArgAddr());
9155
9156             UINT length = pProfileArgIterator->GetArgSize();
9157             pArgumentInfo->ranges[count].length = length;
9158             pArgumentInfo->totalArgumentSize += length;
9159             count++;
9160         }
9161     }
9162
9163     return S_OK;
9164 }
9165
9166
9167
9168 HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId,                              // in
9169                                                      COR_PRF_ELT_INFO eltInfo,                           // in
9170                                                      COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9171                                                      ULONG * pcbArgumentInfo,                            // in, out
9172                                                      COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo)     // out
9173 {
9174     CONTRACTL
9175     {
9176         // Yay!
9177         NOTHROW;
9178
9179         // Yay!
9180         GC_NOTRIGGER;
9181
9182         // Yay!
9183         MODE_ANY;
9184
9185         // ProfilingGetFunctionEnter3Info may take locks
9186         CAN_TAKE_LOCK;
9187
9188
9189     }
9190     CONTRACTL_END;
9191
9192     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9193                                     LL_INFO1000, 
9194                                     "**PROF: GetFunctionEnter3Info.\n"));
9195
9196     _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL);
9197
9198     if (!CORProfilerELT3SlowPathEnterEnabled())
9199     {
9200         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9201     }
9202
9203     return ProfilingGetFunctionEnter3Info(functionId, eltInfo, pFrameInfo, pcbArgumentInfo, pArgumentInfo);
9204 }
9205
9206 //---------------------------------------------------------------------------------------
9207 //
9208 // ProfilingGetFunctionLeave3Info provides frame information and return value infomation 
9209 // of the function ELT callback is inspecting.  It is called either by the profiler or the 
9210 // C helper function.
9211 // 
9212 // Arguments:
9213 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9214 //      * eltInfo - [in] The opaque pointer FunctionLeave3WithInfo callback passed to the profiler
9215 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9216 //                     generic types
9217 //      * pRetvalRange - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_RANGE to store return value
9218 //          
9219 // Return Value:
9220 //    HRESULT indicating success or failure.
9221 //    
9222
9223 HRESULT ProfilingGetFunctionLeave3Info(FunctionID functionId,                              // in
9224                                        COR_PRF_ELT_INFO eltInfo,                           // in
9225                                        COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9226                                        COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange)     // out
9227 {
9228     CONTRACTL
9229     {
9230         // Yay!
9231         NOTHROW;
9232
9233         // Yay!
9234         GC_NOTRIGGER;
9235
9236         // Yay!
9237         MODE_ANY;
9238
9239         // ProfileArgIterator::ProfileArgIterator may take locks
9240         CAN_TAKE_LOCK;
9241
9242     }
9243     CONTRACTL_END;
9244
9245     if ((pFrameInfo == NULL) || (eltInfo == NULL))
9246     {
9247         return E_INVALIDARG;
9248     }
9249
9250     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9251     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9252
9253     // The loader won't trigger a GC or throw for already loaded argument types.
9254     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9255
9256     //
9257     // Find the method this is referring to, so we can get the signature
9258     //
9259     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9260     MetaSig metaSig(pMethodDesc);
9261
9262     NewHolder<ProfileArgIterator> pProfileArgIterator;
9263
9264     {
9265         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9266         FAULT_NOT_FATAL();
9267
9268         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9269
9270         if (pProfileArgIterator == NULL)
9271         {
9272             return E_UNEXPECTED;
9273         }
9274     }
9275
9276     if (CORProfilerFrameInfoEnabled())
9277     {
9278         if (pFrameInfo == NULL)
9279         {
9280             return E_INVALIDARG;
9281         }
9282
9283         COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9284
9285         //
9286         // Setup the COR_PRF_FRAME_INFO structure first.
9287         //
9288         pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9289         pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9290         pCorPrfFrameInfo->funcID = functionId;
9291         pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9292
9293         // Upon entering Leave hook, the register assigned to store this pointer on function calls may 
9294         // already be reused and is likely not to contain this pointer.
9295         pCorPrfFrameInfo->extraArg = NULL;
9296         pCorPrfFrameInfo->thisArg = NULL;
9297
9298         *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9299     }
9300
9301     //
9302     // Do argument processing if desired.
9303     //
9304     if (CORProfilerFunctionReturnValueEnabled())
9305     {
9306         if (pRetvalRange == NULL)
9307         {
9308             return E_INVALIDARG;
9309         }
9310
9311         if (!metaSig.IsReturnTypeVoid())
9312         {
9313             pRetvalRange->length = metaSig.GetReturnTypeSize();
9314             pRetvalRange->startAddress = (UINT_PTR)pProfileArgIterator->GetReturnBufferAddr();
9315         }
9316         else
9317         {
9318             pRetvalRange->length = 0;
9319             pRetvalRange->startAddress = 0;
9320         }
9321     }
9322
9323     return S_OK;
9324 }
9325
9326
9327 HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId,                              // in
9328                                                      COR_PRF_ELT_INFO eltInfo,                           // in
9329                                                      COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9330                                                      COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange)     // out
9331 {
9332     CONTRACTL
9333     {
9334         // Yay!
9335         NOTHROW;
9336
9337         // Yay!
9338         GC_NOTRIGGER;
9339
9340         // Yay!
9341         MODE_ANY;
9342
9343         // ProfilingGetFunctionLeave3Info may take locks
9344         CAN_TAKE_LOCK;
9345
9346
9347     }
9348     CONTRACTL_END;
9349
9350     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9351                                     LL_INFO1000, 
9352                                     "**PROF: GetFunctionLeave3Info.\n"));
9353
9354     _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL);
9355
9356     if (!CORProfilerELT3SlowPathLeaveEnabled())
9357     {
9358         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9359     }
9360
9361     return ProfilingGetFunctionLeave3Info(functionId, eltInfo, pFrameInfo, pRetvalRange);
9362 }
9363
9364 //---------------------------------------------------------------------------------------
9365 //
9366 // ProfilingGetFunctionTailcall3Info provides frame information of the function ELT callback 
9367 // is inspecting.  It is called either by the profiler or the C helper function.
9368 // 
9369 // Arguments:
9370 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9371 //      * eltInfo - [in] The opaque pointer FunctionTailcall3WithInfo callback passed to the 
9372 //                  profiler
9373 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9374 //                     generic types
9375 //          
9376 // Return Value:
9377 //    HRESULT indicating success or failure.
9378 //    
9379
9380 HRESULT ProfilingGetFunctionTailcall3Info(FunctionID functionId,                              // in
9381                                           COR_PRF_ELT_INFO eltInfo,                           // in
9382                                           COR_PRF_FRAME_INFO * pFrameInfo)                    // out
9383 {
9384     CONTRACTL
9385     {
9386         // Yay!
9387         NOTHROW;
9388
9389         // Yay!
9390         GC_NOTRIGGER;
9391
9392         // Yay!
9393         MODE_ANY;
9394
9395         // ProfileArgIterator::ProfileArgIterator may take locks
9396         CAN_TAKE_LOCK;
9397
9398
9399     }
9400     CONTRACTL_END;
9401
9402     if ((functionId == NULL) || (eltInfo == NULL) || (pFrameInfo == NULL))
9403     {
9404         return E_INVALIDARG;
9405     }
9406
9407     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9408     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9409
9410     // The loader won't trigger a GC or throw for already loaded argument types.
9411     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9412
9413     //
9414     // Find the method this is referring to, so we can get the signature
9415     //
9416     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9417     MetaSig metaSig(pMethodDesc);
9418
9419     NewHolder<ProfileArgIterator> pProfileArgIterator;
9420
9421     {
9422         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9423         FAULT_NOT_FATAL();
9424
9425         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9426
9427         if (pProfileArgIterator == NULL)
9428         {
9429             return E_UNEXPECTED;
9430         }
9431     }
9432
9433     COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9434
9435     //
9436     // Setup the COR_PRF_FRAME_INFO structure first.
9437     //
9438     pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9439     pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9440     pCorPrfFrameInfo->funcID = functionId;
9441     pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9442
9443     // Tailcall is designed to report the caller, not the callee.  But the taillcall hook is invoked 
9444     // with registers containing parameters passed to the callee before calling into the callee.  
9445     // This pointer we get here is for the callee.  Because of the constraints imposed on tailcall
9446     // optimization, this pointer passed to the callee accidentally happens to be the same this pointer 
9447     // passed to the caller.  
9448     // 
9449     // It is a fragile coincidence we should not depend on because JIT is free to change the 
9450     // implementation details in the future.
9451     pCorPrfFrameInfo->extraArg = NULL;
9452     pCorPrfFrameInfo->thisArg = NULL;
9453
9454     *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9455
9456     return S_OK;
9457 }
9458
9459
9460 HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId,                              // in
9461                                                         COR_PRF_ELT_INFO eltInfo,                           // in
9462                                                         COR_PRF_FRAME_INFO * pFrameInfo)                    // out
9463 {
9464     CONTRACTL
9465     {
9466         // Yay!
9467         NOTHROW;
9468
9469         // Yay!
9470         GC_NOTRIGGER;
9471
9472         // Yay!
9473         MODE_ANY;
9474
9475         // ProfilingGetFunctionTailcall3Info may take locks
9476         CAN_TAKE_LOCK;
9477
9478
9479     }
9480     CONTRACTL_END;
9481
9482     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9483                                     LL_INFO1000, 
9484                                     "**PROF: GetFunctionTailcall3Info.\n"));
9485
9486     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL);
9487
9488     if (!CORProfilerELT3SlowPathTailcallEnabled())
9489     {
9490         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9491     }
9492
9493     return ProfilingGetFunctionTailcall3Info(functionId, eltInfo, pFrameInfo);
9494 }
9495
9496 HRESULT ProfToEEInterfaceImpl::EnumThreads(
9497     /* out */ ICorProfilerThreadEnum ** ppEnum)
9498 {
9499
9500     CONTRACTL
9501     {
9502         // Yay!
9503         NOTHROW;
9504
9505         // Yay!
9506         GC_NOTRIGGER;
9507
9508         // Yay!
9509         MODE_ANY;
9510
9511         // Need to acquire the thread store lock
9512         CAN_TAKE_LOCK;
9513         
9514
9515         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
9516
9517     }
9518     CONTRACTL_END;
9519
9520     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9521         kP2EEAllowableAfterAttach,
9522         (LF_CORPROF, 
9523         LL_INFO10, 
9524         "**PROF: EnumThreads.\n"));
9525
9526     HRESULT hr;
9527
9528     if (ppEnum == NULL)
9529     {
9530         return E_INVALIDARG;
9531     }
9532
9533     *ppEnum = NULL;
9534
9535     NewHolder<ProfilerThreadEnum> pThreadEnum(new (nothrow) ProfilerThreadEnum);
9536     if (pThreadEnum == NULL)
9537     {
9538         return E_OUTOFMEMORY;
9539     }
9540
9541     hr = pThreadEnum->Init();
9542     if (FAILED(hr))
9543     {
9544         return hr;
9545     }
9546
9547     // Ownership transferred to [out] param.  Caller must Release() when done with this.
9548     *ppEnum = (ICorProfilerThreadEnum *) pThreadEnum.Extract();
9549
9550     return S_OK;
9551 }
9552
9553 // This function needs to be called on any thread before making any ICorProfilerInfo* calls and must be 
9554 // made before any thread is suspended by this profiler.
9555 // As you might have already figured out, this is done to avoid deadlocks situation when 
9556 // the suspended thread holds on the loader lock / heap lock while the current thread is trying to obtain
9557 // the same lock.
9558 HRESULT ProfToEEInterfaceImpl::InitializeCurrentThread()
9559 {
9560
9561     CONTRACTL
9562     {
9563         // Yay!
9564         NOTHROW;
9565
9566         // Yay!
9567         GC_NOTRIGGER;
9568
9569         // Yay!
9570         MODE_ANY;
9571
9572         // May take thread store lock and OS APIs may also take locks
9573         CAN_TAKE_LOCK;
9574         
9575     }
9576     CONTRACTL_END;
9577     
9578    
9579     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9580             kP2EEAllowableAfterAttach,
9581             (LF_CORPROF, 
9582             LL_INFO10, 
9583             "**PROF: InitializeCurrentThread.\n"));
9584
9585     HRESULT hr = S_OK;
9586     
9587     EX_TRY
9588     {
9589         CExecutionEngine::SetupTLSForThread(GetThread());
9590     }
9591     EX_CATCH_HRESULT(hr);
9592
9593     if (FAILED(hr))
9594         return hr;
9595     
9596      return S_OK;
9597 }
9598
9599 struct InternalProfilerModuleEnum : public ProfilerModuleEnum
9600 {
9601     CDynArray<ModuleID> *GetRawElementsArray()
9602     {
9603         return &m_elements;
9604     }
9605 };
9606
9607 HRESULT ProfToEEInterfaceImpl::EnumNgenModuleMethodsInliningThisMethod(
9608     ModuleID    inlinersModuleId,
9609     ModuleID    inlineeModuleId,
9610     mdMethodDef inlineeMethodId,
9611     BOOL       *incompleteData,
9612     ICorProfilerMethodEnum** ppEnum)
9613 {
9614     CONTRACTL
9615     {
9616         NOTHROW;
9617         GC_TRIGGERS; 
9618         MODE_ANY;
9619         CAN_TAKE_LOCK;
9620         PRECONDITION(CheckPointer(ppEnum));
9621     }
9622     CONTRACTL_END;
9623
9624     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EETriggers, (LF_CORPROF, LL_INFO1000,  "**PROF: EnumNgenModuleMethodsInliningThisMethod.\n"));
9625
9626     if (ppEnum == NULL)
9627     {
9628         return E_INVALIDARG;
9629     }
9630     *ppEnum = NULL;
9631     HRESULT hr = S_OK;
9632
9633     Module *inlineeOwnerModule = reinterpret_cast<Module *>(inlineeModuleId);
9634     if (inlineeOwnerModule == NULL)
9635     {
9636         return E_INVALIDARG;
9637     }
9638     if (inlineeOwnerModule->IsBeingUnloaded())
9639     {
9640         return CORPROF_E_DATAINCOMPLETE;
9641     }
9642
9643     Module  *inlinersModule = reinterpret_cast<Module *>(inlinersModuleId);
9644     if (inlinersModule == NULL)
9645     {
9646         return E_INVALIDARG;
9647     }
9648     if(inlinersModule->IsBeingUnloaded())
9649     {
9650         return CORPROF_E_DATAINCOMPLETE;
9651     }
9652
9653     if (!inlinersModule->HasInlineTrackingMap())
9654     {
9655         return CORPROF_E_DATAINCOMPLETE;
9656     }
9657
9658     CDynArray<COR_PRF_METHOD> results;
9659     const COUNT_T staticBufferSize = 10;
9660     MethodInModule staticBuffer[staticBufferSize];
9661     NewArrayHolder<MethodInModule> dynamicBuffer;
9662     MethodInModule *methodsBuffer = staticBuffer;
9663     EX_TRY
9664     {
9665         // Trying to use static buffer
9666         COUNT_T methodsAvailable = inlinersModule->GetInliners(inlineeOwnerModule, inlineeMethodId, staticBufferSize, staticBuffer, incompleteData);
9667
9668         // If static buffer is not enough, allocate an array.
9669         if (methodsAvailable > staticBufferSize)
9670         {
9671             DWORD dynamicBufferSize = methodsAvailable;
9672             dynamicBuffer = methodsBuffer = new MethodInModule[dynamicBufferSize];
9673             methodsAvailable = inlinersModule->GetInliners(inlineeOwnerModule, inlineeMethodId, dynamicBufferSize, dynamicBuffer, incompleteData);                
9674             if (methodsAvailable > dynamicBufferSize)
9675             {
9676                 _ASSERTE(!"Ngen image inlining info changed, this shouldn't be possible.");
9677                 methodsAvailable = dynamicBufferSize;
9678             }
9679         }
9680
9681         //Go through all inliners found in the inlinersModule and prepare them to export via results.
9682         results.AllocateBlockThrowing(methodsAvailable);
9683         for (COUNT_T j = 0; j < methodsAvailable; j++)
9684         {
9685             COR_PRF_METHOD *newPrfMethod = &results[j];
9686             newPrfMethod->moduleId = reinterpret_cast<ModuleID>(methodsBuffer[j].m_module);
9687             newPrfMethod->methodId = methodsBuffer[j].m_methodDef;
9688         }
9689         *ppEnum = new ProfilerMethodEnum(&results);
9690     }
9691     EX_CATCH_HRESULT(hr);
9692
9693     return hr;
9694 }
9695
9696 HRESULT ProfToEEInterfaceImpl::GetInMemorySymbolsLength(
9697     ModuleID moduleId,
9698     DWORD* pCountSymbolBytes)
9699 {
9700
9701     CONTRACTL
9702     {
9703         NOTHROW;
9704         GC_NOTRIGGER;
9705         MODE_ANY;
9706     }
9707     CONTRACTL_END;
9708
9709
9710     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9711         kP2EEAllowableAfterAttach,
9712         (LF_CORPROF,
9713             LL_INFO10,
9714             "**PROF: GetInMemorySymbolsLength.\n"));
9715
9716     HRESULT hr = S_OK;
9717     if (pCountSymbolBytes == NULL)
9718     {
9719         return E_INVALIDARG;
9720     }
9721     *pCountSymbolBytes = 0;
9722
9723     Module* pModule = reinterpret_cast< Module* >(moduleId);
9724     if (pModule == NULL)
9725     {
9726         return E_INVALIDARG;
9727     }
9728     if (pModule->IsBeingUnloaded())
9729     {
9730         return CORPROF_E_DATAINCOMPLETE;
9731     }
9732
9733     //This method would work fine on reflection.emit, but there would be no way to know
9734     //if some other thread was changing the size of the symbols before this method returned.
9735     //Adding events or locks to detect/prevent changes would make the scenario workable
9736     if (pModule->IsReflection())
9737     {
9738         return COR_PRF_MODULE_DYNAMIC;
9739     }
9740     
9741     CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9742     if (pStream == NULL)
9743     {
9744         return S_OK;
9745     }
9746
9747     STATSTG SizeData = { 0 };
9748     hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9749     if (FAILED(hr))
9750     {
9751         return hr;
9752     }
9753     if (SizeData.cbSize.u.HighPart > 0)
9754     {
9755         return COR_E_OVERFLOW;
9756     }
9757     *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
9758
9759     return S_OK;
9760 }
9761
9762 HRESULT ProfToEEInterfaceImpl::ReadInMemorySymbols(
9763     ModuleID moduleId,
9764     DWORD symbolsReadOffset,
9765     BYTE* pSymbolBytes,
9766     DWORD countSymbolBytes,
9767     DWORD* pCountSymbolBytesRead)
9768 {
9769     CONTRACTL
9770     {
9771         NOTHROW;
9772         GC_NOTRIGGER;
9773         MODE_ANY;
9774     }
9775     CONTRACTL_END;
9776
9777     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9778         kP2EEAllowableAfterAttach,
9779         (LF_CORPROF,
9780             LL_INFO10,
9781             "**PROF: ReadInMemorySymbols.\n"));
9782
9783     HRESULT hr = S_OK;
9784     if (pSymbolBytes == NULL)
9785     {
9786         return E_INVALIDARG;
9787     }
9788     if (pCountSymbolBytesRead == NULL)
9789     {
9790         return E_INVALIDARG;
9791     }
9792     *pCountSymbolBytesRead = 0;
9793
9794     Module* pModule = reinterpret_cast< Module* >(moduleId);
9795     if (pModule == NULL)
9796     {
9797         return E_INVALIDARG;
9798     }
9799     if (pModule->IsBeingUnloaded())
9800     {
9801         return CORPROF_E_DATAINCOMPLETE;
9802     }
9803
9804     //This method would work fine on reflection.emit, but there would be no way to know
9805     //if some other thread was changing the size of the symbols before this method returned.
9806     //Adding events or locks to detect/prevent changes would make the scenario workable
9807     if (pModule->IsReflection())
9808     {
9809         return COR_PRF_MODULE_DYNAMIC;
9810     }
9811
9812     CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9813     if (pStream == NULL)
9814     {
9815         return E_INVALIDARG;
9816     }
9817
9818     STATSTG SizeData = { 0 };
9819     hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9820     if (FAILED(hr))
9821     {
9822         return hr;
9823     }
9824     if (SizeData.cbSize.u.HighPart > 0)
9825     {
9826         return COR_E_OVERFLOW;
9827     }
9828     DWORD streamSize = SizeData.cbSize.u.LowPart;
9829     if (symbolsReadOffset >= streamSize)
9830     {
9831         return E_INVALIDARG;
9832     }
9833
9834     *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
9835     memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
9836
9837     return S_OK;
9838 }
9839
9840 HRESULT ProfToEEInterfaceImpl::ApplyMetaData(
9841     ModuleID    moduleId)
9842 {
9843     CONTRACTL
9844     {
9845         NOTHROW;
9846         GC_TRIGGERS;
9847         MODE_ANY;
9848     }
9849     CONTRACTL_END;
9850
9851     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach | kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: ApplyMetaData.\n"));
9852
9853     if (moduleId == NULL)
9854     {
9855         return E_INVALIDARG;
9856     }
9857
9858     HRESULT hr = S_OK;
9859     EX_TRY
9860     {
9861         Module *pModule = (Module *)moduleId;
9862         _ASSERTE(pModule != NULL);
9863         if (pModule->IsBeingUnloaded())
9864         {
9865             hr = CORPROF_E_DATAINCOMPLETE;
9866         }
9867        else
9868        {
9869             pModule->ApplyMetaData();
9870        }
9871     }
9872     EX_CATCH_HRESULT(hr);
9873     return hr;
9874 }
9875
9876 //---------------------------------------------------------------------------------------
9877 //
9878 // Simple wrapper around EEToProfInterfaceImpl::ManagedToUnmanagedTransition.  This
9879 // can be called by C++ code and directly by generated stubs.
9880 //
9881 // Arguments:
9882 //      pMD - MethodDesc for the managed function involved in the transition
9883 //      reason - Passed on to profiler to indicate why the transition is occurring
9884 //
9885
9886 void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD,
9887                                                       COR_PRF_TRANSITION_REASON reason)
9888 {
9889     CONTRACTL
9890     {
9891         NOTHROW;
9892         GC_TRIGGERS;
9893         MODE_PREEMPTIVE;
9894     }
9895     CONTRACTL_END;
9896
9897     // This function is called within the runtime, not directly from managed code.
9898     // Also, the only case MD is NULL is the calli pinvoke case, and we still
9899     // want to notify the profiler in that case.
9900
9901     // Do not notify the profiler about QCalls
9902     if (pMD == NULL || !pMD->IsQCall())
9903     {
9904         BEGIN_PIN_PROFILER(CORProfilerPresent());
9905         g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD),
9906                                                                         reason);
9907         END_PIN_PROFILER();
9908     }
9909 }
9910
9911 //---------------------------------------------------------------------------------------
9912 //
9913 // Simple wrapper around EEToProfInterfaceImpl::UnmanagedToManagedTransition.  This
9914 // can be called by C++ code and directly by generated stubs.
9915 //
9916 // Arguments:
9917 //      pMD - MethodDesc for the managed function involved in the transition
9918 //      reason - Passed on to profiler to indicate why the transition is occurring
9919 //
9920
9921 void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD,
9922                                                       COR_PRF_TRANSITION_REASON reason)
9923 {
9924     CONTRACTL
9925     {
9926         NOTHROW;
9927         GC_TRIGGERS;
9928         MODE_PREEMPTIVE;
9929     }
9930     CONTRACTL_END;
9931
9932     // This function is called within the runtime, not directly from managed code.
9933     // Also, the only case MD is NULL is the calli pinvoke case, and we still
9934     // want to notify the profiler in that case.
9935
9936     // Do not notify the profiler about QCalls
9937     if (pMD == NULL || !pMD->IsQCall())
9938     {
9939         BEGIN_PIN_PROFILER(CORProfilerPresent());
9940         g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD),
9941                                                                         reason);
9942         END_PIN_PROFILER();
9943     }
9944 }
9945
9946
9947
9948 #endif // PROFILING_SUPPORTED
9949
9950
9951 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemoting)
9952 {
9953     FCALL_CONTRACT;
9954
9955 #ifdef PROFILING_SUPPORTED
9956     FC_RETURN_BOOL(CORProfilerTrackRemoting());
9957 #else // !PROFILING_SUPPORTED
9958     FC_RETURN_BOOL(FALSE);
9959 #endif // !PROFILING_SUPPORTED
9960 }
9961 FCIMPLEND
9962
9963 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingCookie)
9964 {
9965     FCALL_CONTRACT;
9966
9967 #ifdef PROFILING_SUPPORTED
9968     FC_RETURN_BOOL(CORProfilerTrackRemotingCookie());
9969 #else // !PROFILING_SUPPORTED
9970     FC_RETURN_BOOL(FALSE);
9971 #endif // !PROFILING_SUPPORTED
9972 }
9973 FCIMPLEND
9974
9975 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingAsync)
9976 {
9977     FCALL_CONTRACT;
9978
9979 #ifdef PROFILING_SUPPORTED
9980     FC_RETURN_BOOL(CORProfilerTrackRemotingAsync());
9981 #else // !PROFILING_SUPPORTED
9982     FC_RETURN_BOOL(FALSE);
9983 #endif // !PROFILING_SUPPORTED
9984 }
9985 FCIMPLEND
9986
9987 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingClientSendingMessage, GUID *pId, CLR_BOOL fIsAsync)
9988 {
9989     FCALL_CONTRACT;
9990
9991 #ifdef PROFILING_SUPPORTED
9992     // Need to erect a GC frame so that GCs can occur without a problem
9993     // within the profiler code.
9994
9995     // Note that we don't need to worry about pId moving around since
9996     // it is a value class declared on the stack and so GC doesn't
9997     // know about it.
9998
9999     _ASSERTE (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pId));     // should be on the stack, not in the heap
10000     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10001
10002     {
10003         BEGIN_PIN_PROFILER(CORProfilerPresent());
10004         GCX_PREEMP();
10005         if (CORProfilerTrackRemotingCookie())
10006         {
10007             g_profControlBlock.pProfInterface->GetGUID(pId);
10008             _ASSERTE(pId->Data1);
10009
10010             g_profControlBlock.pProfInterface->RemotingClientSendingMessage(pId, fIsAsync);
10011         }
10012         else
10013         {
10014             g_profControlBlock.pProfInterface->RemotingClientSendingMessage(NULL, fIsAsync);
10015         }
10016         END_PIN_PROFILER();
10017     }
10018     HELPER_METHOD_FRAME_END_POLL();
10019 #endif // PROFILING_SUPPORTED
10020 }
10021 FCIMPLEND
10022
10023
10024 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingClientReceivingReply, GUID id, CLR_BOOL fIsAsync)
10025 {
10026     FCALL_CONTRACT;
10027
10028 #ifdef PROFILING_SUPPORTED
10029     // Need to erect a GC frame so that GCs can occur without a problem
10030     // within the profiler code.
10031
10032     // Note that we don't need to worry about pId moving around since
10033     // it is a value class declared on the stack and so GC doesn't
10034     // know about it.
10035
10036     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10037
10038
10039     {
10040         BEGIN_PIN_PROFILER(CORProfilerPresent());
10041         GCX_PREEMP();
10042         if (CORProfilerTrackRemotingCookie())
10043         {
10044             g_profControlBlock.pProfInterface->RemotingClientReceivingReply(&id, fIsAsync);
10045         }
10046         else
10047         {
10048             g_profControlBlock.pProfInterface->RemotingClientReceivingReply(NULL, fIsAsync);
10049         }
10050         END_PIN_PROFILER();
10051     }
10052
10053     HELPER_METHOD_FRAME_END_POLL();
10054 #endif // PROFILING_SUPPORTED
10055 }
10056 FCIMPLEND
10057
10058
10059 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingServerReceivingMessage, GUID id, CLR_BOOL fIsAsync)
10060 {
10061     FCALL_CONTRACT;
10062
10063 #ifdef PROFILING_SUPPORTED
10064     // Need to erect a GC frame so that GCs can occur without a problem
10065     // within the profiler code.
10066
10067     // Note that we don't need to worry about pId moving around since
10068     // it is a value class declared on the stack and so GC doesn't
10069     // know about it.
10070
10071     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10072
10073     {
10074         BEGIN_PIN_PROFILER(CORProfilerPresent());
10075         GCX_PREEMP();
10076         if (CORProfilerTrackRemotingCookie())
10077         {
10078             g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(&id, fIsAsync);
10079         }
10080         else
10081         {
10082             g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(NULL, fIsAsync);
10083         }
10084         END_PIN_PROFILER();
10085     }
10086
10087     HELPER_METHOD_FRAME_END_POLL();
10088 #endif // PROFILING_SUPPORTED
10089 }
10090 FCIMPLEND
10091
10092 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingServerSendingReply, GUID *pId, CLR_BOOL fIsAsync)
10093 {
10094     FCALL_CONTRACT;
10095
10096 #ifdef PROFILING_SUPPORTED
10097     // Need to erect a GC frame so that GCs can occur without a problem
10098     // within the profiler code.
10099
10100     // Note that we don't need to worry about pId moving around since
10101     // it is a value class declared on the stack and so GC doesn't
10102     // know about it.
10103
10104     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10105
10106     {
10107         BEGIN_PIN_PROFILER(CORProfilerPresent());
10108         GCX_PREEMP();
10109         if (CORProfilerTrackRemotingCookie())
10110         {
10111             g_profControlBlock.pProfInterface->GetGUID(pId);
10112             _ASSERTE(pId->Data1);
10113
10114             g_profControlBlock.pProfInterface->RemotingServerSendingReply(pId, fIsAsync);
10115         }
10116         else
10117         {
10118             g_profControlBlock.pProfInterface->RemotingServerSendingReply(NULL, fIsAsync);
10119         }
10120         END_PIN_PROFILER();
10121     }
10122
10123     HELPER_METHOD_FRAME_END_POLL();
10124 #endif // PROFILING_SUPPORTED
10125 }
10126 FCIMPLEND
10127
10128
10129 //*******************************************************************************************
10130 // These do a lot of work for us, setting up Frames, gathering arg info and resolving generics.
10131   //*******************************************************************************************
10132
10133 HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecificHandle)
10134 {
10135     FCALL_CONTRACT;
10136
10137 #ifdef PROFILING_SUPPORTED
10138
10139 #ifdef PROF_TEST_ONLY_FORCE_ELT
10140     // If this test-only flag is set, it's possible we might not have a profiler
10141     // attached, or might not have any of the hooks set. See
10142     // code:ProfControlBlock#TestOnlyELT
10143     if (g_profControlBlock.fTestOnlyForceEnterLeave)
10144     {
10145         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10146             (
10147                 (g_profControlBlock.pProfInterface->GetEnterHook()          == NULL) &&
10148                 (g_profControlBlock.pProfInterface->GetEnter2Hook()         == NULL) &&
10149                 (g_profControlBlock.pProfInterface->GetEnter3Hook()         == NULL) &&
10150                 (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL)
10151             )
10152            )
10153         {
10154             return;
10155         }
10156     }       
10157 #endif // PROF_TEST_ONLY_FORCE_ELT
10158
10159     // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10160     _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL);
10161     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10162     _ASSERTE(platformSpecificHandle != NULL);
10163
10164     // Set up a frame
10165     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10166
10167     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10168     // frame, like we're about to do.
10169     SetCallbackStateFlagsHolder csf(
10170         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10171    
10172     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10173     eltInfo.platformSpecificHandle = platformSpecificHandle;
10174
10175     //
10176     // CLR v4 Slow-Path ELT
10177     //
10178     if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL)
10179     {
10180         FunctionIDOrClientID functionIDOrClientID;
10181         functionIDOrClientID.clientID = clientData;
10182         g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()(
10183             functionIDOrClientID, 
10184             (COR_PRF_ELT_INFO)&eltInfo);
10185         goto LExit;
10186     }
10187
10188     if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL)
10189     {
10190         // We have run out of heap memory, so the content of the mapping table becomes stale.
10191         // All Whidbey ETL hooks must be turned off.
10192         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10193         {
10194             goto LExit;
10195         }
10196
10197         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10198         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10199         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10200         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10201         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10202         FunctionID functionId = clientData;
10203         _ASSERTE(functionId != NULL);
10204         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10205
10206         //
10207         // Whidbey Fast-Path ELT
10208         //
10209         if (CORProfilerELT2FastPathEnterEnabled())
10210         {
10211             g_profControlBlock.pProfInterface->GetEnter2Hook()(
10212                 functionId,
10213                 clientData, 
10214                 NULL,
10215                 NULL);
10216             goto LExit;
10217         }
10218
10219         //
10220         // Whidbey Slow-Path ELT
10221         //
10222         ProfileSetFunctionIDInPlatformSpecificHandle(platformSpecificHandle, functionId);
10223
10224         COR_PRF_FRAME_INFO frameInfo = NULL;
10225         COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo = NULL;
10226         ULONG ulArgInfoSize = 0;
10227
10228         if (CORProfilerFunctionArgsEnabled())
10229         {
10230             // The loader won't trigger a GC or throw for already loaded argument types.
10231             ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
10232
10233             //
10234             // Find the method this is referring to, so we can get the signature
10235             //
10236             MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
10237             MetaSig metaSig(pMethodDesc);
10238
10239             NewHolder<ProfileArgIterator> pProfileArgIterator;
10240
10241             {
10242                 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
10243                 FAULT_NOT_FATAL();
10244
10245                 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, platformSpecificHandle);
10246
10247                 if (pProfileArgIterator == NULL)
10248                 {
10249                     goto LExit;
10250                 }
10251             }
10252
10253             ULONG32 count = pProfileArgIterator->GetNumArgs();
10254
10255             if (metaSig.HasThis())
10256             {
10257                 count++;
10258             }
10259             
10260             ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE);
10261             pArgumentInfo = (COR_PRF_FUNCTION_ARGUMENT_INFO *)_alloca(ulArgInfoSize);
10262         }
10263
10264         HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo);
10265
10266         _ASSERTE(hr == S_OK);
10267         g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
10268
10269         goto LExit;
10270     }
10271
10272
10273     // We will not be here unless the jit'd or ngen'd function we're about to enter
10274     // was backpatched with this wrapper around the profiler's hook, and that
10275     // wouldn't have happened unless the profiler supplied us with a hook
10276     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10277     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10278     // its mind about where the hooks are.)
10279     _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL);
10280
10281     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10282     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10283     // to enable the jitter to add enter/leave callouts independently of whether
10284     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10285     // the callouts quickly return and do nothing.)
10286
10287     //
10288     // Everett ELT
10289     //
10290     {
10291         g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData);
10292     }
10293
10294 LExit:
10295     ;
10296
10297     HELPER_METHOD_FRAME_END();      // Un-link the frame
10298
10299 #endif // PROFILING_SUPPORTED
10300 }
10301 HCIMPLEND
10302
10303 HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecificHandle)
10304 {
10305     FCALL_CONTRACT;
10306
10307     FC_GC_POLL_NOT_NEEDED();            // we pulse GC mode, so we are doing a poll
10308
10309 #ifdef PROFILING_SUPPORTED
10310
10311 #ifdef PROF_TEST_ONLY_FORCE_ELT
10312     // If this test-only flag is set, it's possible we might not have a profiler
10313     // attached, or might not have any of the hooks set. See
10314     // code:ProfControlBlock#TestOnlyELT
10315     if (g_profControlBlock.fTestOnlyForceEnterLeave)
10316     {
10317         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10318             (
10319                 (g_profControlBlock.pProfInterface->GetLeaveHook()          == NULL) &&
10320                 (g_profControlBlock.pProfInterface->GetLeave2Hook()         == NULL) &&
10321                 (g_profControlBlock.pProfInterface->GetLeave3Hook()         == NULL) &&
10322                 (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL)
10323             )
10324            )
10325         {
10326             return;
10327         }
10328     }
10329 #endif // PROF_TEST_ONLY_FORCE_ELT
10330
10331     // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10332     _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL);
10333     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10334     _ASSERTE(platformSpecificHandle != NULL);
10335
10336     // Set up a frame
10337     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2); 
10338
10339     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10340     // frame, like we're about to do.
10341     SetCallbackStateFlagsHolder csf(
10342         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10343     
10344     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10345     eltInfo.platformSpecificHandle = platformSpecificHandle;
10346     
10347     //
10348     // CLR v4 Slow-Path ELT
10349     //
10350     if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL)
10351     {
10352         FunctionIDOrClientID functionIDOrClientID;
10353         functionIDOrClientID.clientID = clientData;
10354         g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()(
10355             functionIDOrClientID, 
10356             (COR_PRF_ELT_INFO)&eltInfo);
10357         goto LExit;
10358     }
10359
10360     if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL)
10361     {
10362         // We have run out of heap memory, so the content of the mapping table becomes stale.
10363         // All Whidbey ETL hooks must be turned off.
10364         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10365         {
10366             goto LExit;
10367         }
10368
10369         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10370         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10371         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10372         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10373         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10374         FunctionID functionId = clientData;
10375         _ASSERTE(functionId != NULL);
10376         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10377
10378         //
10379         // Whidbey Fast-Path ELT
10380         //
10381         if (CORProfilerELT2FastPathLeaveEnabled())
10382         {
10383             g_profControlBlock.pProfInterface->GetLeave2Hook()(
10384                 functionId,
10385                 clientData, 
10386                 NULL,
10387                 NULL);
10388             goto LExit;
10389         }
10390
10391         //
10392         // Whidbey Slow-Path ELT
10393         //
10394         COR_PRF_FRAME_INFO frameInfo = NULL;
10395         COR_PRF_FUNCTION_ARGUMENT_RANGE argumentRange;
10396
10397         HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange);
10398         _ASSERTE(hr == S_OK);
10399
10400         g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
10401         goto LExit;
10402     }
10403
10404     // We will not be here unless the jit'd or ngen'd function we're about to leave
10405     // was backpatched with this wrapper around the profiler's hook, and that
10406     // wouldn't have happened unless the profiler supplied us with a hook
10407     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10408     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10409     // its mind about where the hooks are.)
10410     _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL);
10411
10412     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10413     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10414     // to enable the jitter to add enter/leave callouts independently of whether
10415     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10416     // the callouts quickly return and do nothing.)
10417
10418     //
10419     // Everett ELT
10420     //
10421     {
10422         g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData);
10423     }
10424
10425 LExit:
10426
10427     ;
10428
10429     HELPER_METHOD_FRAME_END();      // Un-link the frame
10430
10431 #endif // PROFILING_SUPPORTED
10432 }
10433 HCIMPLEND
10434
10435 HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpecificHandle)
10436 {
10437     FCALL_CONTRACT;
10438
10439     FC_GC_POLL_NOT_NEEDED();            // we pulse GC mode, so we are doing a poll
10440
10441 #ifdef PROFILING_SUPPORTED
10442
10443 #ifdef PROF_TEST_ONLY_FORCE_ELT
10444     // If this test-only flag is set, it's possible we might not have a profiler
10445     // attached, or might not have any of the hooks set. See
10446     // code:ProfControlBlock#TestOnlyELT
10447     if (g_profControlBlock.fTestOnlyForceEnterLeave)
10448     {
10449         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10450             (
10451                 (g_profControlBlock.pProfInterface->GetTailcallHook()          == NULL) &&
10452                 (g_profControlBlock.pProfInterface->GetTailcall2Hook()         == NULL) &&
10453                 (g_profControlBlock.pProfInterface->GetTailcall3Hook()         == NULL) &&
10454                 (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL)
10455             )
10456            )
10457         {
10458             return;
10459         }
10460     }
10461 #endif // PROF_TEST_ONLY_FORCE_ELT
10462
10463     // ELT3 fast-path hooks should be NULL when ELT intermediary is used.
10464     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL);
10465     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10466     _ASSERTE(platformSpecificHandle != NULL);
10467
10468     // Set up a frame
10469     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10470
10471     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10472     // frame, like we're about to do.
10473     SetCallbackStateFlagsHolder csf(
10474         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10475     
10476     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10477     eltInfo.platformSpecificHandle = platformSpecificHandle;
10478
10479     //
10480     // CLR v4 Slow-Path ELT
10481     //
10482     if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL)
10483     {
10484         FunctionIDOrClientID functionIDOrClientID;
10485         functionIDOrClientID.clientID = clientData;
10486         g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()(
10487             functionIDOrClientID, 
10488             (COR_PRF_ELT_INFO)&eltInfo);
10489         goto LExit;
10490     }
10491
10492     if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL)
10493     {
10494         // We have run out of heap memory, so the content of the mapping table becomes stale.
10495         // All Whidbey ETL hooks must be turned off.
10496         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10497         {
10498             goto LExit;
10499         }
10500
10501         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10502         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10503         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10504         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10505         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10506         FunctionID functionId = clientData;
10507         _ASSERTE(functionId != NULL);
10508         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10509
10510         //
10511         // Whidbey Fast-Path ELT
10512         //
10513         if (CORProfilerELT2FastPathTailcallEnabled())
10514         {
10515             g_profControlBlock.pProfInterface->GetTailcall2Hook()(
10516                 functionId,
10517                 clientData, 
10518                 NULL);
10519             goto LExit;
10520         }
10521
10522         //
10523         // Whidbey Slow-Path ELT
10524         //
10525         COR_PRF_FRAME_INFO frameInfo = NULL;
10526
10527         HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo);
10528         _ASSERTE(hr == S_OK);
10529
10530         g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
10531         goto LExit;
10532     }
10533
10534     // We will not be here unless the jit'd or ngen'd function we're about to tailcall
10535     // was backpatched with this wrapper around the profiler's hook, and that
10536     // wouldn't have happened unless the profiler supplied us with a hook
10537     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10538     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10539     // its mind about where the hooks are.)
10540     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL);
10541
10542     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10543     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10544     // to enable the jitter to add enter/leave callouts independently of whether
10545     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10546     // the callouts quickly return and do nothing.)
10547     
10548     //
10549     // Everett ELT
10550     //
10551     g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData);
10552
10553 LExit:
10554
10555     ;
10556
10557     HELPER_METHOD_FRAME_END();      // Un-link the frame
10558
10559 #endif // PROFILING_SUPPORTED
10560 }
10561 HCIMPLEND
10562