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// COM+99 Debug Interface Header
6//
7
8
9
10#ifndef _dbgInterface_h_
11#define _dbgInterface_h_
12
13#include "common.h"
14#include "eedbginterface.h"
15#include "corjit.h"
16#include "../debug/inc/dbgipcevents.h"
17#include "primitives.h"
18
19typedef DPTR(struct ICorDebugInfo::NativeVarInfo) PTR_NativeVarInfo;
20
21typedef void (*FAVORCALLBACK)(void *);
22
23//
24// The purpose of this object is to serve as an entry point to the
25// debugger, which used to reside in a seperate DLL.
26//
27
28class DebugInterface
29{
30 VPTR_BASE_VTABLE_CLASS_AND_CTOR(DebugInterface);
31
32public:
33
34 //
35 // Functions exported from the debugger to the EE.
36 //
37
38#ifndef DACCESS_COMPILE
39
40 virtual HRESULT Startup(void) = 0;
41
42 virtual HRESULT StartupPhase2(Thread * pThread) = 0;
43
44 // Some callers into the debugger (e.g., ETW rundown) know they will need the lazy
45 // data initialized but cannot afford to have it initialized unpredictably or inside a
46 // lock. They can use this function to force the data to be initialized at a
47 // controlled point in time
48 virtual void InitializeLazyDataIfNecessary() = 0;
49
50 virtual void SetEEInterface(EEDebugInterface* i) = 0;
51
52 virtual void StopDebugger(void) = 0;
53
54 virtual BOOL IsStopped(void) = 0;
55
56 virtual void ThreadCreated(Thread* pRuntimeThread) = 0;
57
58 virtual void ThreadStarted(Thread* pRuntimeThread) = 0;
59
60 virtual void DetachThread(Thread *pRuntimeThread) = 0;
61
62 // Called when a module is being loaded into an AppDomain.
63 // This includes when a domain neutral module is loaded into a new AppDomain.
64 // This is called only when a debugger is attached, and will occur after the
65 // related LoadAssembly and AddAppDomainToIPCBlock calls and before any
66 // LoadClass calls for this module.
67 virtual void LoadModule(Module * pRuntimeModule, // the module being loaded
68 LPCWSTR psModuleName, // module file name
69 DWORD dwModuleName, // number of characters in file name excludign null
70 Assembly * pAssembly, // the assembly the module belongs to
71 AppDomain * pAppDomain, // the AppDomain the module is being loaded into
72 DomainFile * pDomainFile,
73 BOOL fAttaching) = 0; // true if this notification is due to a debugger
74 // being attached to the process
75
76 // Called AFTER LoadModule, and after the module has reached FILE_LOADED. This lets
77 // dbgapi do any processing that needs to wait until the FILE_LOADED stage (e.g.,
78 // binding breakpoints in NGENd generics).
79 virtual void LoadModuleFinished(Module * pModule, AppDomain * pAppDomain) = 0;
80
81 // Called for all modules in an AppDomain when the AppDomain is unloaded.
82 // This includes domain neutral modules that are also loaded into other domains.
83 // This is called only when a debugger is attached, and will occur after all UnloadClass
84 // calls and before any UnloadAssembly or RemoveAppDomainFromIPCBlock calls realted
85 // to this module. On CLR shutdown, we are not guarenteed to get UnloadModule calls for
86 // all outstanding loaded modules.
87 virtual void UnloadModule(Module* pRuntimeModule, AppDomain *pAppDomain) = 0;
88
89 // Called when a Module* is being destroyed.
90 // Specifically, the Module has completed unloading (which may have been done asyncronously), all resources
91 // associated are being freed, and the Module* is about to become invalid. The debugger should remove all
92 // references to this Module*.
93 // NOTE: This is called REGARDLESS of whether a debugger is attached or not, and will occur after any other
94 // notifications about this module (including any RemoveAppDomainFromIPCBlock call indicating the module's
95 // domain has been unloaded).
96 virtual void DestructModule(Module *pModule) = 0;
97
98 virtual BOOL LoadClass(TypeHandle th,
99 mdTypeDef classMetadataToken,
100 Module *classModule,
101 AppDomain *pAppDomain) = 0;
102
103 virtual void UnloadClass(mdTypeDef classMetadataToken,
104 Module *classModule,
105 AppDomain *pAppDomain) = 0;
106
107 // Filter we call in 1st-pass to dispatch a CHF callback.
108 // pCatchStackAddress really should be a Frame* onto the stack. That way the CHF stack address
109 // and the debugger's stacktrace Frames will match up.
110 // This is only called by stubs.
111 virtual LONG NotifyOfCHFFilter(EXCEPTION_POINTERS* pExceptionPointers, PVOID pCatchStackAddr) = 0;
112
113
114 virtual bool FirstChanceNativeException(EXCEPTION_RECORD *exception,
115 CONTEXT *context,
116 DWORD code,
117 Thread *thread) = 0;
118
119 // pThread is thread that exception is on.
120 // currentSP is stack frame of the throw site.
121 // currentIP is ip of the throw site.
122 // pStubFrame = NULL if the currentSp is for a non-stub frame (ie, a regular JITed catched).
123 // For stub-based throws, pStubFrame is the EE Frame of the stub.
124 virtual bool FirstChanceManagedException(Thread *pThread, SIZE_T currentIP, SIZE_T currentSP) = 0;
125
126 virtual void FirstChanceManagedExceptionCatcherFound(Thread *pThread,
127 MethodDesc *pMD, TADDR pMethodAddr,
128 BYTE *currentSP,
129 EE_ILEXCEPTION_CLAUSE *pEHClause) = 0;
130
131 virtual LONG LastChanceManagedException(EXCEPTION_POINTERS * pExceptionInfo,
132 Thread *thread,
133 BOOL jitAttachRequested) = 0;
134
135 virtual void ManagedExceptionUnwindBegin(Thread *pThread) = 0;
136
137 virtual void DeleteInterceptContext(void *pContext) = 0;
138
139 virtual void ExceptionFilter(MethodDesc *fd, TADDR pMethodAddr,
140 SIZE_T offset,
141 BYTE *pStack) = 0;
142
143 virtual void ExceptionHandle(MethodDesc *fd, TADDR pMethodAddr,
144 SIZE_T offset,
145 BYTE *pStack) = 0;
146
147 virtual void SendUserBreakpoint(Thread *thread) = 0;
148
149 // Send an UpdateModuleSyms event, and block waiting for the debugger to continue it.
150 virtual void SendUpdateModuleSymsEventAndBlock(Module *pRuntimeModule,
151 AppDomain *pAppDomain) = 0;
152
153 //
154 // RequestFavor gets the debugger helper thread to call a function. It's
155 // typically called when the current thread can't call the function directly,
156 // e.g, there isn't enough stack space.
157 //
158 // RequestFavor ensures that the helper thread has been initialized to
159 // execute favors and then calls Debugger:DoFavor. It blocks until the
160 // favor callback completes.
161 //
162 // Parameters:
163 // fp - Favour callback function
164 // pData - the parameter passed to the favor callback function.
165 //
166 // Return values:
167 // S_OK if the function succeeds, else a failure HRESULT
168 //
169 virtual HRESULT RequestFavor(FAVORCALLBACK fp, void * pData) = 0;
170
171#endif // #ifndef DACCESS_COMPILE
172
173 // JITComplete() is called after a method is jit-compiled, successfully or not
174
175#ifndef DACCESS_COMPILE
176
177 virtual void JITComplete(MethodDesc* fd, TADDR newAddress) = 0;
178
179 //
180 // EnC functions
181 //
182#ifdef EnC_SUPPORTED
183 // Notify that an existing method has been edited in a loaded type
184 virtual HRESULT UpdateFunction(MethodDesc* md, SIZE_T enCVersion) = 0;
185
186 // Notify that a new method has been added to a loaded type
187 virtual HRESULT AddFunction(MethodDesc* md, SIZE_T enCVersion) = 0;
188
189 virtual HRESULT UpdateNotYetLoadedFunction(mdMethodDef token, Module * pModule, SIZE_T enCVersion) = 0;
190
191 // Notify that a field has been added
192 virtual HRESULT AddField(FieldDesc* fd, SIZE_T enCVersion) = 0;
193
194 // Notify that the EE has completed the remap and is about to resume execution
195 virtual HRESULT RemapComplete(MethodDesc *pMd, TADDR addr, SIZE_T nativeOffset) = 0;
196
197 // Used by the codemanager FixContextForEnC() to update
198 virtual HRESULT MapILInfoToCurrentNative(MethodDesc *pMD,
199 SIZE_T ilOffset,
200 TADDR nativeFnxStart,
201 SIZE_T *nativeOffset) = 0;
202#endif // EnC_SUPPORTED
203
204 // Get debugger variable information for a specific version of a method
205 virtual void GetVarInfo(MethodDesc * fd, // [IN] method of interest
206 void *DebuggerVersionToken, // [IN] which edit version
207 SIZE_T * cVars, // [OUT] size of 'vars'
208 const ICorDebugInfo::NativeVarInfo **vars // [OUT] map telling where local vars are stored
209 ) = 0;
210
211 virtual void getBoundaries(MethodDesc * ftn,
212 unsigned int *cILOffsets, DWORD **pILOffsets,
213 ICorDebugInfo::BoundaryTypes* implictBoundaries) = 0;
214
215 virtual void getVars(MethodDesc * ftn,
216 ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
217 bool *extendOthers) = 0;
218
219 virtual BOOL CheckGetPatchedOpcode(CORDB_ADDRESS_TYPE *address, /*OUT*/ PRD_TYPE *pOpcode) = 0;
220
221 virtual PRD_TYPE GetPatchedOpcode(CORDB_ADDRESS_TYPE *ip) = 0;
222
223 virtual void TraceCall(const BYTE *target) = 0;
224
225 virtual bool ThreadsAtUnsafePlaces(void) = 0;
226
227 virtual HRESULT LaunchDebuggerForUser(Thread * pThread, EXCEPTION_POINTERS * pExceptionInfo, BOOL sendManagedEvent, BOOL explicitUserRequest) = 0;
228
229 // Launches a debugger and waits for it to attach
230 virtual void JitAttach(Thread * pThread, EXCEPTION_POINTERS * pExceptionInfo, BOOL willSendManagedEvent, BOOL explicitUserRequest) = 0;
231
232 // Prepares for a jit attach and decides which of several potentially
233 // racing threads get to launch the debugger
234 virtual BOOL PreJitAttach(BOOL willSendManagedEvent, BOOL willLaunchDebugger, BOOL explicitUserRequest) = 0;
235
236 // Waits for a jit attach to complete
237 virtual void WaitForDebuggerAttach() = 0;
238
239 // Completes the jit attach, unblocking all threads waiting for attach,
240 // regardless of whether or not the debugger actually attached
241 virtual void PostJitAttach() = 0;
242
243 virtual void SendUserBreakpointAndSynchronize(Thread * pThread) = 0;
244
245 virtual void SendLogMessage(int iLevel,
246 SString * pSwitchName,
247 SString * pMessage) = 0;
248
249 // send a custom notification from the target to the RS. This will become an ICorDebugThread and
250 // ICorDebugAppDomain on the RS.
251 virtual void SendCustomDebuggerNotification(Thread * pThread, DomainFile * pDomainFile, mdTypeDef classToken) = 0;
252
253 // Send an MDA notification. This ultimately translates to an ICorDebugMDA object on the Right-Side.
254 virtual void SendMDANotification(
255 Thread * pThread, // may be NULL. Lets us send on behalf of other threads.
256 SString * szName,
257 SString * szDescription,
258 SString * szXML,
259 CorDebugMDAFlags flags,
260 BOOL bAttach
261 ) = 0;
262
263 virtual bool IsJMCMethod(Module* pModule, mdMethodDef tkMethod) = 0;
264
265 // Given a method, get's its EnC version number. 1 if the method is not EnCed.
266 // Note that MethodDescs are reused between versions so this will give us
267 // the most recent EnC number.
268 virtual int GetMethodEncNumber(MethodDesc * pMethod) = 0;
269
270 virtual void SendLogSwitchSetting (int iLevel,
271 int iReason,
272 __in_z LPCWSTR pLogSwitchName,
273 __in_z LPCWSTR pParentSwitchName) = 0;
274
275 virtual bool IsLoggingEnabled (void) = 0;
276
277 virtual bool GetILOffsetFromNative (MethodDesc *PFD,
278 const BYTE *pbAddr,
279 DWORD nativeOffset,
280 DWORD *ilOffset) = 0;
281
282 virtual HRESULT GetILToNativeMapping(PCODE pNativeCodeStartAddress,
283 ULONG32 cMap,
284 ULONG32 *pcMap,
285 COR_DEBUG_IL_TO_NATIVE_MAP map[]) = 0;
286
287 virtual HRESULT GetILToNativeMappingIntoArrays(
288 MethodDesc * pMethodDesc,
289 PCODE pCode,
290 USHORT cMapMax,
291 USHORT * pcMap,
292 UINT ** prguiILOffset,
293 UINT ** prguiNativeOffset) = 0;
294
295 virtual DWORD GetHelperThreadID(void ) = 0;
296
297 // Called whenever a new AppDomain is created, regardless of whether a debugger is attached.
298 // This will be called before any LoadAssembly calls for assemblies in this domain.
299 virtual HRESULT AddAppDomainToIPC (AppDomain *pAppDomain) = 0;
300
301 // Called whenever an AppDomain is unloaded, regardless of whether a Debugger is attached
302 // This will occur after any UnloadAssembly and UnloadModule callbacks for this domain (if any).
303 virtual HRESULT RemoveAppDomainFromIPC (AppDomain *pAppDomain) = 0;
304
305 virtual HRESULT UpdateAppDomainEntryInIPC (AppDomain *pAppDomain) = 0;
306
307 // Called when an assembly is being loaded into an AppDomain.
308 // This includes when a domain neutral assembly is loaded into a new AppDomain.
309 // This is called only when a debugger is attached, and will occur after the
310 // related AddAppDomainToIPCBlock call and before any LoadModule or
311 // LoadClass calls for this assembly.
312 virtual void LoadAssembly(DomainAssembly * pDomainAssembly) = 0; // the assembly being loaded
313
314
315 // Called for all assemblies in an AppDomain when the AppDomain is unloaded.
316 // This includes domain neutral assemblies that are also loaded into other domains.
317 // This is called only when a debugger is attached, and will occur after all UnloadClass
318 // and UnloadModule calls and before any RemoveAppDomainFromIPCBlock calls realted
319 // to this assembly. On CLR shutdown, we are not guarenteed to get UnloadAssembly calls for
320 // all outstanding loaded assemblies.
321 virtual void UnloadAssembly(DomainAssembly * pDomainAssembly) = 0;
322
323 virtual HRESULT SetILInstrumentedCodeMap(MethodDesc *fd,
324 BOOL fStartJit,
325 ULONG32 cILMapEntries,
326 COR_IL_MAP rgILMapEntries[]) = 0;
327
328 virtual void EarlyHelperThreadDeath(void) = 0;
329
330 virtual void ShutdownBegun(void) = 0;
331
332 virtual void LockDebuggerForShutdown(void) = 0;
333
334 virtual void DisableDebugger(void) = 0;
335
336 virtual HRESULT NameChangeEvent(AppDomain *pAppDomain,
337 Thread *pThread) = 0;
338
339 // send an event to the RS indicating that there's a Ctrl-C or Ctrl-Break
340 virtual BOOL SendCtrlCToDebugger(DWORD dwCtrlType) = 0;
341
342 // Allows the debugger to keep an up to date list of special threads
343 virtual HRESULT UpdateSpecialThreadList(DWORD cThreadArrayLength,
344 DWORD *rgdwThreadIDArray) = 0;
345
346 // Updates the pointer for the debugger services
347 virtual void SetIDbgThreadControl(IDebuggerThreadControl *pIDbgThreadControl) = 0;
348
349 virtual DWORD GetRCThreadId(void) = 0;
350
351 virtual HRESULT GetVariablesFromOffset(MethodDesc *pMD,
352 UINT varNativeInfoCount,
353 ICorDebugInfo::NativeVarInfo *varNativeInfo,
354 SIZE_T offsetFrom,
355 CONTEXT *pCtx,
356 SIZE_T *rgVal1,
357 SIZE_T *rgVal2,
358 UINT uRgValSize,
359 BYTE ***rgpVCs) = 0;
360
361 virtual HRESULT SetVariablesAtOffset(MethodDesc *pMD,
362 UINT varNativeInfoCount,
363 ICorDebugInfo::NativeVarInfo *varNativeInfo,
364 SIZE_T offsetTo,
365 CONTEXT *pCtx,
366 SIZE_T *rgVal1,
367 SIZE_T *rgVal2,
368 BYTE **rgpVCs) = 0;
369
370 virtual BOOL IsThreadContextInvalid(Thread *pThread) = 0;
371
372 // For Just-My-Code (aka Just-User-Code).
373 // The jit inserts probes that look like.
374 // if (*pAddr != 0) call g_pDebugInterface->OnMethodEnter()
375
376 // Invoked when we enter a user method.
377 // pIP is an ip within the method, right after the prolog.
378 virtual void OnMethodEnter(void * pIP) = 0;
379
380 // Given a method, the debugger provides the address of the flag.
381 // This allows the debugger to store the flag whereever it wants
382 // and with whatever granularity (per-module, per-class, per-function, etc).
383 virtual DWORD* GetJMCFlagAddr(Module * pModule) = 0;
384
385 // notification for SQL fiber debugging support
386 virtual void CreateConnection(CONNID dwConnectionId, __in_z WCHAR *wzName) = 0;
387 virtual void DestroyConnection(CONNID dwConnectionId) = 0;
388 virtual void ChangeConnection(CONNID dwConnectionId) = 0;
389
390 //
391 // This function is used to identify the helper thread.
392 //
393 virtual bool ThisIsHelperThread(void) = 0;
394
395 virtual HRESULT ReDaclEvents(PSECURITY_DESCRIPTOR securityDescriptor) = 0;
396
397 virtual BOOL ShouldAutoAttach() = 0;
398 virtual BOOL FallbackJITAttachPrompt() = 0;
399 virtual HRESULT SetFiberMode(bool isFiberMode) = 0;
400
401#ifdef FEATURE_INTEROP_DEBUGGING
402 virtual LONG FirstChanceSuspendHijackWorker(PCONTEXT pContext, PEXCEPTION_RECORD pExceptionRecord) = 0;
403#endif
404
405#endif // #ifndef DACCESS_COMPILE
406
407#ifdef DACCESS_COMPILE
408 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
409 virtual void EnumMemoryRegionsIfFuncEvalFrame(CLRDataEnumMemoryFlags flags, Frame * pFrame) = 0;
410#endif
411#ifndef DACCESS_COMPILE
412 virtual void SuspendForGarbageCollectionStarted() = 0;
413 virtual void SuspendForGarbageCollectionCompleted() = 0;
414 virtual void ResumeForGarbageCollectionStarted() = 0;
415#endif
416 virtual BOOL IsSynchronizing() = 0;
417};
418
419#ifndef DACCESS_COMPILE
420// Helper to make GCC compile. GCC can't handle putting a virtual call in a filter.
421struct NotifyOfCHFFilterWrapperParam { void *pFrame; };
422LONG NotifyOfCHFFilterWrapper(EXCEPTION_POINTERS *pExceptionInfo, PVOID pNotifyOfCHFFilterWrapperParam);
423#endif
424
425
426#endif // _dbgInterface_h_
427