Add check to prevent attaching a profiler when one is already present (#25520)
[platform/upstream/coreclr.git] / src / inc / profilepriv.h
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 // ProfilePriv.h
6 // 
7
8 //
9 // Structures, etc. used by the Profiling API and throughout the EE
10 // 
11
12 // ======================================================================================
13
14 #ifndef _ProfilePriv_h_
15 #define _ProfilePriv_h_
16
17
18 // Forward declarations
19 class EEToProfInterfaceImpl;
20 class Object;
21 struct ScanContext;
22
23 #if defined (PROFILING_SUPPORTED_DATA) || defined(PROFILING_SUPPORTED)
24 #ifndef PROFILING_SUPPORTED_DATA
25 #define PROFILING_SUPPORTED_DATA 1
26 #endif  // PROFILING_SUPPORTED_DATA
27
28 #include "corprof.h"
29
30 //---------------------------------------------------------------------------------------
31 // Enumerates the various init states of profiling.
32 // 
33 // *** NOTE: The order is important here, as some of the status checks (e.g.,
34 // CORProfilerPresentOrInitializing) use ">" with these enum values. ***
35
36 enum ProfilerStatus
37 {
38     kProfStatusNone                        = 0, // No profiler running.
39     kProfStatusDetaching                   = 1, // Prof was running, is now detaching, but still loaded
40     kProfStatusInitializingForStartupLoad  = 2, // Prof ready for (or in) its Initialize callback
41     kProfStatusInitializingForAttachLoad   = 3, // Prof ready for (or in) its InitializeForAttach callback
42     kProfStatusActive                      = 4, // Prof completed initialization and is actively running
43     kProfStatusPreInitialize               = 5, // Prof is in LoadProfiler, but initialization has yet to occur
44 };
45
46 class CurrentProfilerStatus
47 {
48 private:
49     // Why volatile?
50     // See code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
51     Volatile<ProfilerStatus> m_profStatus;
52
53 public:
54     void Init();
55     ProfilerStatus Get();
56     void Set(ProfilerStatus profStatus);
57 };
58
59 // ---------------------------------------------------------------------------------------
60 // Global struct that lets the EE see the load status of the profiler, and provides a
61 // pointer (pProfInterface) through which profiler calls can be made
62 //
63 // When you are adding new session, please refer to 
64 // code:ProfControlBlock::ResetPerSessionStatus#ProfileResetSessionStatus for more details.
65 struct ProfControlBlock
66 {
67     // **** IMPORTANT!! ****
68     // All uses of pProfInterface must be properly synchronized to avoid the profiler
69     // from detaching while the EE attempts to call into it.  The recommended way to do
70     // this is to use the (lockless) BEGIN_PIN_PROFILER / END_PIN_PROFILER macros.  See
71     // code:BEGIN_PIN_PROFILER for instructions.  For full details on how the
72     // synchronization works, see
73     // code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization
74     VolatilePtr<EEToProfInterfaceImpl> pProfInterface;
75     // **** IMPORTANT!! ****
76     
77     DWORD dwEventMask;          // Original low event mask bits
78     DWORD dwEventMaskHigh;      // New high event mask bits
79     CurrentProfilerStatus curProfStatus;
80     BOOL fGCInProgress;
81     BOOL fBaseSystemClassesLoaded;
82
83 #ifdef PROF_TEST_ONLY_FORCE_ELT_DATA
84     // #TestOnlyELT This implements a test-only (and debug-only) hook that allows a test
85     // profiler to ensure enter/leave/tailcall is enabled on startup even though no
86     // profiler is loaded on startup. This allows an attach profiler to use ELT to build
87     // shadow stacks for the sole purpose of verifying OTHER areas of the profiling API
88     // (e.g., stack walking). When this BOOL is TRUE, the JIT will insert calls to the
89     // slow-path profiling API enter/leave/tailcall hooks, which will forward the call to
90     // a profiler if one is loaded (and do nothing otherwise).
91     // 
92     // See code:AreCallbackStateFlagsSet#P2CLRRestrictionsOverview for general information
93     // on how the test hooks lift restrictions normally in place for the Info functions.
94     BOOL fTestOnlyForceEnterLeave;
95 #endif
96
97 #ifdef PROF_TEST_ONLY_FORCE_OBJECT_ALLOCATED_DATA
98     // #TestOnlyObjectAllocated This implements a test-only (and debug-only) hook that allows
99     // a test profiler to ensure ObjectAllocated callback is enabled on startup even though no
100     // profiler is loaded on startup. This allows an attach profiler to use ObjectAllocated 
101     // callback for the sole purpose of verifying OTHER GC areas of the profiling API
102     // (e.g., constructing a object graph). When this BOOL is TRUE, the JIT will use special 
103     // version of new allocators that issue object allocation notifications, which will forward 
104     // the notifications to a profiler if one is loaded (and do nothing otherwise).
105     // 
106     // See code:AreCallbackStateFlagsSet#P2CLRRestrictionsOverview for general information
107     // on how the test hooks lift restrictions normally in place for the Info functions.
108     BOOL fTestOnlyForceObjectAllocated;
109 #endif 
110
111 #ifdef _DEBUG
112     // Test-only, debug-only code to allow attaching profilers to call ICorProfilerInfo inteface,  
113     // which would otherwise be disallowed for attaching profilers
114     BOOL                    fTestOnlyEnableICorProfilerInfo;
115 #endif // _DEBUG
116
117     // Whether we've turned off concurrent GC during attach
118     BOOL fConcurrentGCDisabledForAttach;
119
120     Volatile<BOOL> fProfControlBlockInitialized;
121
122     Volatile<BOOL> fProfilerRequestedRuntimeSuspend;
123     
124     void Init();
125     void ResetPerSessionStatus();    
126 };
127
128
129 GVAL_DECL(ProfControlBlock, g_profControlBlock);
130
131 // Provides definitions of the CORProfilerTrack* functions that test whether a profiler
132 // is active and responding to various callbacks
133 #include "profilepriv.inl"
134
135 //---------------------------------------------------------------
136 // Bit flags used to track profiler callback execution state, such as which
137 // ICorProfilerCallback method we're currently executing. These help us enforce the
138 // invariants of which calls a profiler is allowed to make at given times. These flags
139 // are stored in Thread::m_profilerCallbackState.
140 //
141 // For now, we ensure:
142 //     * Only asynchronous-safe calls are made asynchronously (i.e., are made from
143 //         outside of profiler callbacks).
144 //     * GC_TRIGGERS info methods are not called from GC_NOTRIGGER callbacks
145 //
146 // Later, we may choose to enforce even more refined call trees and add more flags.
147 #define COR_PRF_CALLBACKSTATE_INCALLBACK                 0x1
148 #define COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE          0x2
149 #define COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED         0x4
150 #define COR_PRF_CALLBACKSTATE_REJIT_WAS_CALLED           0x8
151 //
152 //---------------------------------------------------------------
153
154 #endif // defined(PROFILING_SUPPORTED_DATA) || defined(PROFILING_SUPPORTED)
155
156 // This is the helper callback that the gc uses when walking the heap.
157 bool HeapWalkHelper(Object* pBO, void* pv);
158 void ScanRootsHelper(Object* pObj, Object** ppRoot, ScanContext *pSC, uint32_t dwUnused);
159 bool AllocByClassHelper(Object* pBO, void* pv);
160
161 #endif  // _ProfilePriv_h_
162