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 | * DbgIPCEvents.h -- header file for private Debugger data shared by various |
6 | // |
7 | |
8 | * debugger components. |
9 | * ------------------------------------------------------------------------- */ |
10 | |
11 | #ifndef _DbgIPCEvents_h_ |
12 | #define _DbgIPCEvents_h_ |
13 | |
14 | #include <new.hpp> |
15 | #include <cor.h> |
16 | #include <cordebug.h> |
17 | #include <corjit.h> // for ICorDebugInfo::VarLocType & VarLoc |
18 | #include <specstrings.h> |
19 | |
20 | #include "dbgtargetcontext.h" |
21 | |
22 | |
23 | // Get version numbers for IPCHeader stamp |
24 | #include "ndpversion.h" |
25 | |
26 | #include "dbgappdomain.h" |
27 | |
28 | #include "./common.h" |
29 | |
30 | //----------------------------------------------------------------------------- |
31 | // V3 additions to IPC protocol between LS and RS. |
32 | //----------------------------------------------------------------------------- |
33 | |
34 | // Special Exception code for LS to communicate with RS. |
35 | // LS will raise this exception to communicate managed debug events to the RS. |
36 | // Exception codes can't use bit 0x10000000, that's reserved by OS. |
37 | #define CLRDBG_NOTIFICATION_EXCEPTION_CODE ((DWORD) 0x04242420) |
38 | |
39 | // This is exception argument 0 included in debugger notification events. |
40 | // The debugger uses this as a sanity check. |
41 | // This could be very volatile data that changes between builds. |
42 | #define CLRDBG_EXCEPTION_DATA_CHECKSUM ((DWORD) 0x31415927) |
43 | |
44 | |
45 | // Reasons for hijack. |
46 | namespace EHijackReason |
47 | { |
48 | enum EHijackReason |
49 | { |
50 | kUnhandledException = 1, |
51 | kM2UHandoff = 2, |
52 | kFirstChanceSuspend = 3, |
53 | kGenericHijack = 4, |
54 | kMax |
55 | }; |
56 | inline bool IsValid(EHijackReason value) |
57 | { |
58 | SUPPORTS_DAC; |
59 | return (value > 0) && (value < kMax); |
60 | } |
61 | } |
62 | |
63 | |
64 | |
65 | #define MAX_LOG_SWITCH_NAME_LEN 256 |
66 | |
67 | //----------------------------------------------------------------------------- |
68 | // Versioning note: |
69 | // This file describes the IPC communication protocol between the LS (mscorwks) |
70 | // and the RS (mscordbi). For Desktop builds, it is private and can change on a |
71 | // daily basis. The version of the LS will always match the version of the RS |
72 | // (but see the discussion of CoreCLR below). They are like a single conceptual |
73 | // DLL split across 2 processes. |
74 | // The only restriction is that it should be flavor agnostic - so don't change |
75 | // layout based off '#ifdef DEBUG'. This lets us drop a Debug flavor RS onto |
76 | // a retail installation w/o any further installation woes. That's very useful |
77 | // for debugging. |
78 | //----------------------------------------------------------------------------- |
79 | |
80 | |
81 | // We want this available for DbgInterface.h - put it here. |
82 | typedef enum |
83 | { |
84 | IPC_TARGET_OUTOFPROC, |
85 | IPC_TARGET_COUNT, |
86 | } IpcTarget; |
87 | |
88 | // |
89 | // Names of the setup sync event and shared memory used for IPC between the Left Side and the Right Side. NOTE: these |
90 | // names must include a %d for the process id. The process id used is the process id of the debuggee. |
91 | // |
92 | |
93 | #define CorDBIPCSetupSyncEventName W("CorDBIPCSetupSyncEvent_%d") |
94 | |
95 | // |
96 | // This define controls whether we always pass first chance exceptions to the in-process first chance hijack filter |
97 | // during interop debugging or if we try to short-circuit and make the decision out-of-process as much as possible. |
98 | // |
99 | #define CorDB_Short_Circuit_First_Chance_Ownership 1 |
100 | |
101 | // |
102 | // Defines for current version numbers for the left and right sides |
103 | // |
104 | #define CorDB_LeftSideProtocolCurrent 2 |
105 | #define CorDB_LeftSideProtocolMinSupported 2 |
106 | #define CorDB_RightSideProtocolCurrent 2 |
107 | #define CorDB_RightSideProtocolMinSupported 2 |
108 | |
109 | // |
110 | // The remaining data structures in this file can be shared between two processes and for network transport |
111 | // based debugging this can mean two different platforms as well. The two platforms that can share these |
112 | // data structures must have identical layouts for them (each field must lie at the same offset and have the |
113 | // same length). The MSLAYOUT macro should be applied to each structure to avoid any compiler packing differences. |
114 | // |
115 | |
116 | // |
117 | // DebuggerIPCRuntimeOffsets contains addresses and offsets of important global variables, functions, and fields in |
118 | // Runtime objects. This is populated during Left Side initialization and is read by the Right Side. This struct is |
119 | // mostly to facilitate unmanaged debugging support, but it may have some small uses for managed debugging. |
120 | // |
121 | struct MSLAYOUT DebuggerIPCRuntimeOffsets |
122 | { |
123 | #ifdef FEATURE_INTEROP_DEBUGGING |
124 | void *m_genericHijackFuncAddr; |
125 | void *m_signalHijackStartedBPAddr; |
126 | void *m_excepForRuntimeHandoffStartBPAddr; |
127 | void *m_excepForRuntimeHandoffCompleteBPAddr; |
128 | void *m_signalHijackCompleteBPAddr; |
129 | void *m_excepNotForRuntimeBPAddr; |
130 | void *m_notifyRSOfSyncCompleteBPAddr; |
131 | void *m_raiseExceptionAddr; // The address of kernel32!RaiseException in the debuggee |
132 | DWORD m_debuggerWordTLSIndex; // The TLS slot for the debugger word used in the debugger hijack functions |
133 | #endif // FEATURE_INTEROP_DEBUGGING |
134 | SIZE_T m_TLSIndex; // The TLS index the CLR is using to hold Thread objects |
135 | SIZE_T m_TLSIsSpecialIndex; // The index into the Predef block of the the "IsSpecial" status for a thread. |
136 | SIZE_T m_TLSCantStopIndex; // The index into the Predef block of the the Can't-Stop count. |
137 | SIZE_T m_EEThreadStateOffset; // Offset of m_state in a Thread |
138 | SIZE_T m_EEThreadStateNCOffset; // Offset of m_stateNC in a Thread |
139 | SIZE_T m_EEThreadPGCDisabledOffset; // Offset of the bit for whether PGC is disabled or not in a Thread |
140 | DWORD m_EEThreadPGCDisabledValue; // Value at m_EEThreadPGCDisabledOffset that equals "PGC disabled". |
141 | SIZE_T m_EEThreadFrameOffset; // Offset of the Frame ptr in a Thread |
142 | SIZE_T m_EEThreadMaxNeededSize; // Max memory to read to get what we need out of a Thread object |
143 | DWORD m_EEThreadSteppingStateMask; // Mask for Thread::TSNC_DebuggerIsStepping |
144 | DWORD m_EEMaxFrameValue; // The max Frame value |
145 | SIZE_T m_EEThreadDebuggerFilterContextOffset; // Offset of debugger's filter context within a Thread Object. |
146 | SIZE_T m_EEThreadCantStopOffset; // Offset of the can't stop count in a Thread |
147 | SIZE_T m_EEFrameNextOffset; // Offset of the next ptr in a Frame |
148 | DWORD m_EEIsManagedExceptionStateMask; // Mask for Thread::TSNC_DebuggerIsManagedException |
149 | void *m_pPatches; // Addr of patch table |
150 | BOOL *m_pPatchTableValid; // Addr of g_patchTableValid |
151 | SIZE_T m_offRgData; // Offset of m_pcEntries |
152 | SIZE_T m_offCData; // Offset of count of m_pcEntries |
153 | SIZE_T m_cbPatch; // Size per patch entry |
154 | SIZE_T m_offAddr; // Offset within patch of target addr |
155 | SIZE_T m_offOpcode; // Offset within patch of target opcode |
156 | SIZE_T m_cbOpcode; // Max size of opcode |
157 | SIZE_T m_offTraceType; // Offset of the trace.type within a patch |
158 | DWORD m_traceTypeUnmanaged; // TRACE_UNMANAGED |
159 | |
160 | DebuggerIPCRuntimeOffsets() |
161 | { |
162 | ZeroMemory(this, sizeof(DebuggerIPCRuntimeOffsets)); |
163 | } |
164 | }; |
165 | |
166 | // |
167 | // The size of the send and receive IPC buffers. |
168 | // These must be big enough to fit a DebuggerIPCEvent. Also, the bigger they are, the fewer events |
169 | // it takes to send variable length stuff like the stack trace. |
170 | // But for perf reasons, they need to be small enough to not just push us over a page boundary in an IPC block. |
171 | // Unfortunately, there's a lot of other goo in the IPC block, so we can't use some clean formula. So we |
172 | // have to resort to just tuning things. |
173 | // |
174 | |
175 | // When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound |
176 | // for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is |
177 | // orthogonal to the host's page size. Because of this we defer definition of CorDBIPC_BUFFER_SIZE until we've |
178 | // declared DebuggerIPCEvent at the end of this header (and we can do so because in the transport case there |
179 | // aren't any embedded buffers in the DebuggerIPCControlBlock). |
180 | |
181 | #if defined(DBG_TARGET_X86) || defined(DBG_TARGET_ARM) |
182 | #ifdef _WIN64 |
183 | #define CorDBIPC_BUFFER_SIZE 2104 |
184 | #else |
185 | #define CorDBIPC_BUFFER_SIZE 2092 |
186 | #endif |
187 | #else // !_TARGET_X86_ && !_TARGET_ARM_ |
188 | // This is the size of a DebuggerIPCEvent. You will hit an assert in Cordb::Initialize() (di\rsmain.cpp) |
189 | // if this is not defined correctly. AMD64 actually has a page size of 0x1000, not 0x2000. |
190 | #define CorDBIPC_BUFFER_SIZE 4016 // (4016 + 6) * 2 + 148 = 8192 (two (DebuggerIPCEvent + alignment padding) + other fields = page size) |
191 | #endif // DBG_TARGET_X86 || DBG_TARGET_ARM |
192 | |
193 | // |
194 | // DebuggerIPCControlBlock describes the layout of the shared memory shared between the Left Side and the Right |
195 | // Side. This includes error information, handles for the IPC channel, and space for the send/receive buffers. |
196 | // |
197 | struct MSLAYOUT DebuggerIPCControlBlock |
198 | { |
199 | // Version data should be first in the control block to ensure that we can read it even if the control block |
200 | // changes. |
201 | SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized |
202 | ULONG m_verMajor; // CLR build number for the Left Side. |
203 | ULONG m_verMinor; // CLR build number for the Left Side. |
204 | |
205 | // This next stuff fits in a DWORD. |
206 | bool m_checkedBuild; // CLR build type for the Left Side. |
207 | // using the first padding byte to indicate if hosted in fiber mode. |
208 | // We actually just need one bit. So if needed, can turn this to a bit. |
209 | // BYTE padding1; |
210 | bool m_bHostingInFiber; |
211 | BYTE padding2; |
212 | BYTE padding3; |
213 | |
214 | ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side. |
215 | ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support. |
216 | |
217 | ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side. |
218 | ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires. |
219 | |
220 | HRESULT m_errorHR; |
221 | unsigned int m_errorCode; |
222 | |
223 | #if defined(DBG_TARGET_WIN64) |
224 | // 64-bit needs this padding to make the handles after this aligned. |
225 | // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0. |
226 | ULONG padding4; |
227 | #endif // DBG_TARGET_WIN64 |
228 | |
229 | |
230 | RemoteHANDLE m_rightSideEventAvailable; |
231 | RemoteHANDLE m_rightSideEventRead; |
232 | |
233 | // @dbgtodo inspection - this is where LSEA and LSER used to be. We need to the padding to maintain binary compatibility. |
234 | // Eventually, we expect to remove this whole block. |
235 | RemoteHANDLE m_paddingObsoleteLSEA; |
236 | RemoteHANDLE m_paddingObsoleteLSER; |
237 | |
238 | RemoteHANDLE m_rightSideProcessHandle; |
239 | |
240 | //............................................................................. |
241 | // Everything above this point must have the exact same binary layout as v1.1. |
242 | // See protocol details below. |
243 | //............................................................................. |
244 | |
245 | RemoteHANDLE m_leftSideUnmanagedWaitEvent; |
246 | |
247 | |
248 | |
249 | // This is set immediately when the helper thread is created. |
250 | // This will be set even if there's a temporary helper thread or if the real helper |
251 | // thread is not yet pumping (eg, blocked on a loader lock). |
252 | DWORD m_realHelperThreadId; |
253 | |
254 | // This is only published once the helper thread starts running in its main loop. |
255 | // Thus we can use this field to see if the real helper thread is actually pumping. |
256 | DWORD m_helperThreadId; |
257 | |
258 | // This is non-zero if the LS has a temporary helper thread. |
259 | DWORD m_temporaryHelperThreadId; |
260 | |
261 | // ID of the Helper's canary thread. |
262 | DWORD m_CanaryThreadId; |
263 | |
264 | DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets; |
265 | void *m_helperThreadStartAddr; |
266 | void *m_helperRemoteStartAddr; |
267 | DWORD *m_specialThreadList; |
268 | |
269 | BYTE m_receiveBuffer[CorDBIPC_BUFFER_SIZE]; |
270 | BYTE m_sendBuffer[CorDBIPC_BUFFER_SIZE]; |
271 | |
272 | DWORD m_specialThreadListLength; |
273 | bool m_shutdownBegun; |
274 | bool m_rightSideIsWin32Debugger; // RS status |
275 | bool m_specialThreadListDirty; |
276 | |
277 | bool m_rightSideShouldCreateHelperThread; |
278 | |
279 | // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without |
280 | // changing this! |
281 | // Only initialized by the LS, opened by the RS. |
282 | HRESULT Init( |
283 | HANDLE rsea, |
284 | HANDLE rser, |
285 | HANDLE lsea, |
286 | HANDLE lser, |
287 | HANDLE lsuwe |
288 | ); |
289 | |
290 | }; |
291 | |
292 | #if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) |
293 | |
294 | // We need an alternate definition for the control block if using the transport, because the control block has to be sent over the transport |
295 | // In particular we can't nest the send/receive buffers inside of it and we don't use any of the remote handles |
296 | |
297 | struct MSLAYOUT DebuggerIPCControlBlockTransport |
298 | { |
299 | // Version data should be first in the control block to ensure that we can read it even if the control block |
300 | // changes. |
301 | SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized |
302 | ULONG m_verMajor; // CLR build number for the Left Side. |
303 | ULONG m_verMinor; // CLR build number for the Left Side. |
304 | |
305 | // This next stuff fits in a DWORD. |
306 | bool m_checkedBuild; // CLR build type for the Left Side. |
307 | // using the first padding byte to indicate if hosted in fiber mode. |
308 | // We actually just need one bit. So if needed, can turn this to a bit. |
309 | // BYTE padding1; |
310 | bool m_bHostingInFiber; |
311 | BYTE padding2; |
312 | BYTE padding3; |
313 | |
314 | ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side. |
315 | ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support. |
316 | |
317 | ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side. |
318 | ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires. |
319 | |
320 | HRESULT m_errorHR; |
321 | unsigned int m_errorCode; |
322 | |
323 | #if defined(DBG_TARGET_WIN64) |
324 | // 64-bit needs this padding to make the handles after this aligned. |
325 | // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0. |
326 | ULONG padding4; |
327 | #endif // DBG_TARGET_WIN64 |
328 | |
329 | // This is set immediately when the helper thread is created. |
330 | // This will be set even if there's a temporary helper thread or if the real helper |
331 | // thread is not yet pumping (eg, blocked on a loader lock). |
332 | DWORD m_realHelperThreadId; |
333 | |
334 | // This is only published once the helper thread starts running in its main loop. |
335 | // Thus we can use this field to see if the real helper thread is actually pumping. |
336 | DWORD m_helperThreadId; |
337 | |
338 | // This is non-zero if the LS has a temporary helper thread. |
339 | DWORD m_temporaryHelperThreadId; |
340 | |
341 | // ID of the Helper's canary thread. |
342 | DWORD m_CanaryThreadId; |
343 | |
344 | DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets; |
345 | void *m_helperThreadStartAddr; |
346 | void *m_helperRemoteStartAddr; |
347 | DWORD *m_specialThreadList; |
348 | |
349 | DWORD m_specialThreadListLength; |
350 | bool m_shutdownBegun; |
351 | bool m_rightSideIsWin32Debugger; // RS status |
352 | bool m_specialThreadListDirty; |
353 | |
354 | bool m_rightSideShouldCreateHelperThread; |
355 | |
356 | // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without |
357 | // changing this! |
358 | // Only initialized by the LS, opened by the RS. |
359 | HRESULT Init(); |
360 | |
361 | }; |
362 | |
363 | #endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) |
364 | |
365 | #if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) |
366 | #include "dbgtransportsession.h" |
367 | #endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) |
368 | |
369 | #if defined(DBG_TARGET_X86) && !defined(FEATURE_CORESYSTEM) |
370 | // We have an versioning requirement. |
371 | // Certain portions of the v1.0 and v1.1 IPC block are shared. This is b/c a v1.1 debugger needs to be able |
372 | // to look at a v2.0 app enough to recognize the version mismatch. |
373 | // This check is only necessary for platforms that ran on v1.1 (Win32-x86) |
374 | |
375 | // Just to catch any potential illegal change in the IPC block, we assert the offsets against the offsets from v1.1. |
376 | // The constants here are pulled from v1.1. |
377 | // The RS will look at these versioning fields, so they absolutely must line up. |
378 | static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolCurrent) == 0x10); |
379 | static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolMinSupported) == 0x14); |
380 | static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolCurrent) == 0x18); |
381 | static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolMinSupported) == 0x1c); |
382 | |
383 | // Unfortunately, on detecting such failure, v1.1 will also null out LSEA, LSER and RSPH. |
384 | // If these get adjusted, a version-mismatch attach will effectively null out random fields. |
385 | static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSEA) == 0x30); |
386 | static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSER) == 0x34); |
387 | static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProcessHandle) == 0x38); |
388 | |
389 | |
390 | |
391 | #endif |
392 | |
393 | #define INITIAL_APP_DOMAIN_INFO_LIST_SIZE 16 |
394 | |
395 | |
396 | //----------------------------------------------------------------------------- |
397 | // Provide some Type-safety in the IPC block when we pass remote pointers around. |
398 | //----------------------------------------------------------------------------- |
399 | |
400 | |
401 | //----------------------------------------------------------------------------- |
402 | // This is the same in both the LS & RS. |
403 | // Definitions on the LS & RS should be binary compatible. So all storage is |
404 | // declared in GeneralLsPointer, and then the Ls & RS each have their own |
405 | // derived accessors. |
406 | //----------------------------------------------------------------------------- |
407 | class MSLAYOUT GeneralLsPointer |
408 | { |
409 | protected: |
410 | friend ULONG_PTR LsPtrToCookie(GeneralLsPointer p); |
411 | void * m_ptr; |
412 | |
413 | public: |
414 | bool IsNull() { return m_ptr == NULL; } |
415 | }; |
416 | |
417 | class MSLAYOUT GeneralRsPointer |
418 | { |
419 | protected: |
420 | UINT m_data; |
421 | |
422 | public: |
423 | bool IsNull() { return m_data == 0; } |
424 | }; |
425 | |
426 | // In some cases, we need to get a uuid from a pointer (ie, in a hash) |
427 | inline ULONG_PTR LsPtrToCookie(GeneralLsPointer p) { |
428 | return (ULONG_PTR) p.m_ptr; |
429 | } |
430 | #define VmPtrToCookie(vm) LsPtrToCookie((vm).ToLsPtr()) |
431 | |
432 | |
433 | #ifdef RIGHT_SIDE_COMPILE |
434 | //----------------------------------------------------------------------------- |
435 | // Infrasturcture for RS Definitions |
436 | //----------------------------------------------------------------------------- |
437 | |
438 | // On the RS, we don't have the LS classes defined, so we can't templatize that |
439 | // in terms of <class T>, but we still want things to be unique. |
440 | // So we create an empty enum for each LS type and then templatize it in terms |
441 | // of the enum. |
442 | template <typename T> |
443 | class MSLAYOUT LsPointer : public GeneralLsPointer |
444 | { |
445 | public: |
446 | void Set(void * p) |
447 | { |
448 | m_ptr = p; |
449 | } |
450 | void * UnsafeGet() |
451 | { |
452 | return m_ptr; |
453 | } |
454 | |
455 | static LsPointer<T> NullPtr() |
456 | { |
457 | return MakePtr(NULL); |
458 | } |
459 | |
460 | static LsPointer<T> MakePtr(T* p) |
461 | { |
462 | #ifdef _PREFAST_ |
463 | #pragma warning(push) |
464 | #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't' |
465 | #endif // _PREFAST_ |
466 | |
467 | LsPointer<T> t; |
468 | t.Set(p); |
469 | return t; |
470 | |
471 | #ifdef _PREFAST_ |
472 | #pragma warning(pop) |
473 | #endif // _PREFAST_ |
474 | } |
475 | |
476 | bool operator!= (void * p) { return m_ptr != p; } |
477 | bool operator== (void * p) { return m_ptr == p; } |
478 | bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; } |
479 | |
480 | // We should never UnWrap() them in the RS, so we don't define that here. |
481 | }; |
482 | |
483 | class CordbProcess; |
484 | template <class T> UINT AllocCookie(CordbProcess * pProc, T * p); |
485 | template <class T> T * UnwrapCookie(CordbProcess * pProc, UINT cookie); |
486 | |
487 | UINT AllocCookieCordbEval(CordbProcess * pProc, class CordbEval * p); |
488 | class CordbEval * UnwrapCookieCordbEval(CordbProcess * pProc, UINT cookie); |
489 | |
490 | template <class CordbEval> UINT AllocCookie(CordbProcess * pProc, CordbEval * p) |
491 | { |
492 | return AllocCookieCordbEval(pProc, p); |
493 | } |
494 | template <class CordbEval> CordbEval * UnwrapCookie(CordbProcess * pProc, UINT cookie) |
495 | { |
496 | return UnwrapCookieCordbEval(pProc, cookie); |
497 | } |
498 | |
499 | |
500 | |
501 | // This is how the RS sees the pointers in the IPC block. |
502 | template<class T> |
503 | class MSLAYOUT RsPointer : public GeneralRsPointer |
504 | { |
505 | public: |
506 | // Since we're being used inside a union, we can't have a ctor. |
507 | |
508 | static RsPointer<T> NullPtr() |
509 | { |
510 | RsPointer<T> t; |
511 | t.m_data = 0; |
512 | return t; |
513 | } |
514 | |
515 | bool AllocHandle(CordbProcess *pProc, T* p) |
516 | { |
517 | // This will force validation. |
518 | m_data = AllocCookie<T>(pProc, p); |
519 | return (m_data != 0); |
520 | } |
521 | |
522 | bool operator==(RsPointer<T> p) { return p.m_data == this->m_data; } |
523 | |
524 | T* UnWrapAndRemove(CordbProcess *pProc) |
525 | { |
526 | return UnwrapCookie<T>(pProc, m_data); |
527 | } |
528 | |
529 | protected: |
530 | }; |
531 | |
532 | // Forward declare a class so that each type of LS pointer can have |
533 | // its own type. We use the real class name to be compatible with VMPTRs. |
534 | #define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \ |
535 | ls_type; \ |
536 | typedef LsPointer<ls_type> ptr_name; |
537 | |
538 | |
539 | #define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \ |
540 | class rs_type; \ |
541 | typedef RsPointer<rs_type> ptr_name; |
542 | |
543 | #else // !RIGHT_SIDE_COMPILE |
544 | //----------------------------------------------------------------------------- |
545 | // Infrastructure for LS Definitions |
546 | //----------------------------------------------------------------------------- |
547 | |
548 | // This is how the LS sees the pointers in the IPC block. |
549 | template<typename T> |
550 | class MSLAYOUT LsPointer : public GeneralLsPointer |
551 | { |
552 | public: |
553 | // Since we're being used inside a union, we can't have a ctor. |
554 | //LsPointer() { } |
555 | |
556 | static LsPointer<T> NullPtr() |
557 | { |
558 | return MakePtr(NULL); |
559 | } |
560 | |
561 | static LsPointer<T> MakePtr(T * p) |
562 | { |
563 | #ifdef _PREFAST_ |
564 | #pragma warning(push) |
565 | #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't' |
566 | #endif // _PREFAST_ |
567 | |
568 | LsPointer<T> t; |
569 | t.Set(p); |
570 | return t; |
571 | |
572 | #ifdef _PREFAST_ |
573 | #pragma warning(pop) |
574 | #endif // _PREFAST_ |
575 | } |
576 | |
577 | bool operator!= (void * p) { return m_ptr != p; } |
578 | bool operator== (void * p) { return m_ptr == p; } |
579 | bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; } |
580 | |
581 | // @todo - we want to be able to swap out Set + Unwrap functions |
582 | void Set(T * p) |
583 | { |
584 | SUPPORTS_DAC; |
585 | // We could validate the pointer here. |
586 | m_ptr = p; |
587 | } |
588 | |
589 | T * UnWrap() |
590 | { |
591 | // If we wanted to validate the pointer, here's our chance. |
592 | return static_cast<T*>(m_ptr); |
593 | } |
594 | }; |
595 | |
596 | template <class n> |
597 | class MSLAYOUT RsPointer : public GeneralRsPointer |
598 | { |
599 | public: |
600 | static RsPointer<n> NullPtr() |
601 | { |
602 | RsPointer<n> t; |
603 | t.m_data = 0; |
604 | return t; |
605 | } |
606 | |
607 | bool operator==(RsPointer<n> p) { return p.m_data == this->m_data; } |
608 | |
609 | // We should never UnWrap() them in the LS, so we don't define that here. |
610 | }; |
611 | |
612 | #define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \ |
613 | ls_type; \ |
614 | typedef LsPointer<ls_type> ptr_name; |
615 | |
616 | #define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \ |
617 | enum __RS__##rs_type { }; \ |
618 | typedef RsPointer<__RS__##rs_type> ptr_name; |
619 | |
620 | #endif // !RIGHT_SIDE_COMPILE |
621 | |
622 | // We must be binary compatible w/ a pointer. |
623 | static_assert_no_msg(sizeof(LsPointer<void>) == sizeof(GeneralLsPointer)); |
624 | |
625 | static_assert_no_msg(sizeof(void*) == sizeof(GeneralLsPointer)); |
626 | |
627 | |
628 | |
629 | //----------------------------------------------------------------------------- |
630 | // Definitions for Left-Side ptrs. |
631 | // NOTE: Use VMPTR instead of LSPTR. Don't add new LSPTR types. |
632 | // |
633 | //----------------------------------------------------------------------------- |
634 | |
635 | |
636 | |
637 | DEFINE_LSPTR_TYPE(class Assembly, LSPTR_ASSEMBLY); |
638 | DEFINE_LSPTR_TYPE(class DebuggerJitInfo, LSPTR_DJI); |
639 | DEFINE_LSPTR_TYPE(class DebuggerMethodInfo, LSPTR_DMI); |
640 | DEFINE_LSPTR_TYPE(class MethodDesc, LSPTR_METHODDESC); |
641 | DEFINE_LSPTR_TYPE(class DebuggerBreakpoint, LSPTR_BREAKPOINT); |
642 | DEFINE_LSPTR_TYPE(class DebuggerDataBreakpoint, LSPTR_DATA_BREAKPOINT); |
643 | DEFINE_LSPTR_TYPE(class DebuggerEval, LSPTR_DEBUGGEREVAL); |
644 | DEFINE_LSPTR_TYPE(class DebuggerStepper, LSPTR_STEPPER); |
645 | |
646 | // Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct. |
647 | #if defined(RIGHT_SIDE_COMPILE) |
648 | typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT; |
649 | #else // RIGHT_SIDE_COMPILE |
650 | typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT; |
651 | #endif // RIGHT_SIDE_COMPILE |
652 | |
653 | DEFINE_LSPTR_TYPE(struct OBJECTHANDLE__, LSPTR_OBJECTHANDLE); |
654 | DEFINE_LSPTR_TYPE(class TypeHandleDummyPtr, LSPTR_TYPEHANDLE); // TypeHandle in the LS is not a direct pointer. |
655 | |
656 | //----------------------------------------------------------------------------- |
657 | // Definitions for Right-Side ptrs. |
658 | //----------------------------------------------------------------------------- |
659 | DEFINE_RSPTR_TYPE(CordbEval, RSPTR_CORDBEVAL); |
660 | |
661 | |
662 | //--------------------------------------------------------------------------------------- |
663 | // VMPTR_Base is the base type for an abstraction over pointers into the VM so |
664 | // that DBI can treat them as opaque handles. Classes will derive from it to |
665 | // provide type-safe Target pointers, which ICD will view as opaque handles. |
666 | // |
667 | // Lifetimes: |
668 | // VMPTR_ objects survive across flushing the DAC cache. Therefore, the underlying |
669 | // storage must be a target-pointer (and not a marshalled host pointer). |
670 | // The RS must ensure they're still in sync with the LS (eg, by |
671 | // tracking unload events). |
672 | // |
673 | // |
674 | // Assumptions: |
675 | // These handles are TADDR pointers and must not require any cleanup from DAC/DBI. |
676 | // For direct untyped pointers into the VM, use CORDB_ADDRESS. |
677 | // |
678 | // Notes: |
679 | // 1. This helps enforce that DBI goes through the primitives interface |
680 | // for all access (and that it doesn't accidentally start calling |
681 | // dac-ized methods on the objects) |
682 | // 2. This isolates DBI from VM headers. |
683 | // 3. This isolates DBI from the dac implementation (of DAC_Ptr) |
684 | // 4. This is distinct from LSPTR because LSPTRs are truly opaque handles, whereas VMPtrs |
685 | // move across VM, DAC, and DBI, exposing proper functionality in each component. |
686 | // 5. VMPTRs are blittable because they are Target Addresses which act as opaque |
687 | // handles outside of the Target / Dac-marshaller. |
688 | // |
689 | //--------------------------------------------------------------------------------------- |
690 | |
691 | |
692 | template <typename TTargetPtr, typename TDacPtr> |
693 | class MSLAYOUT VMPTR_Base |
694 | { |
695 | // Underlying pointer into Target address space. |
696 | // Target pointers are blittable. |
697 | // - In Target: can be used as normal local pointers. |
698 | // - In DAC: must be marshalled to a host-pointer and then they can be used via DAC |
699 | // - In RS: opaque handles. |
700 | private: |
701 | TADDR m_addr; |
702 | |
703 | public: |
704 | typedef VMPTR_Base<TTargetPtr,TDacPtr> VMPTR_This; |
705 | |
706 | // For DBI, VMPTRs are opaque handles. |
707 | // But the DAC side is allowed to inspect the handles to get at the raw pointer. |
708 | #if defined(ALLOW_VMPTR_ACCESS) |
709 | // |
710 | // Case 1: Using in DAcDbi implementation |
711 | // |
712 | |
713 | // DAC accessor |
714 | TDacPtr GetDacPtr() const |
715 | { |
716 | SUPPORTS_DAC; |
717 | return TDacPtr(m_addr); |
718 | } |
719 | |
720 | |
721 | // This will initialize the handle to a given target-pointer. |
722 | // We choose TADDR to make it explicit that it's a target pointer and avoid the risk |
723 | // of it accidentally getting marshalled to a host pointer. |
724 | void SetDacTargetPtr(TADDR addr) |
725 | { |
726 | SUPPORTS_DAC; |
727 | m_addr = addr; |
728 | } |
729 | |
730 | void SetHostPtr(const TTargetPtr * pObject) |
731 | { |
732 | SUPPORTS_DAC; |
733 | m_addr = PTR_HOST_TO_TADDR(pObject); |
734 | } |
735 | |
736 | |
737 | #elif !defined(RIGHT_SIDE_COMPILE) |
738 | // |
739 | // Case 2: Used in Left-side. Can get/set from local pointers. |
740 | // |
741 | |
742 | // This will set initialize from a Target pointer. Since this is happening in the |
743 | // Left-side (Target), the pointer is local. |
744 | // This is commonly used by the Left-side to create a VMPTR_ for a notification event. |
745 | void SetRawPtr(TTargetPtr * ptr) |
746 | { |
747 | m_addr = reinterpret_cast<TADDR>(ptr); |
748 | } |
749 | |
750 | // This will get the raw underlying target pointer. |
751 | // This can be used by inproc Left-side code to unwrap a VMPTR (Eg, for a func-eval |
752 | // hijack or in-proc worker threads) |
753 | TTargetPtr * GetRawPtr() |
754 | { |
755 | return reinterpret_cast<TTargetPtr*>(m_addr); |
756 | } |
757 | |
758 | // Convenience for converting TTargetPtr --> VMPTR |
759 | static VMPTR_This MakePtr(TTargetPtr * ptr) |
760 | { |
761 | #ifdef _PREFAST_ |
762 | #pragma warning(push) |
763 | #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't' |
764 | #endif // _PREFAST_ |
765 | |
766 | VMPTR_This t; |
767 | t.SetRawPtr(ptr); |
768 | return t; |
769 | |
770 | #ifdef _PREFAST_ |
771 | #pragma warning(pop) |
772 | #endif // _PREFAST_ |
773 | } |
774 | |
775 | |
776 | #else |
777 | // |
778 | // Case 3: Used in RS. Opaque handles only. |
779 | // |
780 | #endif |
781 | |
782 | |
783 | #ifndef DACCESS_COMPILE |
784 | // For compatibility, these can be converted to LSPTRs on the RS or LS (case 2 and 3). We don't allow |
785 | // this in the DAC case because it's a cast between address spaces which we're trying to eliminate |
786 | // in the DAC code. |
787 | // @dbgtodo inspection: LSPTRs will go away entirely once we've moved completely over to DAC |
788 | LsPointer<TTargetPtr> ToLsPtr() |
789 | { |
790 | return LsPointer<TTargetPtr>::MakePtr( reinterpret_cast<TTargetPtr *>(m_addr)); |
791 | } |
792 | #endif |
793 | |
794 | // |
795 | // Operators to emulate Pointer semantics. |
796 | // |
797 | bool IsNull() { SUPPORTS_DAC; return m_addr == NULL; } |
798 | |
799 | static VMPTR_This NullPtr() |
800 | { |
801 | SUPPORTS_DAC; |
802 | |
803 | #ifdef _PREFAST_ |
804 | #pragma warning(push) |
805 | #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't' |
806 | #endif // _PREFAST_ |
807 | |
808 | VMPTR_This dummy; |
809 | dummy.m_addr = NULL; |
810 | return dummy; |
811 | |
812 | #ifdef _PREFAST_ |
813 | #pragma warning(pop) |
814 | #endif // _PREFAST_ |
815 | } |
816 | |
817 | bool operator!= (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr != vmOther.m_addr; } |
818 | bool operator== (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr == vmOther.m_addr; } |
819 | }; |
820 | |
821 | #if defined(ALLOW_VMPTR_ACCESS) |
822 | // Helper macro to define a VMPTR. |
823 | // This is used in the DAC case, so this definition connects the pointers up to their DAC values. |
824 | #define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \ |
825 | ls_type; \ |
826 | typedef VMPTR_Base<ls_type, dac_ptr_type> ptr_name; |
827 | |
828 | #else |
829 | // Helper macro to define a VMPTR. |
830 | // This is used in the Right-side and Left-side (but not DAC) case. |
831 | // This definition explicitly ignores dac_ptr_type to prevent accidental DAC usage. |
832 | #define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \ |
833 | ls_type; \ |
834 | typedef VMPTR_Base<ls_type, void> ptr_name; |
835 | |
836 | #endif |
837 | |
838 | // Declare VMPTRs. |
839 | // The naming convention for instantiating a VMPTR is a 'vm' prefix. |
840 | // |
841 | // VM definition, DAC definition, pretty name for VMPTR |
842 | DEFINE_VMPTR(class AppDomain, PTR_AppDomain, VMPTR_AppDomain); |
843 | |
844 | // Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct. |
845 | // DEFINE_VMPTR(struct _CONTEXT, PTR_CONTEXT, VMPTR_CONTEXT); |
846 | #if defined(ALLOW_VMPTR_ACCESS) |
847 | typedef VMPTR_Base<DT_CONTEXT, PTR_CONTEXT> VMPTR_CONTEXT; |
848 | #else |
849 | typedef VMPTR_Base<DT_CONTEXT, void > VMPTR_CONTEXT; |
850 | #endif |
851 | |
852 | // DomainFile is a base-class for a CLR module, with app-domain affinity. |
853 | // For domain-neutral modules (like mscorlib), there is a DomainFile instance |
854 | // for each appdomain the module lives in. |
855 | // This is the canonical handle ICorDebug uses to a CLR module. |
856 | DEFINE_VMPTR(class DomainFile, PTR_DomainFile, VMPTR_DomainFile); |
857 | DEFINE_VMPTR(class Module, PTR_Module, VMPTR_Module); |
858 | |
859 | // DomainAssembly derives from DomainFile and represents a manifest module. |
860 | DEFINE_VMPTR(class DomainAssembly, PTR_DomainAssembly, VMPTR_DomainAssembly); |
861 | DEFINE_VMPTR(class Assembly, PTR_Assembly, VMPTR_Assembly); |
862 | |
863 | DEFINE_VMPTR(class PEFile, PTR_PEFile, VMPTR_PEFile); |
864 | DEFINE_VMPTR(class MethodDesc, PTR_MethodDesc, VMPTR_MethodDesc); |
865 | DEFINE_VMPTR(class FieldDesc, PTR_FieldDesc, VMPTR_FieldDesc); |
866 | |
867 | // ObjectHandle is a safe way to represent an object into the GC heap. It gets updated |
868 | // when a GC occurs. |
869 | DEFINE_VMPTR(struct OBJECTHANDLE__, TADDR, VMPTR_OBJECTHANDLE); |
870 | |
871 | DEFINE_VMPTR(class TypeHandle, PTR_TypeHandle, VMPTR_TypeHandle); |
872 | |
873 | // A VMPTR_Thread represents a thread that has entered the runtime at some point. |
874 | // It may or may not have executed managed code yet; and it may or may not have managed code |
875 | // on its callstack. |
876 | DEFINE_VMPTR(class Thread, PTR_Thread, VMPTR_Thread); |
877 | |
878 | DEFINE_VMPTR(class Object, PTR_Object, VMPTR_Object); |
879 | |
880 | DEFINE_VMPTR(class CrstBase, PTR_Crst, VMPTR_Crst); |
881 | DEFINE_VMPTR(class SimpleRWLock, PTR_SimpleRWLock, VMPTR_SimpleRWLock); |
882 | DEFINE_VMPTR(class SimpleRWLock, PTR_SimpleRWLock, VMPTR_RWLock); |
883 | DEFINE_VMPTR(struct ReJitInfo, PTR_ReJitInfo, VMPTR_ReJitInfo); |
884 | DEFINE_VMPTR(struct SharedReJitInfo, PTR_SharedReJitInfo, VMPTR_SharedReJitInfo); |
885 | DEFINE_VMPTR(class NativeCodeVersionNode, PTR_NativeCodeVersionNode, VMPTR_NativeCodeVersionNode); |
886 | DEFINE_VMPTR(class ILCodeVersionNode, PTR_ILCodeVersionNode, VMPTR_ILCodeVersionNode); |
887 | |
888 | typedef CORDB_ADDRESS GENERICS_TYPE_TOKEN; |
889 | |
890 | |
891 | //----------------------------------------------------------------------------- |
892 | // We pass some fixed size strings in the IPC block. |
893 | // Helper class to wrap the buffer and protect against buffer overflows. |
894 | // This should be binary compatible w/ a wchar[] array. |
895 | //----------------------------------------------------------------------------- |
896 | |
897 | template <int nMaxLengthIncludingNull> |
898 | class MSLAYOUT EmbeddedIPCString |
899 | { |
900 | public: |
901 | // Set, caller responsibility that wcslen(pData) < nMaxLengthIncludingNull |
902 | void SetString(const WCHAR * pData) |
903 | { |
904 | // If the string doesn't fit into the buffer, that's an issue (and so this is a real |
905 | // assert, not just a simplifying assumption). To fix it, either: |
906 | // - make the buffer larger |
907 | // - don't pass the string as an embedded string in the IPC block. |
908 | // This will truncate (rather than AV on the RS). |
909 | int ret; |
910 | ret = SafeCopy(pData); |
911 | |
912 | // See comment above - caller should guarantee that buffer is large enough. |
913 | _ASSERTE(ret != STRUNCATE); |
914 | } |
915 | |
916 | // Set a string from a substring. This will truncate if necessary. |
917 | void SetStringTruncate(const WCHAR * pData) |
918 | { |
919 | // ignore return value because truncation is ok. |
920 | SafeCopy(pData); |
921 | } |
922 | |
923 | const WCHAR * GetString() |
924 | { |
925 | // For a null-termination just in case an issue in the debuggee process |
926 | // yields a malformed string. |
927 | m_data[nMaxLengthIncludingNull - 1] = W('\0'); |
928 | return &m_data[0]; |
929 | } |
930 | int GetMaxSize() const { return nMaxLengthIncludingNull; } |
931 | |
932 | private: |
933 | int SafeCopy(const WCHAR * pData) |
934 | { |
935 | return wcsncpy_s( |
936 | m_data, nMaxLengthIncludingNull, |
937 | pData, _TRUNCATE); |
938 | } |
939 | WCHAR m_data[nMaxLengthIncludingNull]; |
940 | }; |
941 | |
942 | // |
943 | // Types of events that can be sent between the Runtime Controller and |
944 | // the Debugger Interface. Some of these events are one way only, while |
945 | // others go both ways. The grouping of the event numbers is an attempt |
946 | // to show this distinction and perhaps even allow generic operations |
947 | // based on the type of the event. |
948 | // |
949 | enum DebuggerIPCEventType |
950 | { |
951 | #define IPC_EVENT_TYPE0(type, val) type = val, |
952 | #define IPC_EVENT_TYPE1(type, val) type = val, |
953 | #define IPC_EVENT_TYPE2(type, val) type = val, |
954 | #include "dbgipceventtypes.h" |
955 | #undef IPC_EVENT_TYPE2 |
956 | #undef IPC_EVENT_TYPE1 |
957 | #undef IPC_EVENT_TYPE0 |
958 | }; |
959 | |
960 | #ifdef _DEBUG |
961 | |
962 | // This is a static debugging structure to help breaking at the right place. |
963 | // Debug only. This is to track the number of events that have been happened so far. |
964 | // User can choose to set break point base on the number of events. |
965 | // Variables are named as the event name with prefix m_iDebugCount. For example |
966 | // m_iDebugCount_DB_IPCE_BREAKPOINT if for event DB_IPCE_BREAKPOINT. |
967 | struct MSLAYOUT DebugEventCounter |
968 | { |
969 | // we don't need the event type 0 |
970 | #define IPC_EVENT_TYPE0(type, val) |
971 | #define IPC_EVENT_TYPE1(type, val) int m_iDebugCount_##type; |
972 | #define IPC_EVENT_TYPE2(type, val) int m_iDebugCount_##type; |
973 | #include "dbgipceventtypes.h" |
974 | #undef IPC_EVENT_TYPE2 |
975 | #undef IPC_EVENT_TYPE1 |
976 | #undef IPC_EVENT_TYPE0 |
977 | }; |
978 | #endif // _DEBUG |
979 | |
980 | |
981 | #if !defined(DACCESS_COMPILE) |
982 | |
983 | struct MSLAYOUT IPCEventTypeNameMapping |
984 | { |
985 | DebuggerIPCEventType eventType; |
986 | const char * eventName; |
987 | }; |
988 | |
989 | extern const IPCEventTypeNameMapping DECLSPEC_SELECTANY DbgIPCEventTypeNames[] = |
990 | { |
991 | #define IPC_EVENT_TYPE0(type, val) { type, #type }, |
992 | #define IPC_EVENT_TYPE1(type, val) { type, #type }, |
993 | #define IPC_EVENT_TYPE2(type, val) { type, #type }, |
994 | #include "dbgipceventtypes.h" |
995 | #undef IPC_EVENT_TYPE2 |
996 | #undef IPC_EVENT_TYPE1 |
997 | #undef IPC_EVENT_TYPE0 |
998 | { DB_IPCE_INVALID_EVENT, "DB_IPCE_Error" } |
999 | }; |
1000 | |
1001 | const size_t nameCount = sizeof(DbgIPCEventTypeNames) / sizeof(DbgIPCEventTypeNames[0]); |
1002 | |
1003 | |
1004 | struct MSLAYOUT IPCENames // We use a class/struct so that the function can remain in a shared header file |
1005 | { |
1006 | static DebuggerIPCEventType GetEventType(__in_z char * strEventType) |
1007 | { |
1008 | // pass in the string of event name and find the matching enum value |
1009 | // This is a linear search which is pretty slow. However, this is only used |
1010 | // at startup time when debug assert is turn on and with registry key set. So it is not that bad. |
1011 | // |
1012 | for (size_t i = 0; i < nameCount; i++) |
1013 | { |
1014 | if (_stricmp(DbgIPCEventTypeNames[i].eventName, strEventType) == 0) |
1015 | return DbgIPCEventTypeNames[i].eventType; |
1016 | } |
1017 | return DB_IPCE_INVALID_EVENT; |
1018 | } |
1019 | static const char * GetName(DebuggerIPCEventType eventType) |
1020 | { |
1021 | |
1022 | enum DbgIPCEventTypeNum |
1023 | { |
1024 | #define IPC_EVENT_TYPE0(type, val) type##_Num, |
1025 | #define IPC_EVENT_TYPE1(type, val) type##_Num, |
1026 | #define IPC_EVENT_TYPE2(type, val) type##_Num, |
1027 | #include "dbgipceventtypes.h" |
1028 | #undef IPC_EVENT_TYPE2 |
1029 | #undef IPC_EVENT_TYPE1 |
1030 | #undef IPC_EVENT_TYPE0 |
1031 | }; |
1032 | |
1033 | unsigned int i, lim; |
1034 | |
1035 | if (eventType < DB_IPCE_DEBUGGER_FIRST) |
1036 | { |
1037 | i = DB_IPCE_RUNTIME_FIRST_Num + 1; |
1038 | lim = DB_IPCE_DEBUGGER_FIRST_Num; |
1039 | } |
1040 | else |
1041 | { |
1042 | i = DB_IPCE_DEBUGGER_FIRST_Num + 1; |
1043 | lim = nameCount; |
1044 | } |
1045 | |
1046 | for (/**/; i < lim; i++) |
1047 | { |
1048 | if (DbgIPCEventTypeNames[i].eventType == eventType) |
1049 | return DbgIPCEventTypeNames[i].eventName; |
1050 | } |
1051 | |
1052 | return DbgIPCEventTypeNames[nameCount - 1].eventName; |
1053 | } |
1054 | }; |
1055 | |
1056 | #endif // !DACCESS_COMPILE |
1057 | |
1058 | // |
1059 | // NOTE: CPU-specific values below! |
1060 | // |
1061 | // DebuggerREGDISPLAY is very similar to the EE REGDISPLAY structure. It holds |
1062 | // register values that can be saved over calls for each frame in a stack |
1063 | // trace. |
1064 | // |
1065 | // DebuggerIPCE_FloatCount is the number of doubles in the processor's |
1066 | // floating point stack. |
1067 | // |
1068 | // <TODO>Note: We used to just pass the values of the registers for each frame to the Right Side, but I had to add in the |
1069 | // address of each register, too, to support using enregistered variables on non-leaf frames as args to a func eval. Its |
1070 | // very, very possible that we would rework the entire code base to just use the register's address instead of passing |
1071 | // both, but its way, way too late in V1 to undertake that, so I'm just using these addresses to suppport our one func |
1072 | // eval case. Clearly, this needs to be cleaned up post V1. |
1073 | // |
1074 | // -- Fri Feb 09 11:21:24 2001</TODO> |
1075 | // |
1076 | |
1077 | struct MSLAYOUT DebuggerREGDISPLAY |
1078 | { |
1079 | #if defined(DBG_TARGET_X86) |
1080 | #define DebuggerIPCE_FloatCount 8 |
1081 | |
1082 | SIZE_T Edi; |
1083 | void *pEdi; |
1084 | SIZE_T Esi; |
1085 | void *pEsi; |
1086 | SIZE_T Ebx; |
1087 | void *pEbx; |
1088 | SIZE_T Edx; |
1089 | void *pEdx; |
1090 | SIZE_T Ecx; |
1091 | void *pEcx; |
1092 | SIZE_T Eax; |
1093 | void *pEax; |
1094 | SIZE_T FP; |
1095 | void *pFP; |
1096 | SIZE_T SP; |
1097 | SIZE_T PC; |
1098 | |
1099 | #elif defined(DBG_TARGET_AMD64) |
1100 | #define DebuggerIPCE_FloatCount 16 |
1101 | |
1102 | SIZE_T Rax; |
1103 | void *pRax; |
1104 | SIZE_T Rcx; |
1105 | void *pRcx; |
1106 | SIZE_T Rdx; |
1107 | void *pRdx; |
1108 | SIZE_T Rbx; |
1109 | void *pRbx; |
1110 | SIZE_T Rbp; |
1111 | void *pRbp; |
1112 | SIZE_T Rsi; |
1113 | void *pRsi; |
1114 | SIZE_T Rdi; |
1115 | void *pRdi; |
1116 | |
1117 | SIZE_T R8; |
1118 | void *pR8; |
1119 | SIZE_T R9; |
1120 | void *pR9; |
1121 | SIZE_T R10; |
1122 | void *pR10; |
1123 | SIZE_T R11; |
1124 | void *pR11; |
1125 | SIZE_T R12; |
1126 | void *pR12; |
1127 | SIZE_T R13; |
1128 | void *pR13; |
1129 | SIZE_T R14; |
1130 | void *pR14; |
1131 | SIZE_T R15; |
1132 | void *pR15; |
1133 | |
1134 | SIZE_T SP; |
1135 | SIZE_T PC; |
1136 | #elif defined(DBG_TARGET_ARM) |
1137 | #define DebuggerIPCE_FloatCount 32 |
1138 | |
1139 | SIZE_T R0; |
1140 | void *pR0; |
1141 | SIZE_T R1; |
1142 | void *pR1; |
1143 | SIZE_T R2; |
1144 | void *pR2; |
1145 | SIZE_T R3; |
1146 | void *pR3; |
1147 | SIZE_T R4; |
1148 | void *pR4; |
1149 | SIZE_T R5; |
1150 | void *pR5; |
1151 | SIZE_T R6; |
1152 | void *pR6; |
1153 | SIZE_T R7; |
1154 | void *pR7; |
1155 | SIZE_T R8; |
1156 | void *pR8; |
1157 | SIZE_T R9; |
1158 | void *pR9; |
1159 | SIZE_T R10; |
1160 | void *pR10; |
1161 | SIZE_T R11; |
1162 | void *pR11; |
1163 | SIZE_T R12; |
1164 | void *pR12; |
1165 | SIZE_T SP; |
1166 | void *pSP; |
1167 | SIZE_T LR; |
1168 | void *pLR; |
1169 | SIZE_T PC; |
1170 | void *pPC; |
1171 | #elif defined(DBG_TARGET_ARM64) |
1172 | #define DebuggerIPCE_FloatCount 32 |
1173 | |
1174 | SIZE_T X[29]; |
1175 | SIZE_T SP; |
1176 | SIZE_T FP; |
1177 | SIZE_T LR; |
1178 | SIZE_T PC; |
1179 | #else |
1180 | #define DebuggerIPCE_FloatCount 1 |
1181 | |
1182 | SIZE_T PC; |
1183 | SIZE_T FP; |
1184 | SIZE_T SP; |
1185 | void *pFP; |
1186 | #endif |
1187 | }; |
1188 | |
1189 | inline LPVOID GetSPAddress(const DebuggerREGDISPLAY * display) |
1190 | { |
1191 | return (LPVOID)&display->SP; |
1192 | } |
1193 | |
1194 | #if !defined(DBG_TARGET_AMD64) && !defined(DBG_TARGET_ARM) |
1195 | inline LPVOID GetFPAddress(const DebuggerREGDISPLAY * display) |
1196 | { |
1197 | return (LPVOID)&display->FP; |
1198 | } |
1199 | #endif // !DBG_TARGET_AMD64 |
1200 | |
1201 | |
1202 | class MSLAYOUT FramePointer |
1203 | { |
1204 | friend bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2); |
1205 | friend bool IsCloserToRoot(FramePointer fp1, FramePointer fp2); |
1206 | friend bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2); |
1207 | friend bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2); |
1208 | |
1209 | public: |
1210 | |
1211 | static FramePointer MakeFramePointer(LPVOID sp) |
1212 | { |
1213 | LIMITED_METHOD_DAC_CONTRACT; |
1214 | FramePointer fp; |
1215 | fp.m_sp = sp; |
1216 | return fp; |
1217 | } |
1218 | |
1219 | static FramePointer MakeFramePointer(UINT_PTR sp) |
1220 | { |
1221 | SUPPORTS_DAC; |
1222 | return MakeFramePointer((LPVOID)sp); |
1223 | } |
1224 | |
1225 | inline bool operator==(FramePointer fp) |
1226 | { |
1227 | return (m_sp == fp.m_sp); |
1228 | } |
1229 | |
1230 | inline bool operator!=(FramePointer fp) |
1231 | { |
1232 | return !(*this == fp); |
1233 | } |
1234 | |
1235 | // This is needed because on the RS, the m_id values of CordbFrame and |
1236 | // CordbChain are really FramePointers. |
1237 | LPVOID GetSPValue() const |
1238 | { |
1239 | return m_sp; |
1240 | } |
1241 | |
1242 | |
1243 | private: |
1244 | // Declare some private constructors which signatures matching common usage of FramePointer |
1245 | // to prevent people from accidentally assigning a pointer to a FramePointer(). |
1246 | FramePointer &operator=(LPVOID sp); |
1247 | FramePointer &operator=(BYTE* sp); |
1248 | FramePointer &operator=(const BYTE* sp); |
1249 | |
1250 | LPVOID m_sp; |
1251 | }; |
1252 | |
1253 | // For non-IA64 platforms, we use stack pointers as frame pointers. |
1254 | // (Stack grows towards smaller address.) |
1255 | #define LEAF_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)NULL) |
1256 | #define ROOT_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)-1) |
1257 | |
1258 | static_assert_no_msg(sizeof(FramePointer) == sizeof(void*)); |
1259 | |
1260 | |
1261 | inline bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2) |
1262 | { |
1263 | return (fp1.m_sp < fp2.m_sp); |
1264 | } |
1265 | |
1266 | inline bool IsCloserToRoot(FramePointer fp1, FramePointer fp2) |
1267 | { |
1268 | return (fp1.m_sp > fp2.m_sp); |
1269 | } |
1270 | |
1271 | inline bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2) |
1272 | { |
1273 | return !IsCloserToRoot(fp1, fp2); |
1274 | } |
1275 | |
1276 | inline bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2) |
1277 | { |
1278 | return !IsCloserToLeaf(fp1, fp2); |
1279 | } |
1280 | |
1281 | |
1282 | // struct DebuggerIPCE_FuncData: DebuggerIPCE_FuncData holds data |
1283 | // to describe a given function, its |
1284 | // class, and a little bit about the code for the function. This is used |
1285 | // in the stack trace result data to pass function information back that |
1286 | // may be needed. Its also used when getting data about a specific function. |
1287 | // |
1288 | // void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is |
1289 | // the address of the real start address of the native code. |
1290 | // This field will be NULL only if the method hasn't been JITted |
1291 | // yet (and thus no code is available). Otherwise, it will be |
1292 | // the adress of a CORDB_ADDRESS in the remote memory. This |
1293 | // CORDB_ADDRESS may be NULL, in which case the code is unavailable |
1294 | // has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE) |
1295 | // |
1296 | // SIZE_T nVersion: The version of the code that this instance of the |
1297 | // function is using. |
1298 | struct MSLAYOUT DebuggerIPCE_FuncData |
1299 | { |
1300 | mdMethodDef funcMetadataToken; |
1301 | VMPTR_DomainFile vmDomainFile; |
1302 | |
1303 | mdTypeDef classMetadataToken; |
1304 | |
1305 | void* ilStartAddress; |
1306 | SIZE_T ilSize; |
1307 | |
1308 | SIZE_T currentEnCVersion; |
1309 | |
1310 | mdSignature localVarSigToken; |
1311 | |
1312 | |
1313 | }; |
1314 | |
1315 | // struct DebuggerIPCE_JITFuncData: DebuggerIPCE_JITFuncData holds |
1316 | // a little bit about the JITted code for the function. |
1317 | // |
1318 | // void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is |
1319 | // the address of the real start address of the native code. |
1320 | // This field will be NULL only if the method hasn't been JITted |
1321 | // yet (and thus no code is available). Otherwise, it will be |
1322 | // the address of a CORDB_ADDRESS in the remote memory. This |
1323 | // CORDB_ADDRESS may be NULL, in which case the code is unavailable |
1324 | // or has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE) |
1325 | // |
1326 | // SIZE_T nativeSize: Size of the native code. |
1327 | // |
1328 | // SIZE_T nativeOffset: Offset from the beginning of the function, |
1329 | // in bytes. This may be non-zero even when nativeStartAddressPtr |
1330 | // is NULL |
1331 | // void * nativeCodeJITInfoToken: An opaque value to hand back to the left |
1332 | // side when fetching the JITInfo for the native code, i.e. the |
1333 | // IL->native maps for the variables. This may be NULL if no JITInfo is available. |
1334 | // void * nativeCodeMethodDescToken: An opaque value to hand back to the left |
1335 | // side when fetching the code. In addition this token can act as the |
1336 | // unique identity for the native code in the case where there are |
1337 | // multiple blobs of native code per IL method (i.e. if the method is |
1338 | // generic code of some kind) |
1339 | // BOOL isInstantiatedGeneric: Indicates if the method is |
1340 | // generic code of some kind. |
1341 | // BOOL jsutAfterILThrow: indicates that code just threw a software exception and |
1342 | // nativeOffset points to an instruction just after [call IL_Throw]. |
1343 | // This is being used to figure out a real offset of the exception origin. |
1344 | // By subtracting STACKWALK_CONTROLPC_ADJUST_OFFSET from nativeOffset you can get |
1345 | // an address somewhere inside [call IL_Throw] instruction. |
1346 | // void *ilToNativeMapAddr etc.: If nativeCodeJITInfoToken is not NULL then these |
1347 | // specify the table giving the mapping of IPs. |
1348 | struct MSLAYOUT DebuggerIPCE_JITFuncData |
1349 | { |
1350 | TADDR nativeStartAddressPtr; |
1351 | SIZE_T nativeHotSize; |
1352 | |
1353 | // If we have a cold region, need its size & the pointer to where starts. |
1354 | TADDR nativeStartAddressColdPtr; |
1355 | SIZE_T nativeColdSize; |
1356 | |
1357 | |
1358 | SIZE_T nativeOffset; |
1359 | LSPTR_DJI nativeCodeJITInfoToken; |
1360 | VMPTR_MethodDesc vmNativeCodeMethodDescToken; |
1361 | |
1362 | #ifdef WIN64EXCEPTIONS |
1363 | BOOL fIsFilterFrame; |
1364 | SIZE_T parentNativeOffset; |
1365 | FramePointer fpParentOrSelf; |
1366 | #endif // WIN64EXCEPTIONS |
1367 | |
1368 | // indicates if the MethodDesc is a generic function or a method inside a generic class (or |
1369 | // both!). |
1370 | BOOL isInstantiatedGeneric; |
1371 | |
1372 | // this is the version of the jitted code |
1373 | SIZE_T enCVersion; |
1374 | |
1375 | BOOL jsutAfterILThrow; |
1376 | }; |
1377 | |
1378 | // |
1379 | // DebuggerIPCE_STRData holds data for each stack frame or chain. This data is passed |
1380 | // from the RC to the DI during a stack walk. |
1381 | // |
1382 | #if defined(_MSC_VER) |
1383 | #pragma warning( push ) |
1384 | #pragma warning( disable:4324 ) // the compiler pads a structure to comply with alignment requirements |
1385 | #endif // ARM context structures have a 16-byte alignment requirement |
1386 | struct MSLAYOUT DebuggerIPCE_STRData |
1387 | { |
1388 | FramePointer fp; |
1389 | // @dbgtodo stackwalker/shim- Ideally we should be able to get rid of the DebuggerREGDISPLAY and just use the CONTEXT. |
1390 | DT_CONTEXT ctx; |
1391 | DebuggerREGDISPLAY rd; |
1392 | bool quicklyUnwound; |
1393 | |
1394 | VMPTR_AppDomain vmCurrentAppDomainToken; |
1395 | |
1396 | |
1397 | enum EType |
1398 | { |
1399 | cMethodFrame = 0, |
1400 | cChain, |
1401 | cStubFrame, |
1402 | cRuntimeNativeFrame |
1403 | } eType; |
1404 | |
1405 | union MSLAYOUT |
1406 | { |
1407 | // Data for a chain |
1408 | struct MSLAYOUT |
1409 | { |
1410 | CorDebugChainReason chainReason; |
1411 | bool managed; |
1412 | } u; |
1413 | |
1414 | // Data for a Method |
1415 | struct MSLAYOUT |
1416 | { |
1417 | struct DebuggerIPCE_FuncData funcData; |
1418 | struct DebuggerIPCE_JITFuncData jitFuncData; |
1419 | SIZE_T ILOffset; |
1420 | CorDebugMappingResult mapping; |
1421 | |
1422 | bool fVarArgs; |
1423 | |
1424 | // Indicates whether the managed method has any metadata. |
1425 | // Some dynamic methods such as IL stubs and LCG methods don't have any metadata. |
1426 | // This is used only by the V3 stackwalker, not the V2 one, because we only |
1427 | // expose dynamic methods as real stack frames in V3. |
1428 | bool fNoMetadata; |
1429 | |
1430 | TADDR taAmbientESP; |
1431 | |
1432 | GENERICS_TYPE_TOKEN exactGenericArgsToken; |
1433 | DWORD dwExactGenericArgsTokenIndex; |
1434 | |
1435 | } v; |
1436 | |
1437 | // Data for an Stub Frame. |
1438 | struct MSLAYOUT |
1439 | { |
1440 | mdMethodDef funcMetadataToken; |
1441 | VMPTR_DomainFile vmDomainFile; |
1442 | VMPTR_MethodDesc vmMethodDesc; |
1443 | CorDebugInternalFrameType frameType; |
1444 | } stubFrame; |
1445 | |
1446 | }; |
1447 | }; |
1448 | #if defined(_MSC_VER) |
1449 | #pragma warning( pop ) |
1450 | #endif |
1451 | |
1452 | // |
1453 | // DebuggerIPCE_BasicTypeData and DebuggerIPCE_ExpandedTypeData |
1454 | // hold data for each type sent across the |
1455 | // boundary, whether it be a constructed type List<String> or a non-constructed |
1456 | // type such as String, Foo or Object. |
1457 | // |
1458 | // Logically speaking DebuggerIPCE_BasicTypeData might just be "typeHandle", as |
1459 | // we could then send further events to ask what the elementtype, typeToken and moduleToken |
1460 | // are for the type handle. But as |
1461 | // nearly all types are non-generic we send across even the basic type information in |
1462 | // the slightly expanded form shown below, sending the element type and the |
1463 | // tokens with the type handle itself. The fields debuggerModuleToken, metadataToken and typeHandle |
1464 | // are only used as follows: |
1465 | // elementType debuggerModuleToken metadataToken typeHandle |
1466 | // E_T_INT8 : E_T_INT8 No No No |
1467 | // Boxed E_T_INT8: E_T_CLASS No No No |
1468 | // E_T_CLASS, non-generic class: E_T_CLASS Yes Yes No |
1469 | // E_T_VALUETYPE, non-generic: E_T_VALUETYPE Yes Yes No |
1470 | // E_T_CLASS, generic class: E_T_CLASS Yes Yes Yes |
1471 | // E_T_VALUETYPE, generic class: E_T_VALUETYPE Yes Yes Yes |
1472 | // E_T_BYREF : E_T_BYREF No No Yes |
1473 | // E_T_PTR : E_T_PTR No No Yes |
1474 | // E_T_ARRAY etc. : E_T_ARRAY No No Yes |
1475 | // E_T_FNPTR etc. : E_T_FNPTR No No Yes |
1476 | // This allows us to always set "typeHandle" to NULL except when dealing with highly nested |
1477 | // types or function-pointer types (the latter are too complexe to transfer over in one hit). |
1478 | // |
1479 | |
1480 | struct MSLAYOUT DebuggerIPCE_BasicTypeData |
1481 | { |
1482 | CorElementType elementType; |
1483 | mdTypeDef metadataToken; |
1484 | VMPTR_Module vmModule; |
1485 | VMPTR_DomainFile vmDomainFile; |
1486 | VMPTR_TypeHandle vmTypeHandle; |
1487 | }; |
1488 | |
1489 | // DebuggerIPCE_ExpandedTypeData contains more information showing further |
1490 | // details for array types, byref types etc. |
1491 | // Whenever you fetch type information from the left-side |
1492 | // you get back one of these. These in turn contain further |
1493 | // DebuggerIPCE_BasicTypeData's and typeHandles which you can |
1494 | // then query to get further information about the type parameters. |
1495 | // This copes with the nested cases, e.g. jagged arrays, |
1496 | // String ****, &(String*), Pair<String,Pair<String>> |
1497 | // and so on. |
1498 | // |
1499 | // So this type information is not "fully expanded", it's just a little |
1500 | // more detail then DebuggerIPCE_BasicTypeData. For type |
1501 | // instantiatons (e.g. List<int>) and |
1502 | // function pointer types you will need to make further requests for |
1503 | // information about the type parameters. |
1504 | // For array types there is always only one type parameter so |
1505 | // we include that as part of the expanded data. |
1506 | // |
1507 | // |
1508 | struct MSLAYOUT DebuggerIPCE_ExpandedTypeData |
1509 | { |
1510 | CorElementType elementType; // Note this is _never_ E_T_VAR, E_T_WITH or E_T_MVAR |
1511 | union MSLAYOUT |
1512 | { |
1513 | // used for E_T_CLASS and E_T_VALUECLASS, E_T_PTR, E_T_BYREF etc. |
1514 | // For non-constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be NULL |
1515 | // For constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be non-NULL |
1516 | // For E_T_PTR etc. the tokens will be NULL and the typeHandle will be non-NULL. |
1517 | struct MSLAYOUT |
1518 | { |
1519 | mdTypeDef metadataToken; |
1520 | VMPTR_Module vmModule; |
1521 | VMPTR_DomainFile vmDomainFile; |
1522 | VMPTR_TypeHandle typeHandle; // if non-null then further fetches will be needed to get type arguments |
1523 | } ClassTypeData; |
1524 | |
1525 | // used for E_T_PTR, E_T_BYREF etc. |
1526 | struct MSLAYOUT |
1527 | { |
1528 | DebuggerIPCE_BasicTypeData unaryTypeArg; // used only when sending back to debugger |
1529 | } UnaryTypeData; |
1530 | |
1531 | |
1532 | // used for E_T_ARRAY etc. |
1533 | struct MSLAYOUT |
1534 | { |
1535 | DebuggerIPCE_BasicTypeData arrayTypeArg; // used only when sending back to debugger |
1536 | DWORD arrayRank; |
1537 | } ArrayTypeData; |
1538 | |
1539 | // used for E_T_FNPTR |
1540 | struct MSLAYOUT |
1541 | { |
1542 | VMPTR_TypeHandle typeHandle; // if non-null then further fetches needed to get type arguments |
1543 | } NaryTypeData; |
1544 | |
1545 | }; |
1546 | }; |
1547 | |
1548 | // DebuggerIPCE_TypeArgData is used when sending type arguments |
1549 | // across to a funceval. It contains the DebuggerIPCE_ExpandedTypeData describing the |
1550 | // essence of the type, but the typeHandle and other |
1551 | // BasicTypeData fields should be zero and will be ignored. |
1552 | // The DebuggerIPCE_ExpandedTypeData is then followed |
1553 | // by the required number of type arguments, each of which |
1554 | // will be a further DebuggerIPCE_TypeArgData record in the stream of |
1555 | // flattened type argument data. |
1556 | struct MSLAYOUT DebuggerIPCE_TypeArgData |
1557 | { |
1558 | DebuggerIPCE_ExpandedTypeData data; |
1559 | unsigned int numTypeArgs; // number of immediate children on the type tree |
1560 | }; |
1561 | |
1562 | |
1563 | // |
1564 | // DebuggerIPCE_ObjectData holds the results of a |
1565 | // GetAndSendObjectInfo, i.e., all the info about an object that the |
1566 | // Right Side would need to access it. (This include array, string, |
1567 | // and nstruct info.) |
1568 | // |
1569 | struct MSLAYOUT DebuggerIPCE_ObjectData |
1570 | { |
1571 | void *objRef; |
1572 | bool objRefBad; |
1573 | SIZE_T objSize; |
1574 | |
1575 | // Offset from the beginning of the object to the beginning of the first field |
1576 | SIZE_T objOffsetToVars; |
1577 | |
1578 | // The type of the object.... |
1579 | struct DebuggerIPCE_ExpandedTypeData objTypeData; |
1580 | |
1581 | union MSLAYOUT |
1582 | { |
1583 | struct MSLAYOUT |
1584 | { |
1585 | SIZE_T length; |
1586 | SIZE_T offsetToStringBase; |
1587 | } stringInfo; |
1588 | |
1589 | struct MSLAYOUT |
1590 | { |
1591 | SIZE_T rank; |
1592 | SIZE_T offsetToArrayBase; |
1593 | SIZE_T offsetToLowerBounds; // 0 if not present |
1594 | SIZE_T offsetToUpperBounds; // 0 if not present |
1595 | SIZE_T componentCount; |
1596 | SIZE_T elementSize; |
1597 | } arrayInfo; |
1598 | |
1599 | struct MSLAYOUT |
1600 | { |
1601 | struct DebuggerIPCE_BasicTypeData typedByrefType; // the type of the thing contained in a typedByref... |
1602 | } typedByrefInfo; |
1603 | }; |
1604 | }; |
1605 | |
1606 | // |
1607 | // Remote enregistered info used by CordbValues and for passing |
1608 | // variable homes between the left and right sides during a func eval. |
1609 | // |
1610 | |
1611 | enum RemoteAddressKind |
1612 | { |
1613 | RAK_NONE = 0, |
1614 | RAK_REG, |
1615 | RAK_REGREG, |
1616 | RAK_REGMEM, |
1617 | RAK_MEMREG, |
1618 | RAK_FLOAT, |
1619 | RAK_END |
1620 | }; |
1621 | |
1622 | const CORDB_ADDRESS kLeafFrameRegAddr = 0; |
1623 | const CORDB_ADDRESS kNonLeafFrameRegAddr = (CORDB_ADDRESS)(-1); |
1624 | |
1625 | struct MSLAYOUT RemoteAddress |
1626 | { |
1627 | RemoteAddressKind kind; |
1628 | void *frame; |
1629 | |
1630 | CorDebugRegister reg1; |
1631 | void *reg1Addr; |
1632 | SIZE_T reg1Value; // this is the actual value of the register |
1633 | |
1634 | union MSLAYOUT |
1635 | { |
1636 | struct MSLAYOUT |
1637 | { |
1638 | CorDebugRegister reg2; |
1639 | void *reg2Addr; |
1640 | SIZE_T reg2Value; // this is the actual value of the register |
1641 | } u; |
1642 | |
1643 | CORDB_ADDRESS addr; |
1644 | DWORD floatIndex; |
1645 | }; |
1646 | }; |
1647 | |
1648 | // |
1649 | // DebuggerIPCE_FuncEvalType specifies the type of a function |
1650 | // evaluation that will occur. |
1651 | // |
1652 | enum DebuggerIPCE_FuncEvalType |
1653 | { |
1654 | DB_IPCE_FET_NORMAL, |
1655 | DB_IPCE_FET_NEW_OBJECT, |
1656 | DB_IPCE_FET_NEW_OBJECT_NC, |
1657 | DB_IPCE_FET_NEW_STRING, |
1658 | DB_IPCE_FET_NEW_ARRAY, |
1659 | DB_IPCE_FET_RE_ABORT |
1660 | }; |
1661 | |
1662 | |
1663 | enum NameChangeType |
1664 | { |
1665 | APP_DOMAIN_NAME_CHANGE, |
1666 | THREAD_NAME_CHANGE |
1667 | }; |
1668 | |
1669 | // |
1670 | // DebuggerIPCE_FuncEvalArgData holds data for each argument to a |
1671 | // function evaluation. |
1672 | // |
1673 | struct MSLAYOUT DebuggerIPCE_FuncEvalArgData |
1674 | { |
1675 | RemoteAddress argHome; // enregistered variable home |
1676 | void *argAddr; // address if not enregistered |
1677 | CorElementType argElementType; |
1678 | unsigned int fullArgTypeNodeCount; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types) |
1679 | void *fullArgType; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types) |
1680 | BYTE argLiteralData[8]; // copy of generic value data |
1681 | bool argIsLiteral; // true if value is in argLiteralData |
1682 | bool argIsHandleValue; // true if argAddr is OBJECTHANDLE |
1683 | }; |
1684 | |
1685 | |
1686 | // |
1687 | // DebuggerIPCE_FuncEvalInfo holds info necessary to setup a func eval |
1688 | // operation. |
1689 | // |
1690 | struct MSLAYOUT DebuggerIPCE_FuncEvalInfo |
1691 | { |
1692 | VMPTR_Thread vmThreadToken; |
1693 | DebuggerIPCE_FuncEvalType funcEvalType; |
1694 | mdMethodDef funcMetadataToken; |
1695 | mdTypeDef funcClassMetadataToken; |
1696 | VMPTR_DomainFile vmDomainFile; |
1697 | RSPTR_CORDBEVAL funcEvalKey; |
1698 | bool evalDuringException; |
1699 | |
1700 | unsigned int argCount; |
1701 | unsigned int genericArgsCount; |
1702 | unsigned int genericArgsNodeCount; |
1703 | |
1704 | SIZE_T stringSize; |
1705 | |
1706 | SIZE_T arrayRank; |
1707 | }; |
1708 | |
1709 | |
1710 | // |
1711 | // Used in DebuggerIPCFirstChanceData. This tells the LS what action to take within the hijack |
1712 | // |
1713 | enum HijackAction |
1714 | { |
1715 | HIJACK_ACTION_EXIT_UNHANDLED, |
1716 | HIJACK_ACTION_EXIT_HANDLED, |
1717 | HIJACK_ACTION_WAIT |
1718 | }; |
1719 | |
1720 | // |
1721 | // DebuggerIPCFirstChanceData holds info communicated from the LS to the RS when signaling that an exception does not |
1722 | // belong to the runtime from a first chance hijack. This is used when Win32 debugging only. |
1723 | // |
1724 | struct MSLAYOUT DebuggerIPCFirstChanceData |
1725 | { |
1726 | LSPTR_CONTEXT pLeftSideContext; |
1727 | HijackAction action; |
1728 | UINT debugCounter; |
1729 | }; |
1730 | |
1731 | // |
1732 | // DebuggerIPCSecondChanceData holds info communicated from the RS |
1733 | // to the LS when setting up a second chance exception hijack. This is |
1734 | // used when Win32 debugging only. |
1735 | // |
1736 | struct MSLAYOUT DebuggerIPCSecondChanceData |
1737 | { |
1738 | DT_CONTEXT threadContext; |
1739 | }; |
1740 | |
1741 | |
1742 | |
1743 | //----------------------------------------------------------------------------- |
1744 | // This struct holds pointer from the LS and needs to copy to |
1745 | // the RS. We have to free the memory on the RS. |
1746 | // The transfer function is called when the RS first reads the event. At this point, |
1747 | // the LS is stopped while sending the event. Thus the LS pointers only need to be |
1748 | // valid while the LS is in SendIPCEvent. |
1749 | // |
1750 | // Since this data is in an IPC/Marshallable block, it can't have any Ctors (holders) |
1751 | // in it. |
1752 | //----------------------------------------------------------------------------- |
1753 | struct MSLAYOUT Ls_Rs_BaseBuffer |
1754 | { |
1755 | #ifdef RIGHT_SIDE_COMPILE |
1756 | protected: |
1757 | // copy data can happen on both LS and RS. In LS case, |
1758 | // ReadProcessMemory is really reading from its own process memory. |
1759 | // |
1760 | void CopyLSDataToRSWorker(ICorDebugDataTarget * pTargethProcess); |
1761 | |
1762 | // retrieve the RS data and own it |
1763 | BYTE *TransferRSDataWorker() |
1764 | { |
1765 | BYTE *pbRS = m_pbRS; |
1766 | m_pbRS = NULL; |
1767 | return pbRS; |
1768 | } |
1769 | public: |
1770 | |
1771 | |
1772 | void CleanUp() |
1773 | { |
1774 | if (m_pbRS != NULL) |
1775 | { |
1776 | delete [] m_pbRS; |
1777 | m_pbRS = NULL; |
1778 | } |
1779 | } |
1780 | #else |
1781 | public: |
1782 | // Only LS can call this API |
1783 | void SetLsData(BYTE *pbLS, DWORD cbSize) |
1784 | { |
1785 | m_pbRS = NULL; |
1786 | m_pbLS = pbLS; |
1787 | m_cbSize = cbSize; |
1788 | } |
1789 | #endif // RIGHT_SIDE_COMPILE |
1790 | |
1791 | public: |
1792 | // Common APIs. |
1793 | DWORD GetSize() { return m_cbSize; } |
1794 | |
1795 | |
1796 | |
1797 | protected: |
1798 | // Size of data in bytes |
1799 | DWORD m_cbSize; |
1800 | |
1801 | // If this is non-null, pointer into LS for buffer. |
1802 | // LS can free this after the debug event is continued. |
1803 | BYTE *m_pbLS; // @dbgtodo cross-plat- for cross-platform purposes, this should be a TADDR |
1804 | |
1805 | // If this is non-null, pointer into RS for buffer. RS must then free this. |
1806 | // This buffer was copied from the LS (via CopyLSDataToRSWorker). |
1807 | BYTE *m_pbRS; |
1808 | }; |
1809 | |
1810 | //----------------------------------------------------------------------------- |
1811 | // Byte wrapper around the buffer. |
1812 | //----------------------------------------------------------------------------- |
1813 | struct MSLAYOUT Ls_Rs_ByteBuffer : public Ls_Rs_BaseBuffer |
1814 | { |
1815 | #ifdef RIGHT_SIDE_COMPILE |
1816 | BYTE *GetRSPointer() |
1817 | { |
1818 | return m_pbRS; |
1819 | } |
1820 | |
1821 | void CopyLSDataToRS(ICorDebugDataTarget * pTarget); |
1822 | BYTE *TransferRSData() |
1823 | { |
1824 | return TransferRSDataWorker(); |
1825 | } |
1826 | #endif |
1827 | }; |
1828 | |
1829 | //----------------------------------------------------------------------------- |
1830 | // Wrapper around a Ls_rS_Buffer to get it as a string. |
1831 | // This can also do some sanity checking. |
1832 | //----------------------------------------------------------------------------- |
1833 | struct MSLAYOUT Ls_Rs_StringBuffer : public Ls_Rs_BaseBuffer |
1834 | { |
1835 | #ifdef RIGHT_SIDE_COMPILE |
1836 | const WCHAR * GetString() |
1837 | { |
1838 | return reinterpret_cast<const WCHAR*> (m_pbRS); |
1839 | } |
1840 | |
1841 | // Copy over the string. |
1842 | void CopyLSDataToRS(ICorDebugDataTarget * pTarget); |
1843 | |
1844 | // Caller will pick up ownership. |
1845 | // Since caller will delete this data, we can't give back a constant pointer. |
1846 | WCHAR * TransferStringData() |
1847 | { |
1848 | return reinterpret_cast<WCHAR*> (TransferRSDataWorker()); |
1849 | } |
1850 | #endif |
1851 | }; |
1852 | |
1853 | |
1854 | // Data for an Managed Debug Assistant Probe (MDA). |
1855 | struct MSLAYOUT DebuggerMDANotification |
1856 | { |
1857 | Ls_Rs_StringBuffer szName; |
1858 | Ls_Rs_StringBuffer szDescription; |
1859 | Ls_Rs_StringBuffer szXml; |
1860 | DWORD dwOSThreadId; |
1861 | CorDebugMDAFlags flags; |
1862 | }; |
1863 | |
1864 | |
1865 | // The only remaining problem is that register number mappings are different for each platform. It turns out |
1866 | // that the debugger only uses REGNUM_SP and REGNUM_AMBIENT_SP though, so we can just virtualize these two for |
1867 | // the target platform. |
1868 | // Keep this is sync with the definitions in inc/corinfo.h. |
1869 | #if defined(DBG_TARGET_X86) |
1870 | #define DBG_TARGET_REGNUM_SP 4 |
1871 | #define DBG_TARGET_REGNUM_AMBIENT_SP 9 |
1872 | #ifdef _TARGET_X86_ |
1873 | static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP); |
1874 | static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP); |
1875 | #endif // _TARGET_X86_ |
1876 | #elif defined(DBG_TARGET_AMD64) |
1877 | #define DBG_TARGET_REGNUM_SP 4 |
1878 | #define DBG_TARGET_REGNUM_AMBIENT_SP 17 |
1879 | #ifdef _TARGET_AMD64_ |
1880 | static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP); |
1881 | static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP); |
1882 | #endif // _TARGET_AMD64_ |
1883 | #elif defined(DBG_TARGET_ARM) |
1884 | #define DBG_TARGET_REGNUM_SP 13 |
1885 | #define DBG_TARGET_REGNUM_AMBIENT_SP 17 |
1886 | #ifdef _TARGET_ARM_ |
1887 | C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP); |
1888 | C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP); |
1889 | #endif // _TARGET_ARM_ |
1890 | #elif defined(DBG_TARGET_ARM64) |
1891 | #define DBG_TARGET_REGNUM_SP 31 |
1892 | #define DBG_TARGET_REGNUM_AMBIENT_SP 34 |
1893 | #ifdef _TARGET_ARM64_ |
1894 | C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP); |
1895 | C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP); |
1896 | #endif // _TARGET_ARM64_ |
1897 | #else |
1898 | #error Target registers are not defined for this platform |
1899 | #endif |
1900 | |
1901 | |
1902 | // |
1903 | // Event structure that is passed between the Runtime Controller and the |
1904 | // Debugger Interface. Some types of events are a fixed size and have |
1905 | // entries in the main union, while others are variable length and have |
1906 | // more specialized data structures that are attached to the end of this |
1907 | // structure. |
1908 | // |
1909 | struct MSLAYOUT DebuggerIPCEvent |
1910 | { |
1911 | DebuggerIPCEvent* next; |
1912 | DebuggerIPCEventType type; |
1913 | DWORD processId; |
1914 | DWORD threadId; |
1915 | VMPTR_AppDomain vmAppDomain; |
1916 | VMPTR_Thread vmThread; |
1917 | |
1918 | HRESULT hr; |
1919 | bool replyRequired; |
1920 | bool asyncSend; |
1921 | |
1922 | union MSLAYOUT |
1923 | { |
1924 | struct MSLAYOUT |
1925 | { |
1926 | // Pointer to a BOOL in the target. |
1927 | CORDB_ADDRESS pfBeingDebugged; |
1928 | } LeftSideStartupData; |
1929 | |
1930 | struct MSLAYOUT |
1931 | { |
1932 | // Module whos metadata is being updated |
1933 | // This tells the RS that the metadata for that module has become invalid. |
1934 | VMPTR_DomainFile vmDomainFile; |
1935 | |
1936 | } MetadataUpdateData; |
1937 | |
1938 | struct MSLAYOUT |
1939 | { |
1940 | // Handle to CLR's internal appdomain object. |
1941 | VMPTR_AppDomain vmAppDomain; |
1942 | } AppDomainData; |
1943 | |
1944 | struct MSLAYOUT |
1945 | { |
1946 | VMPTR_DomainAssembly vmDomainAssembly; |
1947 | } AssemblyData; |
1948 | |
1949 | #ifdef TEST_DATA_CONSISTENCY |
1950 | // information necessary for testing whether the LS holds a lock on data |
1951 | // the RS needs to inspect. See code:DataTest::TestDataSafety and |
1952 | // code:IDacDbiInterface::TestCrst for more information |
1953 | struct MSLAYOUT |
1954 | { |
1955 | // the lock to be tested |
1956 | VMPTR_Crst vmCrst; |
1957 | // indicates whether the LS holds the lock |
1958 | bool fOkToTake; |
1959 | } TestCrstData; |
1960 | |
1961 | // information necessary for testing whether the LS holds a lock on data |
1962 | // the RS needs to inspect. See code:DataTest::TestDataSafety and |
1963 | // code:IDacDbiInterface::TestCrst for more information |
1964 | struct MSLAYOUT |
1965 | { |
1966 | // the lock to be tested |
1967 | VMPTR_SimpleRWLock vmRWLock; |
1968 | // indicates whether the LS holds the lock |
1969 | bool fOkToTake; |
1970 | } TestRWLockData; |
1971 | #endif // TEST_DATA_CONSISTENCY |
1972 | |
1973 | // Debug event that a module has been loaded |
1974 | struct MSLAYOUT |
1975 | { |
1976 | // Module that was just loaded. |
1977 | VMPTR_DomainFile vmDomainFile; |
1978 | }LoadModuleData; |
1979 | |
1980 | |
1981 | struct MSLAYOUT |
1982 | { |
1983 | VMPTR_DomainFile vmDomainFile; |
1984 | LSPTR_ASSEMBLY debuggerAssemblyToken; |
1985 | } UnloadModuleData; |
1986 | |
1987 | |
1988 | // The given module's pdb has been updated. |
1989 | // Queury PDB from OOP |
1990 | struct MSLAYOUT |
1991 | { |
1992 | VMPTR_DomainFile vmDomainFile; |
1993 | } UpdateModuleSymsData; |
1994 | |
1995 | DebuggerMDANotification MDANotification; |
1996 | |
1997 | struct MSLAYOUT |
1998 | { |
1999 | LSPTR_BREAKPOINT breakpointToken; |
2000 | mdMethodDef funcMetadataToken; |
2001 | VMPTR_DomainFile vmDomainFile; |
2002 | bool isIL; |
2003 | SIZE_T offset; |
2004 | SIZE_T encVersion; |
2005 | LSPTR_METHODDESC nativeCodeMethodDescToken; // points to the MethodDesc if !isIL |
2006 | } BreakpointData; |
2007 | |
2008 | struct MSLAYOUT |
2009 | { |
2010 | LSPTR_BREAKPOINT breakpointToken; |
2011 | } BreakpointSetErrorData; |
2012 | |
2013 | struct MSLAYOUT |
2014 | { |
2015 | #ifdef FEATURE_DATABREAKPOINT |
2016 | CONTEXT context; |
2017 | #else |
2018 | int dummy; |
2019 | #endif |
2020 | } DataBreakpointData; |
2021 | |
2022 | struct MSLAYOUT |
2023 | { |
2024 | LSPTR_STEPPER stepperToken; |
2025 | VMPTR_Thread vmThreadToken; |
2026 | FramePointer frameToken; |
2027 | bool stepIn; |
2028 | bool rangeIL; |
2029 | bool IsJMCStop; |
2030 | unsigned int totalRangeCount; |
2031 | CorDebugStepReason reason; |
2032 | CorDebugUnmappedStop rgfMappingStop; |
2033 | CorDebugIntercept rgfInterceptStop; |
2034 | unsigned int rangeCount; |
2035 | COR_DEBUG_STEP_RANGE range; //note that this is an array |
2036 | } StepData; |
2037 | |
2038 | struct MSLAYOUT |
2039 | { |
2040 | // An unvalidated GC-handle |
2041 | VMPTR_OBJECTHANDLE GCHandle; |
2042 | } GetGCHandleInfo; |
2043 | |
2044 | struct MSLAYOUT |
2045 | { |
2046 | // An unvalidated GC-handle for which we're returning the results |
2047 | LSPTR_OBJECTHANDLE GCHandle; |
2048 | |
2049 | // The following are initialized by the LS in response to our query: |
2050 | VMPTR_AppDomain vmAppDomain; // AD that handle is in (only applicable if fValid). |
2051 | bool fValid; // Did the LS determine the GC handle to be valid? |
2052 | } GetGCHandleInfoResult; |
2053 | |
2054 | // Allocate memory on the left-side |
2055 | struct MSLAYOUT |
2056 | { |
2057 | ULONG bufSize; // number of bytes to allocate |
2058 | } GetBuffer; |
2059 | |
2060 | // Memory allocated on the left-side |
2061 | struct MSLAYOUT |
2062 | { |
2063 | void *pBuffer; // LS pointer to the buffer allocated |
2064 | HRESULT hr; // success / failure |
2065 | } GetBufferResult; |
2066 | |
2067 | // Free a buffer allocated on the left-side with GetBuffer |
2068 | struct MSLAYOUT |
2069 | { |
2070 | void *pBuffer; // Pointer previously returned in GetBufferResult |
2071 | } ReleaseBuffer; |
2072 | |
2073 | struct MSLAYOUT |
2074 | { |
2075 | HRESULT hr; |
2076 | } ReleaseBufferResult; |
2077 | |
2078 | // Apply an EnC edit |
2079 | struct MSLAYOUT |
2080 | { |
2081 | VMPTR_DomainFile vmDomainFile; // Module to edit |
2082 | DWORD cbDeltaMetadata; // size of blob pointed to by pDeltaMetadata |
2083 | CORDB_ADDRESS pDeltaMetadata; // pointer to delta metadata in debuggee |
2084 | // it's the RS's responsibility to allocate and free |
2085 | // this (and pDeltaIL) using GetBuffer / ReleaseBuffer |
2086 | CORDB_ADDRESS pDeltaIL; // pointer to delta IL in debugee |
2087 | DWORD cbDeltaIL; // size of blob pointed to by pDeltaIL |
2088 | } ApplyChanges; |
2089 | |
2090 | struct MSLAYOUT |
2091 | { |
2092 | HRESULT hr; |
2093 | } ApplyChangesResult; |
2094 | |
2095 | struct MSLAYOUT |
2096 | { |
2097 | mdTypeDef classMetadataToken; |
2098 | VMPTR_DomainFile vmDomainFile; |
2099 | LSPTR_ASSEMBLY classDebuggerAssemblyToken; |
2100 | } LoadClass; |
2101 | |
2102 | struct MSLAYOUT |
2103 | { |
2104 | mdTypeDef classMetadataToken; |
2105 | VMPTR_DomainFile vmDomainFile; |
2106 | LSPTR_ASSEMBLY classDebuggerAssemblyToken; |
2107 | } UnloadClass; |
2108 | |
2109 | struct MSLAYOUT |
2110 | { |
2111 | VMPTR_DomainFile vmDomainFile; |
2112 | bool flag; |
2113 | } SetClassLoad; |
2114 | |
2115 | struct MSLAYOUT |
2116 | { |
2117 | VMPTR_OBJECTHANDLE vmExceptionHandle; |
2118 | bool firstChance; |
2119 | bool continuable; |
2120 | } Exception; |
2121 | |
2122 | struct MSLAYOUT |
2123 | { |
2124 | VMPTR_Thread vmThreadToken; |
2125 | } ClearException; |
2126 | |
2127 | struct MSLAYOUT |
2128 | { |
2129 | void *address; |
2130 | } IsTransitionStub; |
2131 | |
2132 | struct MSLAYOUT |
2133 | { |
2134 | bool isStub; |
2135 | } IsTransitionStubResult; |
2136 | |
2137 | struct MSLAYOUT |
2138 | { |
2139 | CORDB_ADDRESS startAddress; |
2140 | bool fCanSetIPOnly; |
2141 | VMPTR_Thread vmThreadToken; |
2142 | VMPTR_DomainFile vmDomainFile; |
2143 | mdMethodDef mdMethod; |
2144 | VMPTR_MethodDesc vmMethodDesc; |
2145 | SIZE_T offset; |
2146 | bool fIsIL; |
2147 | void * firstExceptionHandler; |
2148 | } SetIP; // this is also used for CanSetIP |
2149 | |
2150 | struct MSLAYOUT |
2151 | { |
2152 | int iLevel; |
2153 | |
2154 | EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szCategory; |
2155 | Ls_Rs_StringBuffer szContent; |
2156 | } FirstLogMessage; |
2157 | |
2158 | struct MSLAYOUT |
2159 | { |
2160 | int iLevel; |
2161 | int iReason; |
2162 | |
2163 | EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szSwitchName; |
2164 | EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szParentSwitchName; |
2165 | } LogSwitchSettingMessage; |
2166 | |
2167 | // information needed to send to the RS as part of a custom notification from the target |
2168 | struct MSLAYOUT |
2169 | { |
2170 | // Domain file for the domain in which the notification occurred |
2171 | VMPTR_DomainFile vmDomainFile; |
2172 | |
2173 | // metadata token for the type of the CustomNotification object's type |
2174 | mdTypeDef classToken; |
2175 | } CustomNotification; |
2176 | |
2177 | struct MSLAYOUT |
2178 | { |
2179 | VMPTR_Thread vmThreadToken; |
2180 | CorDebugThreadState debugState; |
2181 | } SetAllDebugState; |
2182 | |
2183 | DebuggerIPCE_FuncEvalInfo FuncEval; |
2184 | |
2185 | struct MSLAYOUT |
2186 | { |
2187 | CORDB_ADDRESS argDataArea; |
2188 | LSPTR_DEBUGGEREVAL debuggerEvalKey; |
2189 | } FuncEvalSetupComplete; |
2190 | |
2191 | struct MSLAYOUT |
2192 | { |
2193 | RSPTR_CORDBEVAL funcEvalKey; |
2194 | bool successful; |
2195 | bool aborted; |
2196 | void *resultAddr; |
2197 | |
2198 | // AppDomain that the result is in. |
2199 | VMPTR_AppDomain vmAppDomain; |
2200 | |
2201 | VMPTR_OBJECTHANDLE vmObjectHandle; |
2202 | DebuggerIPCE_ExpandedTypeData resultType; |
2203 | } FuncEvalComplete; |
2204 | |
2205 | struct MSLAYOUT |
2206 | { |
2207 | LSPTR_DEBUGGEREVAL debuggerEvalKey; |
2208 | } FuncEvalAbort; |
2209 | |
2210 | struct MSLAYOUT |
2211 | { |
2212 | LSPTR_DEBUGGEREVAL debuggerEvalKey; |
2213 | } FuncEvalRudeAbort; |
2214 | |
2215 | struct MSLAYOUT |
2216 | { |
2217 | LSPTR_DEBUGGEREVAL debuggerEvalKey; |
2218 | } FuncEvalCleanup; |
2219 | |
2220 | struct MSLAYOUT |
2221 | { |
2222 | void *objectRefAddress; |
2223 | VMPTR_OBJECTHANDLE vmObjectHandle; |
2224 | void *newReference; |
2225 | } SetReference; |
2226 | |
2227 | struct MSLAYOUT |
2228 | { |
2229 | NameChangeType eventType; |
2230 | VMPTR_AppDomain vmAppDomain; |
2231 | VMPTR_Thread vmThread; |
2232 | } NameChange; |
2233 | |
2234 | struct MSLAYOUT |
2235 | { |
2236 | VMPTR_DomainFile vmDomainFile; |
2237 | BOOL fAllowJitOpts; |
2238 | BOOL fEnableEnC; |
2239 | } JitDebugInfo; |
2240 | |
2241 | // EnC Remap opportunity |
2242 | struct MSLAYOUT |
2243 | { |
2244 | VMPTR_DomainFile vmDomainFile; |
2245 | mdMethodDef funcMetadataToken ; // methodDef of function with remap opportunity |
2246 | SIZE_T currentVersionNumber; // version currently executing |
2247 | SIZE_T resumeVersionNumber; // latest version |
2248 | SIZE_T currentILOffset; // the IL offset of the current IP |
2249 | SIZE_T *resumeILOffset; // pointer into left-side where an offset to resume |
2250 | // to should be written if remap is desired. |
2251 | } EnCRemap; |
2252 | |
2253 | // EnC Remap has taken place |
2254 | struct MSLAYOUT |
2255 | { |
2256 | VMPTR_DomainFile vmDomainFile; |
2257 | mdMethodDef funcMetadataToken; // methodDef of function that was remapped |
2258 | } EnCRemapComplete; |
2259 | |
2260 | // Notification that the LS is about to update a CLR data structure to account for a |
2261 | // specific edit made by EnC (function add/update or field add). |
2262 | struct MSLAYOUT |
2263 | { |
2264 | VMPTR_DomainFile vmDomainFile; |
2265 | mdToken memberMetadataToken; // Either a methodDef token indicating the function that |
2266 | // was updated/added, or a fieldDef token indicating the |
2267 | // field which was added. |
2268 | mdTypeDef classMetadataToken; // TypeDef token of the class in which the update was made |
2269 | SIZE_T newVersionNumber; // The new function/module version |
2270 | } EnCUpdate; |
2271 | |
2272 | struct MSLAYOUT |
2273 | { |
2274 | void *oldData; |
2275 | void *newData; |
2276 | DebuggerIPCE_BasicTypeData type; |
2277 | } SetValueClass; |
2278 | |
2279 | |
2280 | // Event used to tell LS if a single function is user or non-user code. |
2281 | // Same structure used to get function status. |
2282 | // @todo - Perhaps we can bundle these up so we can set multiple funcs w/ 1 event? |
2283 | struct MSLAYOUT |
2284 | { |
2285 | VMPTR_DomainFile vmDomainFile; |
2286 | mdMethodDef funcMetadataToken; |
2287 | DWORD dwStatus; |
2288 | } SetJMCFunctionStatus; |
2289 | |
2290 | struct MSLAYOUT |
2291 | { |
2292 | TASKID taskid; |
2293 | } GetThreadForTaskId; |
2294 | |
2295 | struct MSLAYOUT |
2296 | { |
2297 | VMPTR_Thread vmThreadToken; |
2298 | } GetThreadForTaskIdResult; |
2299 | |
2300 | struct MSLAYOUT |
2301 | { |
2302 | CONNID connectionId; |
2303 | } ConnectionChange; |
2304 | |
2305 | struct MSLAYOUT |
2306 | { |
2307 | CONNID connectionId; |
2308 | EmbeddedIPCString<MAX_LONGPATH> wzConnectionName; |
2309 | } CreateConnection; |
2310 | |
2311 | struct MSLAYOUT |
2312 | { |
2313 | void *objectToken; |
2314 | BOOL fStrong; |
2315 | } CreateHandle; |
2316 | |
2317 | struct MSLAYOUT |
2318 | { |
2319 | VMPTR_OBJECTHANDLE vmObjectHandle; |
2320 | } CreateHandleResult; |
2321 | |
2322 | // used in DB_IPCE_DISPOSE_HANDLE event |
2323 | struct MSLAYOUT |
2324 | { |
2325 | VMPTR_OBJECTHANDLE vmObjectHandle; |
2326 | BOOL fStrong; |
2327 | } DisposeHandle; |
2328 | |
2329 | struct MSLAYOUT |
2330 | { |
2331 | FramePointer framePointer; |
2332 | SIZE_T nOffset; |
2333 | CorDebugExceptionCallbackType eventType; |
2334 | DWORD dwFlags; |
2335 | VMPTR_OBJECTHANDLE vmExceptionHandle; |
2336 | } ExceptionCallback2; |
2337 | |
2338 | struct MSLAYOUT |
2339 | { |
2340 | CorDebugExceptionUnwindCallbackType eventType; |
2341 | DWORD dwFlags; |
2342 | } ExceptionUnwind; |
2343 | |
2344 | struct MSLAYOUT |
2345 | { |
2346 | VMPTR_Thread vmThreadToken; |
2347 | FramePointer frameToken; |
2348 | } InterceptException; |
2349 | |
2350 | struct MSLAYOUT |
2351 | { |
2352 | VMPTR_Module vmModule; |
2353 | void * pMetadataStart; |
2354 | ULONG nMetadataSize; |
2355 | } MetadataUpdateRequest; |
2356 | }; |
2357 | }; |
2358 | |
2359 | |
2360 | // When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound |
2361 | // for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is |
2362 | // orthogonal to the host's page size. Round the buffer size up to a multiple of 8 since MSVC seems more |
2363 | // aggressive in this regard than gcc. |
2364 | #define CorDBIPC_TRANSPORT_BUFFER_SIZE (((sizeof(DebuggerIPCEvent) + 7) / 8) * 8) |
2365 | |
2366 | // A DebuggerIPCEvent must fit in the send & receive buffers, which are CorDBIPC_BUFFER_SIZE bytes. |
2367 | static_assert_no_msg(sizeof(DebuggerIPCEvent) <= CorDBIPC_BUFFER_SIZE); |
2368 | static_assert_no_msg(CorDBIPC_TRANSPORT_BUFFER_SIZE <= CorDBIPC_BUFFER_SIZE); |
2369 | |
2370 | // 2*sizeof(WCHAR) for the two string terminating characters in the FirstLogMessage |
2371 | #define LOG_MSG_PADDING 4 |
2372 | |
2373 | #endif /* _DbgIPCEvents_h_ */ |
2374 | |