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
9 * ------------------------------------------------------------------------- */
11 #ifndef _DbgIPCEvents_h_
12 #define _DbgIPCEvents_h_
17 #include <corjit.h> // for ICorDebugInfo::VarLocType & VarLoc
18 #include <specstrings.h>
20 #include "dbgtargetcontext.h"
23 // Get version numbers for IPCHeader stamp
24 #include "ndpversion.h"
26 #include "dbgappdomain.h"
30 //-----------------------------------------------------------------------------
31 // V3 additions to IPC protocol between LS and RS.
32 //-----------------------------------------------------------------------------
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)
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)
45 // Reasons for hijack.
46 namespace EHijackReason
50 kUnhandledException = 1,
52 kFirstChanceSuspend = 3,
56 inline bool IsValid(EHijackReason value)
59 return (value > 0) && (value < kMax);
65 #define MAX_LOG_SWITCH_NAME_LEN 256
67 //-----------------------------------------------------------------------------
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
78 //-----------------------------------------------------------------------------
81 // We want this available for DbgInterface.h - put it here.
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.
93 #define CorDBIPCSetupSyncEventName W("CorDBIPCSetupSyncEvent_%d")
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.
99 #define CorDB_Short_Circuit_First_Chance_Ownership 1
102 // Defines for current version numbers for the left and right sides
104 #define CorDB_LeftSideProtocolCurrent 2
105 #define CorDB_LeftSideProtocolMinSupported 2
106 #define CorDB_RightSideProtocolCurrent 2
107 #define CorDB_RightSideProtocolMinSupported 2
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.
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.
121 struct MSLAYOUT DebuggerIPCRuntimeOffsets
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 #endif // FEATURE_INTEROP_DEBUGGING
133 SIZE_T m_TLSIndex; // The TLS index the CLR is using to hold Thread objects
134 SIZE_T m_TLSIsSpecialIndex; // The index into the Predef block of the the "IsSpecial" status for a thread.
135 SIZE_T m_TLSCantStopIndex; // The index into the Predef block of the the Can't-Stop count.
136 SIZE_T m_TLSIndexOfPredefs; // The TLS index of the Predef block.
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_EEThreadDebuggerWordOffset; // Offset of debugger word in a Thread
142 SIZE_T m_EEThreadFrameOffset; // Offset of the Frame ptr in a Thread
143 SIZE_T m_EEThreadMaxNeededSize; // Max memory to read to get what we need out of a Thread object
144 DWORD m_EEThreadSteppingStateMask; // Mask for Thread::TSNC_DebuggerIsStepping
145 DWORD m_EEMaxFrameValue; // The max Frame value
146 SIZE_T m_EEThreadDebuggerFilterContextOffset; // Offset of debugger's filter context within a Thread Object.
147 SIZE_T m_EEThreadCantStopOffset; // Offset of the can't stop count in a Thread
148 SIZE_T m_EEFrameNextOffset; // Offset of the next ptr in a Frame
149 DWORD m_EEIsManagedExceptionStateMask; // Mask for Thread::TSNC_DebuggerIsManagedException
150 void *m_pPatches; // Addr of patch table
151 BOOL *m_pPatchTableValid; // Addr of g_patchTableValid
152 SIZE_T m_offRgData; // Offset of m_pcEntries
153 SIZE_T m_offCData; // Offset of count of m_pcEntries
154 SIZE_T m_cbPatch; // Size per patch entry
155 SIZE_T m_offAddr; // Offset within patch of target addr
156 SIZE_T m_offOpcode; // Offset within patch of target opcode
157 SIZE_T m_cbOpcode; // Max size of opcode
158 SIZE_T m_offTraceType; // Offset of the trace.type within a patch
159 DWORD m_traceTypeUnmanaged; // TRACE_UNMANAGED
161 DebuggerIPCRuntimeOffsets()
163 ZeroMemory(this, sizeof(DebuggerIPCRuntimeOffsets));
168 // The size of the send and receive IPC buffers.
169 // These must be big enough to fit a DebuggerIPCEvent. Also, the bigger they are, the fewer events
170 // it takes to send variable length stuff like the stack trace.
171 // But for perf reasons, they need to be small enough to not just push us over a page boundary in an IPC block.
172 // Unfortunately, there's a lot of other goo in the IPC block, so we can't use some clean formula. So we
173 // have to resort to just tuning things.
176 // When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound
177 // for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is
178 // orthogonal to the host's page size. Because of this we defer definition of CorDBIPC_BUFFER_SIZE until we've
179 // declared DebuggerIPCEvent at the end of this header (and we can do so because in the transport case there
180 // aren't any embedded buffers in the DebuggerIPCControlBlock).
182 #if defined(DBG_TARGET_X86) || defined(DBG_TARGET_ARM)
183 #define CorDBIPC_BUFFER_SIZE (2088) // hand tuned to ensure that ipc block in IPCHeader.h fits in 1 page.
184 #else // !_TARGET_X86_ && !_TARGET_ARM_
185 // This is the size of a DebuggerIPCEvent. You will hit an assert in Cordb::Initialize() (DI\process.cpp)
186 // if this is not defined correctly. AMD64 actually has a page size of 0x1000, not 0x2000.
187 #define CorDBIPC_BUFFER_SIZE 4016 // (4016 + 6) * 2 + 148 = 8192 (two (DebuggerIPCEvent + alignment padding) +
188 // other fields = page size)
189 #endif // DBG_TARGET_X86 || DBG_TARGET_ARM
192 // DebuggerIPCControlBlock describes the layout of the shared memory shared between the Left Side and the Right
193 // Side. This includes error information, handles for the IPC channel, and space for the send/receive buffers.
195 struct MSLAYOUT DebuggerIPCControlBlock
197 // Version data should be first in the control block to ensure that we can read it even if the control block
199 SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized
200 ULONG m_verMajor; // CLR build number for the Left Side.
201 ULONG m_verMinor; // CLR build number for the Left Side.
203 // This next stuff fits in a DWORD.
204 bool m_checkedBuild; // CLR build type for the Left Side.
205 // using the first padding byte to indicate if hosted in fiber mode.
206 // We actually just need one bit. So if needed, can turn this to a bit.
208 bool m_bHostingInFiber;
212 ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side.
213 ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support.
215 ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side.
216 ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires.
219 unsigned int m_errorCode;
221 #if defined(DBG_TARGET_WIN64)
222 // 64-bit needs this padding to make the handles after this aligned.
223 // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0.
225 #endif // DBG_TARGET_WIN64
228 RemoteHANDLE m_rightSideEventAvailable;
229 RemoteHANDLE m_rightSideEventRead;
231 // @dbgtodo inspection - this is where LSEA and LSER used to be. We need to the padding to maintain binary compatibility.
232 // Eventually, we expect to remove this whole block.
233 RemoteHANDLE m_paddingObsoleteLSEA;
234 RemoteHANDLE m_paddingObsoleteLSER;
236 RemoteHANDLE m_rightSideProcessHandle;
238 //.............................................................................
239 // Everything above this point must have the exact same binary layout as v1.1.
240 // See protocol details below.
241 //.............................................................................
243 RemoteHANDLE m_leftSideUnmanagedWaitEvent;
247 // This is set immediately when the helper thread is created.
248 // This will be set even if there's a temporary helper thread or if the real helper
249 // thread is not yet pumping (eg, blocked on a loader lock).
250 DWORD m_realHelperThreadId;
252 // This is only published once the helper thread starts running in its main loop.
253 // Thus we can use this field to see if the real helper thread is actually pumping.
254 DWORD m_helperThreadId;
256 // This is non-zero if the LS has a temporary helper thread.
257 DWORD m_temporaryHelperThreadId;
259 // ID of the Helper's canary thread.
260 DWORD m_CanaryThreadId;
262 DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets;
263 void *m_helperThreadStartAddr;
264 void *m_helperRemoteStartAddr;
265 DWORD *m_specialThreadList;
267 BYTE m_receiveBuffer[CorDBIPC_BUFFER_SIZE];
268 BYTE m_sendBuffer[CorDBIPC_BUFFER_SIZE];
270 DWORD m_specialThreadListLength;
271 bool m_shutdownBegun;
272 bool m_rightSideIsWin32Debugger; // RS status
273 bool m_specialThreadListDirty;
275 bool m_rightSideShouldCreateHelperThread;
277 // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without
279 // Only initialized by the LS, opened by the RS.
290 #if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
292 // We need an alternate definition for the control block if using the transport, because the control block has to be sent over the transport
293 // In particular we can't nest the send/receive buffers inside of it and we don't use any of the remote handles
295 struct MSLAYOUT DebuggerIPCControlBlockTransport
297 // Version data should be first in the control block to ensure that we can read it even if the control block
299 SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized
300 ULONG m_verMajor; // CLR build number for the Left Side.
301 ULONG m_verMinor; // CLR build number for the Left Side.
303 // This next stuff fits in a DWORD.
304 bool m_checkedBuild; // CLR build type for the Left Side.
305 // using the first padding byte to indicate if hosted in fiber mode.
306 // We actually just need one bit. So if needed, can turn this to a bit.
308 bool m_bHostingInFiber;
312 ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side.
313 ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support.
315 ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side.
316 ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires.
319 unsigned int m_errorCode;
321 #if defined(DBG_TARGET_WIN64)
322 // 64-bit needs this padding to make the handles after this aligned.
323 // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0.
325 #endif // DBG_TARGET_WIN64
327 // This is set immediately when the helper thread is created.
328 // This will be set even if there's a temporary helper thread or if the real helper
329 // thread is not yet pumping (eg, blocked on a loader lock).
330 DWORD m_realHelperThreadId;
332 // This is only published once the helper thread starts running in its main loop.
333 // Thus we can use this field to see if the real helper thread is actually pumping.
334 DWORD m_helperThreadId;
336 // This is non-zero if the LS has a temporary helper thread.
337 DWORD m_temporaryHelperThreadId;
339 // ID of the Helper's canary thread.
340 DWORD m_CanaryThreadId;
342 DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets;
343 void *m_helperThreadStartAddr;
344 void *m_helperRemoteStartAddr;
345 DWORD *m_specialThreadList;
347 DWORD m_specialThreadListLength;
348 bool m_shutdownBegun;
349 bool m_rightSideIsWin32Debugger; // RS status
350 bool m_specialThreadListDirty;
352 bool m_rightSideShouldCreateHelperThread;
354 // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without
356 // Only initialized by the LS, opened by the RS.
361 #endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
363 #if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
364 #include "dbgtransportsession.h"
365 #endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
367 #if defined(DBG_TARGET_X86) && !defined(FEATURE_CORESYSTEM)
368 // We have an versioning requirement.
369 // 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
370 // to look at a v2.0 app enough to recognize the version mismatch.
371 // This check is only necessary for platforms that ran on v1.1 (Win32-x86)
373 // Just to catch any potential illegal change in the IPC block, we assert the offsets against the offsets from v1.1.
374 // The constants here are pulled from v1.1.
375 // The RS will look at these versioning fields, so they absolutely must line up.
376 static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolCurrent) == 0x10);
377 static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolMinSupported) == 0x14);
378 static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolCurrent) == 0x18);
379 static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolMinSupported) == 0x1c);
381 // Unfortunately, on detecting such failure, v1.1 will also null out LSEA, LSER and RSPH.
382 // If these get adjusted, a version-mismatch attach will effectively null out random fields.
383 static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSEA) == 0x30);
384 static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSER) == 0x34);
385 static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProcessHandle) == 0x38);
391 #define INITIAL_APP_DOMAIN_INFO_LIST_SIZE 16
394 //-----------------------------------------------------------------------------
395 // Provide some Type-safety in the IPC block when we pass remote pointers around.
396 //-----------------------------------------------------------------------------
399 //-----------------------------------------------------------------------------
400 // This is the same in both the LS & RS.
401 // Definitions on the LS & RS should be binary compatible. So all storage is
402 // declared in GeneralLsPointer, and then the Ls & RS each have their own
403 // derived accessors.
404 //-----------------------------------------------------------------------------
405 class MSLAYOUT GeneralLsPointer
408 friend ULONG_PTR LsPtrToCookie(GeneralLsPointer p);
412 bool IsNull() { return m_ptr == NULL; }
415 class MSLAYOUT GeneralRsPointer
421 bool IsNull() { return m_data == 0; }
424 // In some cases, we need to get a uuid from a pointer (ie, in a hash)
425 inline ULONG_PTR LsPtrToCookie(GeneralLsPointer p) {
426 return (ULONG_PTR) p.m_ptr;
428 #define VmPtrToCookie(vm) LsPtrToCookie((vm).ToLsPtr())
431 #ifdef RIGHT_SIDE_COMPILE
432 //-----------------------------------------------------------------------------
433 // Infrasturcture for RS Definitions
434 //-----------------------------------------------------------------------------
436 // On the RS, we don't have the LS classes defined, so we can't templatize that
437 // in terms of <class T>, but we still want things to be unique.
438 // So we create an empty enum for each LS type and then templatize it in terms
440 template <typename T>
441 class MSLAYOUT LsPointer : public GeneralLsPointer
453 static LsPointer<T> NullPtr()
455 return MakePtr(NULL);
458 static LsPointer<T> MakePtr(T* p)
461 #pragma warning(push)
462 #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
474 bool operator!= (void * p) { return m_ptr != p; }
475 bool operator== (void * p) { return m_ptr == p; }
476 bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; }
478 // We should never UnWrap() them in the RS, so we don't define that here.
482 template <class T> UINT AllocCookie(CordbProcess * pProc, T * p);
483 template <class T> T * UnwrapCookie(CordbProcess * pProc, UINT cookie);
485 UINT AllocCookieCordbEval(CordbProcess * pProc, class CordbEval * p);
486 class CordbEval * UnwrapCookieCordbEval(CordbProcess * pProc, UINT cookie);
488 template <class CordbEval> UINT AllocCookie(CordbProcess * pProc, CordbEval * p)
490 return AllocCookieCordbEval(pProc, p);
492 template <class CordbEval> CordbEval * UnwrapCookie(CordbProcess * pProc, UINT cookie)
494 return UnwrapCookieCordbEval(pProc, cookie);
499 // This is how the RS sees the pointers in the IPC block.
501 class MSLAYOUT RsPointer : public GeneralRsPointer
504 // Since we're being used inside a union, we can't have a ctor.
506 static RsPointer<T> NullPtr()
513 bool AllocHandle(CordbProcess *pProc, T* p)
515 // This will force validation.
516 m_data = AllocCookie<T>(pProc, p);
517 return (m_data != 0);
520 bool operator==(RsPointer<T> p) { return p.m_data == this->m_data; }
522 T* UnWrapAndRemove(CordbProcess *pProc)
524 return UnwrapCookie<T>(pProc, m_data);
530 // Forward declare a class so that each type of LS pointer can have
531 // its own type. We use the real class name to be compatible with VMPTRs.
532 #define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \
534 typedef LsPointer<ls_type> ptr_name;
537 #define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \
539 typedef RsPointer<rs_type> ptr_name;
541 #else // !RIGHT_SIDE_COMPILE
542 //-----------------------------------------------------------------------------
543 // Infrastructure for LS Definitions
544 //-----------------------------------------------------------------------------
546 // This is how the LS sees the pointers in the IPC block.
548 class MSLAYOUT LsPointer : public GeneralLsPointer
551 // Since we're being used inside a union, we can't have a ctor.
554 static LsPointer<T> NullPtr()
556 return MakePtr(NULL);
559 static LsPointer<T> MakePtr(T * p)
562 #pragma warning(push)
563 #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
575 bool operator!= (void * p) { return m_ptr != p; }
576 bool operator== (void * p) { return m_ptr == p; }
577 bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; }
579 // @todo - we want to be able to swap out Set + Unwrap functions
583 // We could validate the pointer here.
589 // If we wanted to validate the pointer, here's our chance.
590 return static_cast<T*>(m_ptr);
595 class MSLAYOUT RsPointer : public GeneralRsPointer
598 static RsPointer<n> NullPtr()
605 bool operator==(RsPointer<n> p) { return p.m_data == this->m_data; }
607 // We should never UnWrap() them in the LS, so we don't define that here.
610 #define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \
612 typedef LsPointer<ls_type> ptr_name;
614 #define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \
615 enum __RS__##rs_type { }; \
616 typedef RsPointer<__RS__##rs_type> ptr_name;
618 #endif // !RIGHT_SIDE_COMPILE
620 // We must be binary compatible w/ a pointer.
621 static_assert_no_msg(sizeof(LsPointer<void>) == sizeof(GeneralLsPointer));
623 static_assert_no_msg(sizeof(void*) == sizeof(GeneralLsPointer));
627 //-----------------------------------------------------------------------------
628 // Definitions for Left-Side ptrs.
629 // NOTE: Use VMPTR instead of LSPTR. Don't add new LSPTR types.
631 //-----------------------------------------------------------------------------
635 DEFINE_LSPTR_TYPE(class Assembly, LSPTR_ASSEMBLY);
636 DEFINE_LSPTR_TYPE(class DebuggerJitInfo, LSPTR_DJI);
637 DEFINE_LSPTR_TYPE(class DebuggerMethodInfo, LSPTR_DMI);
638 DEFINE_LSPTR_TYPE(class MethodDesc, LSPTR_METHODDESC);
639 DEFINE_LSPTR_TYPE(class DebuggerBreakpoint, LSPTR_BREAKPOINT);
640 DEFINE_LSPTR_TYPE(class DebuggerEval, LSPTR_DEBUGGEREVAL);
641 DEFINE_LSPTR_TYPE(class DebuggerStepper, LSPTR_STEPPER);
643 // Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct.
644 #if defined(RIGHT_SIDE_COMPILE)
645 typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT;
646 #else // RIGHT_SIDE_COMPILE
647 typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT;
648 #endif // RIGHT_SIDE_COMPILE
650 DEFINE_LSPTR_TYPE(struct OBJECTHANDLE__, LSPTR_OBJECTHANDLE);
651 DEFINE_LSPTR_TYPE(class TypeHandleDummyPtr, LSPTR_TYPEHANDLE); // TypeHandle in the LS is not a direct pointer.
653 //-----------------------------------------------------------------------------
654 // Definitions for Right-Side ptrs.
655 //-----------------------------------------------------------------------------
656 DEFINE_RSPTR_TYPE(CordbEval, RSPTR_CORDBEVAL);
659 //---------------------------------------------------------------------------------------
660 // VMPTR_Base is the base type for an abstraction over pointers into the VM so
661 // that DBI can treat them as opaque handles. Classes will derive from it to
662 // provide type-safe Target pointers, which ICD will view as opaque handles.
665 // VMPTR_ objects survive across flushing the DAC cache. Therefore, the underlying
666 // storage must be a target-pointer (and not a marshalled host pointer).
667 // The RS must ensure they're still in sync with the LS (eg, by
668 // tracking unload events).
672 // These handles are TADDR pointers and must not require any cleanup from DAC/DBI.
673 // For direct untyped pointers into the VM, use CORDB_ADDRESS.
676 // 1. This helps enforce that DBI goes through the primitives interface
677 // for all access (and that it doesn't accidentally start calling
678 // dac-ized methods on the objects)
679 // 2. This isolates DBI from VM headers.
680 // 3. This isolates DBI from the dac implementation (of DAC_Ptr)
681 // 4. This is distinct from LSPTR because LSPTRs are truly opaque handles, whereas VMPtrs
682 // move across VM, DAC, and DBI, exposing proper functionality in each component.
683 // 5. VMPTRs are blittable because they are Target Addresses which act as opaque
684 // handles outside of the Target / Dac-marshaller.
686 //---------------------------------------------------------------------------------------
689 template <typename TTargetPtr, typename TDacPtr>
690 class MSLAYOUT VMPTR_Base
692 // Underlying pointer into Target address space.
693 // Target pointers are blittable.
694 // - In Target: can be used as normal local pointers.
695 // - In DAC: must be marshalled to a host-pointer and then they can be used via DAC
696 // - In RS: opaque handles.
701 typedef VMPTR_Base<TTargetPtr,TDacPtr> VMPTR_This;
703 // For DBI, VMPTRs are opaque handles.
704 // But the DAC side is allowed to inspect the handles to get at the raw pointer.
705 #if defined(ALLOW_VMPTR_ACCESS)
707 // Case 1: Using in DAcDbi implementation
711 TDacPtr GetDacPtr() const
714 return TDacPtr(m_addr);
718 // This will initialize the handle to a given target-pointer.
719 // We choose TADDR to make it explicit that it's a target pointer and avoid the risk
720 // of it accidentally getting marshalled to a host pointer.
721 void SetDacTargetPtr(TADDR addr)
727 void SetHostPtr(const TTargetPtr * pObject)
730 m_addr = PTR_HOST_TO_TADDR(pObject);
734 #elif !defined(RIGHT_SIDE_COMPILE)
736 // Case 2: Used in Left-side. Can get/set from local pointers.
739 // This will set initialize from a Target pointer. Since this is happening in the
740 // Left-side (Target), the pointer is local.
741 // This is commonly used by the Left-side to create a VMPTR_ for a notification event.
742 void SetRawPtr(TTargetPtr * ptr)
744 m_addr = reinterpret_cast<TADDR>(ptr);
747 // This will get the raw underlying target pointer.
748 // This can be used by inproc Left-side code to unwrap a VMPTR (Eg, for a func-eval
749 // hijack or in-proc worker threads)
750 TTargetPtr * GetRawPtr()
752 return reinterpret_cast<TTargetPtr*>(m_addr);
755 // Convenience for converting TTargetPtr --> VMPTR
756 static VMPTR_This MakePtr(TTargetPtr * ptr)
759 #pragma warning(push)
760 #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
775 // Case 3: Used in RS. Opaque handles only.
780 #ifndef DACCESS_COMPILE
781 // For compatibility, these can be converted to LSPTRs on the RS or LS (case 2 and 3). We don't allow
782 // this in the DAC case because it's a cast between address spaces which we're trying to eliminate
784 // @dbgtodo inspection: LSPTRs will go away entirely once we've moved completely over to DAC
785 LsPointer<TTargetPtr> ToLsPtr()
787 return LsPointer<TTargetPtr>::MakePtr( reinterpret_cast<TTargetPtr *>(m_addr));
792 // Operators to emulate Pointer semantics.
794 bool IsNull() { SUPPORTS_DAC; return m_addr == NULL; }
796 static VMPTR_This NullPtr()
801 #pragma warning(push)
802 #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
814 bool operator!= (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr != vmOther.m_addr; }
815 bool operator== (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr == vmOther.m_addr; }
818 #if defined(ALLOW_VMPTR_ACCESS)
819 // Helper macro to define a VMPTR.
820 // This is used in the DAC case, so this definition connects the pointers up to their DAC values.
821 #define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \
823 typedef VMPTR_Base<ls_type, dac_ptr_type> ptr_name;
826 // Helper macro to define a VMPTR.
827 // This is used in the Right-side and Left-side (but not DAC) case.
828 // This definition explicitly ignores dac_ptr_type to prevent accidental DAC usage.
829 #define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \
831 typedef VMPTR_Base<ls_type, void> ptr_name;
836 // The naming convention for instantiating a VMPTR is a 'vm' prefix.
838 // VM definition, DAC definition, pretty name for VMPTR
839 DEFINE_VMPTR(class AppDomain, PTR_AppDomain, VMPTR_AppDomain);
841 // Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct.
842 // DEFINE_VMPTR(struct _CONTEXT, PTR_CONTEXT, VMPTR_CONTEXT);
843 #if defined(ALLOW_VMPTR_ACCESS)
844 typedef VMPTR_Base<DT_CONTEXT, PTR_CONTEXT> VMPTR_CONTEXT;
846 typedef VMPTR_Base<DT_CONTEXT, void > VMPTR_CONTEXT;
849 // DomainFile is a base-class for a CLR module, with app-domain affinity.
850 // For domain-neutral modules (like mscorlib), there is a DomainFile instance
851 // for each appdomain the module lives in.
852 // This is the canonical handle ICorDebug uses to a CLR module.
853 DEFINE_VMPTR(class DomainFile, PTR_DomainFile, VMPTR_DomainFile);
854 DEFINE_VMPTR(class Module, PTR_Module, VMPTR_Module);
856 // DomainAssembly derives from DomainFile and represents a manifest module.
857 DEFINE_VMPTR(class DomainAssembly, PTR_DomainAssembly, VMPTR_DomainAssembly);
858 DEFINE_VMPTR(class Assembly, PTR_Assembly, VMPTR_Assembly);
860 DEFINE_VMPTR(class PEFile, PTR_PEFile, VMPTR_PEFile);
861 DEFINE_VMPTR(class MethodDesc, PTR_MethodDesc, VMPTR_MethodDesc);
862 DEFINE_VMPTR(class FieldDesc, PTR_FieldDesc, VMPTR_FieldDesc);
864 // ObjectHandle is a safe way to represent an object into the GC heap. It gets updated
866 DEFINE_VMPTR(struct OBJECTHANDLE__, TADDR, VMPTR_OBJECTHANDLE);
868 DEFINE_VMPTR(class TypeHandle, PTR_TypeHandle, VMPTR_TypeHandle);
870 // A VMPTR_Thread represents a thread that has entered the runtime at some point.
871 // It may or may not have executed managed code yet; and it may or may not have managed code
873 DEFINE_VMPTR(class Thread, PTR_Thread, VMPTR_Thread);
875 DEFINE_VMPTR(class Object, PTR_Object, VMPTR_Object);
877 DEFINE_VMPTR(class CrstBase, PTR_Crst, VMPTR_Crst);
878 DEFINE_VMPTR(class SimpleRWLock, PTR_SimpleRWLock, VMPTR_SimpleRWLock);
879 DEFINE_VMPTR(class SimpleRWLock, PTR_SimpleRWLock, VMPTR_RWLock);
880 DEFINE_VMPTR(struct ReJitInfo, PTR_ReJitInfo, VMPTR_ReJitInfo);
881 DEFINE_VMPTR(struct SharedReJitInfo, PTR_SharedReJitInfo, VMPTR_SharedReJitInfo);
882 DEFINE_VMPTR(class NativeCodeVersionNode, PTR_NativeCodeVersionNode, VMPTR_NativeCodeVersionNode);
883 DEFINE_VMPTR(class ILCodeVersionNode, PTR_ILCodeVersionNode, VMPTR_ILCodeVersionNode);
885 typedef CORDB_ADDRESS GENERICS_TYPE_TOKEN;
888 //-----------------------------------------------------------------------------
889 // We pass some fixed size strings in the IPC block.
890 // Helper class to wrap the buffer and protect against buffer overflows.
891 // This should be binary compatible w/ a wchar[] array.
892 //-----------------------------------------------------------------------------
894 template <int nMaxLengthIncludingNull>
895 class MSLAYOUT EmbeddedIPCString
898 // Set, caller responsibility that wcslen(pData) < nMaxLengthIncludingNull
899 void SetString(const WCHAR * pData)
901 // If the string doesn't fit into the buffer, that's an issue (and so this is a real
902 // assert, not just a simplifying assumption). To fix it, either:
903 // - make the buffer larger
904 // - don't pass the string as an embedded string in the IPC block.
905 // This will truncate (rather than AV on the RS).
907 ret = SafeCopy(pData);
909 // See comment above - caller should guarantee that buffer is large enough.
910 _ASSERTE(ret != STRUNCATE);
913 // Set a string from a substring. This will truncate if necessary.
914 void SetStringTruncate(const WCHAR * pData)
916 // ignore return value because truncation is ok.
920 const WCHAR * GetString()
922 // For a null-termination just in case an issue in the debuggee process
923 // yields a malformed string.
924 m_data[nMaxLengthIncludingNull - 1] = W('\0');
927 int GetMaxSize() const { return nMaxLengthIncludingNull; }
930 int SafeCopy(const WCHAR * pData)
933 m_data, nMaxLengthIncludingNull,
936 WCHAR m_data[nMaxLengthIncludingNull];
940 // Types of events that can be sent between the Runtime Controller and
941 // the Debugger Interface. Some of these events are one way only, while
942 // others go both ways. The grouping of the event numbers is an attempt
943 // to show this distinction and perhaps even allow generic operations
944 // based on the type of the event.
946 enum DebuggerIPCEventType
948 #define IPC_EVENT_TYPE0(type, val) type = val,
949 #define IPC_EVENT_TYPE1(type, val) type = val,
950 #define IPC_EVENT_TYPE2(type, val) type = val,
951 #include "dbgipceventtypes.h"
952 #undef IPC_EVENT_TYPE2
953 #undef IPC_EVENT_TYPE1
954 #undef IPC_EVENT_TYPE0
959 // This is a static debugging structure to help breaking at the right place.
960 // Debug only. This is to track the number of events that have been happened so far.
961 // User can choose to set break point base on the number of events.
962 // Variables are named as the event name with prefix m_iDebugCount. For example
963 // m_iDebugCount_DB_IPCE_BREAKPOINT if for event DB_IPCE_BREAKPOINT.
964 struct MSLAYOUT DebugEventCounter
966 // we don't need the event type 0
967 #define IPC_EVENT_TYPE0(type, val)
968 #define IPC_EVENT_TYPE1(type, val) int m_iDebugCount_##type;
969 #define IPC_EVENT_TYPE2(type, val) int m_iDebugCount_##type;
970 #include "dbgipceventtypes.h"
971 #undef IPC_EVENT_TYPE2
972 #undef IPC_EVENT_TYPE1
973 #undef IPC_EVENT_TYPE0
978 #if !defined(DACCESS_COMPILE)
980 struct MSLAYOUT IPCEventTypeNameMapping
982 DebuggerIPCEventType eventType;
983 const char * eventName;
986 extern const IPCEventTypeNameMapping DECLSPEC_SELECTANY DbgIPCEventTypeNames[] =
988 #define IPC_EVENT_TYPE0(type, val) { type, #type },
989 #define IPC_EVENT_TYPE1(type, val) { type, #type },
990 #define IPC_EVENT_TYPE2(type, val) { type, #type },
991 #include "dbgipceventtypes.h"
992 #undef IPC_EVENT_TYPE2
993 #undef IPC_EVENT_TYPE1
994 #undef IPC_EVENT_TYPE0
995 { DB_IPCE_INVALID_EVENT, "DB_IPCE_Error" }
998 const size_t nameCount = sizeof(DbgIPCEventTypeNames) / sizeof(DbgIPCEventTypeNames[0]);
1001 struct MSLAYOUT IPCENames // We use a class/struct so that the function can remain in a shared header file
1003 static const DebuggerIPCEventType GetEventType(__in_z char * strEventType)
1005 // pass in the string of event name and find the matching enum value
1006 // This is a linear search which is pretty slow. However, this is only used
1007 // at startup time when debug assert is turn on and with registry key set. So it is not that bad.
1009 for (size_t i = 0; i < nameCount; i++)
1011 if (_stricmp(DbgIPCEventTypeNames[i].eventName, strEventType) == 0)
1012 return DbgIPCEventTypeNames[i].eventType;
1014 return DB_IPCE_INVALID_EVENT;
1016 static const char * GetName(DebuggerIPCEventType eventType)
1019 enum DbgIPCEventTypeNum
1021 #define IPC_EVENT_TYPE0(type, val) type##_Num,
1022 #define IPC_EVENT_TYPE1(type, val) type##_Num,
1023 #define IPC_EVENT_TYPE2(type, val) type##_Num,
1024 #include "dbgipceventtypes.h"
1025 #undef IPC_EVENT_TYPE2
1026 #undef IPC_EVENT_TYPE1
1027 #undef IPC_EVENT_TYPE0
1030 unsigned int i, lim;
1032 if (eventType < DB_IPCE_DEBUGGER_FIRST)
1034 i = DB_IPCE_RUNTIME_FIRST_Num + 1;
1035 lim = DB_IPCE_DEBUGGER_FIRST_Num;
1039 i = DB_IPCE_DEBUGGER_FIRST_Num + 1;
1043 for (/**/; i < lim; i++)
1045 if (DbgIPCEventTypeNames[i].eventType == eventType)
1046 return DbgIPCEventTypeNames[i].eventName;
1049 return DbgIPCEventTypeNames[nameCount - 1].eventName;
1053 #endif // !DACCESS_COMPILE
1056 // NOTE: CPU-specific values below!
1058 // DebuggerREGDISPLAY is very similar to the EE REGDISPLAY structure. It holds
1059 // register values that can be saved over calls for each frame in a stack
1062 // DebuggerIPCE_FloatCount is the number of doubles in the processor's
1063 // floating point stack.
1065 // <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
1066 // address of each register, too, to support using enregistered variables on non-leaf frames as args to a func eval. Its
1067 // very, very possible that we would rework the entire code base to just use the register's address instead of passing
1068 // both, but its way, way too late in V1 to undertake that, so I'm just using these addresses to suppport our one func
1069 // eval case. Clearly, this needs to be cleaned up post V1.
1071 // -- Fri Feb 09 11:21:24 2001</TODO>
1074 struct MSLAYOUT DebuggerREGDISPLAY
1076 #if defined(DBG_TARGET_X86)
1077 #define DebuggerIPCE_FloatCount 8
1096 #elif defined(DBG_TARGET_AMD64)
1097 #define DebuggerIPCE_FloatCount 16
1133 #elif defined(DBG_TARGET_ARM)
1134 #define DebuggerIPCE_FloatCount 32
1168 #elif defined(DBG_TARGET_ARM64)
1169 #define DebuggerIPCE_FloatCount 32
1177 #define DebuggerIPCE_FloatCount 1
1186 inline LPVOID GetSPAddress(const DebuggerREGDISPLAY * display)
1188 return (LPVOID)&display->SP;
1191 #if !defined(DBG_TARGET_AMD64) && !defined(DBG_TARGET_ARM)
1192 inline LPVOID GetFPAddress(const DebuggerREGDISPLAY * display)
1194 return (LPVOID)&display->FP;
1196 #endif // !DBG_TARGET_AMD64
1199 class MSLAYOUT FramePointer
1201 friend bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2);
1202 friend bool IsCloserToRoot(FramePointer fp1, FramePointer fp2);
1203 friend bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2);
1204 friend bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2);
1208 static FramePointer MakeFramePointer(LPVOID sp)
1210 LIMITED_METHOD_DAC_CONTRACT;
1216 static FramePointer MakeFramePointer(UINT_PTR sp)
1219 return MakeFramePointer((LPVOID)sp);
1222 inline bool operator==(FramePointer fp)
1224 return (m_sp == fp.m_sp);
1227 inline bool operator!=(FramePointer fp)
1229 return !(*this == fp);
1232 // This is needed because on the RS, the m_id values of CordbFrame and
1233 // CordbChain are really FramePointers.
1234 LPVOID GetSPValue() const
1241 // Declare some private constructors which signatures matching common usage of FramePointer
1242 // to prevent people from accidentally assigning a pointer to a FramePointer().
1243 FramePointer &operator=(LPVOID sp);
1244 FramePointer &operator=(BYTE* sp);
1245 FramePointer &operator=(const BYTE* sp);
1250 // For non-IA64 platforms, we use stack pointers as frame pointers.
1251 // (Stack grows towards smaller address.)
1252 #define LEAF_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)NULL)
1253 #define ROOT_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)-1)
1255 static_assert_no_msg(sizeof(FramePointer) == sizeof(void*));
1258 inline bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2)
1260 return (fp1.m_sp < fp2.m_sp);
1263 inline bool IsCloserToRoot(FramePointer fp1, FramePointer fp2)
1265 return (fp1.m_sp > fp2.m_sp);
1268 inline bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2)
1270 return !IsCloserToRoot(fp1, fp2);
1273 inline bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2)
1275 return !IsCloserToLeaf(fp1, fp2);
1279 // struct DebuggerIPCE_FuncData: DebuggerIPCE_FuncData holds data
1280 // to describe a given function, its
1281 // class, and a little bit about the code for the function. This is used
1282 // in the stack trace result data to pass function information back that
1283 // may be needed. Its also used when getting data about a specific function.
1285 // void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is
1286 // the address of the real start address of the native code.
1287 // This field will be NULL only if the method hasn't been JITted
1288 // yet (and thus no code is available). Otherwise, it will be
1289 // the adress of a CORDB_ADDRESS in the remote memory. This
1290 // CORDB_ADDRESS may be NULL, in which case the code is unavailable
1291 // has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE)
1293 // SIZE_T nVersion: The version of the code that this instance of the
1294 // function is using.
1295 struct MSLAYOUT DebuggerIPCE_FuncData
1297 mdMethodDef funcMetadataToken;
1298 VMPTR_DomainFile vmDomainFile;
1300 mdTypeDef classMetadataToken;
1302 void* ilStartAddress;
1305 SIZE_T currentEnCVersion;
1307 mdSignature localVarSigToken;
1312 // struct DebuggerIPCE_JITFuncData: DebuggerIPCE_JITFuncData holds
1313 // a little bit about the JITted code for the function.
1315 // void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is
1316 // the address of the real start address of the native code.
1317 // This field will be NULL only if the method hasn't been JITted
1318 // yet (and thus no code is available). Otherwise, it will be
1319 // the address of a CORDB_ADDRESS in the remote memory. This
1320 // CORDB_ADDRESS may be NULL, in which case the code is unavailable
1321 // or has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE)
1323 // SIZE_T nativeSize: Size of the native code.
1325 // SIZE_T nativeOffset: Offset from the beginning of the function,
1326 // in bytes. This may be non-zero even when nativeStartAddressPtr
1328 // void * nativeCodeJITInfoToken: An opaque value to hand back to the left
1329 // side when fetching the JITInfo for the native code, i.e. the
1330 // IL->native maps for the variables. This may be NULL if no JITInfo is available.
1331 // void * nativeCodeMethodDescToken: An opaque value to hand back to the left
1332 // side when fetching the code. In addition this token can act as the
1333 // unique identity for the native code in the case where there are
1334 // multiple blobs of native code per IL method (i.e. if the method is
1335 // generic code of some kind)
1336 // BOOL isInstantiatedGeneric: Indicates if the method is
1337 // generic code of some kind.
1338 // BOOL jsutAfterILThrow: indicates that code just threw a software exception and
1339 // nativeOffset points to an instruction just after [call IL_Throw].
1340 // This is being used to figure out a real offset of the exception origin.
1341 // By subtracting STACKWALK_CONTROLPC_ADJUST_OFFSET from nativeOffset you can get
1342 // an address somewhere inside [call IL_Throw] instruction.
1343 // void *ilToNativeMapAddr etc.: If nativeCodeJITInfoToken is not NULL then these
1344 // specify the table giving the mapping of IPs.
1345 struct MSLAYOUT DebuggerIPCE_JITFuncData
1347 TADDR nativeStartAddressPtr;
1348 SIZE_T nativeHotSize;
1350 // If we have a cold region, need its size & the pointer to where starts.
1351 TADDR nativeStartAddressColdPtr;
1352 SIZE_T nativeColdSize;
1355 SIZE_T nativeOffset;
1356 LSPTR_DJI nativeCodeJITInfoToken;
1357 VMPTR_MethodDesc vmNativeCodeMethodDescToken;
1359 #ifdef WIN64EXCEPTIONS
1360 BOOL fIsFilterFrame;
1361 SIZE_T parentNativeOffset;
1362 FramePointer fpParentOrSelf;
1363 #endif // WIN64EXCEPTIONS
1365 // indicates if the MethodDesc is a generic function or a method inside a generic class (or
1367 BOOL isInstantiatedGeneric;
1369 // this is the version of the jitted code
1372 BOOL jsutAfterILThrow;
1376 // DebuggerIPCE_STRData holds data for each stack frame or chain. This data is passed
1377 // from the RC to the DI during a stack walk.
1379 #if defined(_MSC_VER)
1380 #pragma warning( push )
1381 #pragma warning( disable:4324 ) // the compiler pads a structure to comply with alignment requirements
1382 #endif // ARM context structures have a 16-byte alignment requirement
1383 struct MSLAYOUT DebuggerIPCE_STRData
1386 // @dbgtodo stackwalker/shim- Ideally we should be able to get rid of the DebuggerREGDISPLAY and just use the CONTEXT.
1388 DebuggerREGDISPLAY rd;
1389 bool quicklyUnwound;
1391 VMPTR_AppDomain vmCurrentAppDomainToken;
1407 CorDebugChainReason chainReason;
1411 // Data for a Method
1414 struct DebuggerIPCE_FuncData funcData;
1415 struct DebuggerIPCE_JITFuncData jitFuncData;
1417 CorDebugMappingResult mapping;
1421 // Indicates whether the managed method has any metadata.
1422 // Some dynamic methods such as IL stubs and LCG methods don't have any metadata.
1423 // This is used only by the V3 stackwalker, not the V2 one, because we only
1424 // expose dynamic methods as real stack frames in V3.
1429 GENERICS_TYPE_TOKEN exactGenericArgsToken;
1430 DWORD dwExactGenericArgsTokenIndex;
1434 // Data for an Stub Frame.
1437 mdMethodDef funcMetadataToken;
1438 VMPTR_DomainFile vmDomainFile;
1439 VMPTR_MethodDesc vmMethodDesc;
1440 CorDebugInternalFrameType frameType;
1445 #if defined(_MSC_VER)
1446 #pragma warning( pop )
1450 // DebuggerIPCE_BasicTypeData and DebuggerIPCE_ExpandedTypeData
1451 // hold data for each type sent across the
1452 // boundary, whether it be a constructed type List<String> or a non-constructed
1453 // type such as String, Foo or Object.
1455 // Logically speaking DebuggerIPCE_BasicTypeData might just be "typeHandle", as
1456 // we could then send further events to ask what the elementtype, typeToken and moduleToken
1457 // are for the type handle. But as
1458 // nearly all types are non-generic we send across even the basic type information in
1459 // the slightly expanded form shown below, sending the element type and the
1460 // tokens with the type handle itself. The fields debuggerModuleToken, metadataToken and typeHandle
1461 // are only used as follows:
1462 // elementType debuggerModuleToken metadataToken typeHandle
1463 // E_T_INT8 : E_T_INT8 No No No
1464 // Boxed E_T_INT8: E_T_CLASS No No No
1465 // E_T_CLASS, non-generic class: E_T_CLASS Yes Yes No
1466 // E_T_VALUETYPE, non-generic: E_T_VALUETYPE Yes Yes No
1467 // E_T_CLASS, generic class: E_T_CLASS Yes Yes Yes
1468 // E_T_VALUETYPE, generic class: E_T_VALUETYPE Yes Yes Yes
1469 // E_T_BYREF : E_T_BYREF No No Yes
1470 // E_T_PTR : E_T_PTR No No Yes
1471 // E_T_ARRAY etc. : E_T_ARRAY No No Yes
1472 // E_T_FNPTR etc. : E_T_FNPTR No No Yes
1473 // This allows us to always set "typeHandle" to NULL except when dealing with highly nested
1474 // types or function-pointer types (the latter are too complexe to transfer over in one hit).
1477 struct MSLAYOUT DebuggerIPCE_BasicTypeData
1479 CorElementType elementType;
1480 mdTypeDef metadataToken;
1481 VMPTR_Module vmModule;
1482 VMPTR_DomainFile vmDomainFile;
1483 VMPTR_TypeHandle vmTypeHandle;
1486 // DebuggerIPCE_ExpandedTypeData contains more information showing further
1487 // details for array types, byref types etc.
1488 // Whenever you fetch type information from the left-side
1489 // you get back one of these. These in turn contain further
1490 // DebuggerIPCE_BasicTypeData's and typeHandles which you can
1491 // then query to get further information about the type parameters.
1492 // This copes with the nested cases, e.g. jagged arrays,
1493 // String ****, &(String*), Pair<String,Pair<String>>
1496 // So this type information is not "fully expanded", it's just a little
1497 // more detail then DebuggerIPCE_BasicTypeData. For type
1498 // instantiatons (e.g. List<int>) and
1499 // function pointer types you will need to make further requests for
1500 // information about the type parameters.
1501 // For array types there is always only one type parameter so
1502 // we include that as part of the expanded data.
1505 struct MSLAYOUT DebuggerIPCE_ExpandedTypeData
1507 CorElementType elementType; // Note this is _never_ E_T_VAR, E_T_WITH or E_T_MVAR
1510 // used for E_T_CLASS and E_T_VALUECLASS, E_T_PTR, E_T_BYREF etc.
1511 // For non-constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be NULL
1512 // For constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be non-NULL
1513 // For E_T_PTR etc. the tokens will be NULL and the typeHandle will be non-NULL.
1516 mdTypeDef metadataToken;
1517 VMPTR_Module vmModule;
1518 VMPTR_DomainFile vmDomainFile;
1519 VMPTR_TypeHandle typeHandle; // if non-null then further fetches will be needed to get type arguments
1522 // used for E_T_PTR, E_T_BYREF etc.
1525 DebuggerIPCE_BasicTypeData unaryTypeArg; // used only when sending back to debugger
1529 // used for E_T_ARRAY etc.
1532 DebuggerIPCE_BasicTypeData arrayTypeArg; // used only when sending back to debugger
1536 // used for E_T_FNPTR
1539 VMPTR_TypeHandle typeHandle; // if non-null then further fetches needed to get type arguments
1545 // DebuggerIPCE_TypeArgData is used when sending type arguments
1546 // across to a funceval. It contains the DebuggerIPCE_ExpandedTypeData describing the
1547 // essence of the type, but the typeHandle and other
1548 // BasicTypeData fields should be zero and will be ignored.
1549 // The DebuggerIPCE_ExpandedTypeData is then followed
1550 // by the required number of type arguments, each of which
1551 // will be a further DebuggerIPCE_TypeArgData record in the stream of
1552 // flattened type argument data.
1553 struct MSLAYOUT DebuggerIPCE_TypeArgData
1555 DebuggerIPCE_ExpandedTypeData data;
1556 unsigned int numTypeArgs; // number of immediate children on the type tree
1561 // DebuggerIPCE_ObjectData holds the results of a
1562 // GetAndSendObjectInfo, i.e., all the info about an object that the
1563 // Right Side would need to access it. (This include array, string,
1564 // and nstruct info.)
1566 struct MSLAYOUT DebuggerIPCE_ObjectData
1572 // Offset from the beginning of the object to the beginning of the first field
1573 SIZE_T objOffsetToVars;
1575 // The type of the object....
1576 struct DebuggerIPCE_ExpandedTypeData objTypeData;
1583 SIZE_T offsetToStringBase;
1589 SIZE_T offsetToArrayBase;
1590 SIZE_T offsetToLowerBounds; // 0 if not present
1591 SIZE_T offsetToUpperBounds; // 0 if not present
1592 SIZE_T componentCount;
1598 struct DebuggerIPCE_BasicTypeData typedByrefType; // the type of the thing contained in a typedByref...
1604 // Remote enregistered info used by CordbValues and for passing
1605 // variable homes between the left and right sides during a func eval.
1608 enum RemoteAddressKind
1619 const CORDB_ADDRESS kLeafFrameRegAddr = 0;
1620 const CORDB_ADDRESS kNonLeafFrameRegAddr = (CORDB_ADDRESS)(-1);
1622 struct MSLAYOUT RemoteAddress
1624 RemoteAddressKind kind;
1627 CorDebugRegister reg1;
1629 SIZE_T reg1Value; // this is the actual value of the register
1635 CorDebugRegister reg2;
1637 SIZE_T reg2Value; // this is the actual value of the register
1646 // DebuggerIPCE_FuncEvalType specifies the type of a function
1647 // evaluation that will occur.
1649 enum DebuggerIPCE_FuncEvalType
1652 DB_IPCE_FET_NEW_OBJECT,
1653 DB_IPCE_FET_NEW_OBJECT_NC,
1654 DB_IPCE_FET_NEW_STRING,
1655 DB_IPCE_FET_NEW_ARRAY,
1656 DB_IPCE_FET_RE_ABORT
1662 APP_DOMAIN_NAME_CHANGE,
1667 // DebuggerIPCE_FuncEvalArgData holds data for each argument to a
1668 // function evaluation.
1670 struct MSLAYOUT DebuggerIPCE_FuncEvalArgData
1672 RemoteAddress argHome; // enregistered variable home
1673 void *argAddr; // address if not enregistered
1674 CorElementType argElementType;
1675 unsigned int fullArgTypeNodeCount; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types)
1676 void *fullArgType; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types)
1677 BYTE argLiteralData[8]; // copy of generic value data
1678 bool argIsLiteral; // true if value is in argLiteralData
1679 bool argIsHandleValue; // true if argAddr is OBJECTHANDLE
1684 // DebuggerIPCE_FuncEvalInfo holds info necessary to setup a func eval
1687 struct MSLAYOUT DebuggerIPCE_FuncEvalInfo
1689 VMPTR_Thread vmThreadToken;
1690 DebuggerIPCE_FuncEvalType funcEvalType;
1691 mdMethodDef funcMetadataToken;
1692 mdTypeDef funcClassMetadataToken;
1693 VMPTR_DomainFile vmDomainFile;
1694 RSPTR_CORDBEVAL funcEvalKey;
1695 bool evalDuringException;
1697 unsigned int argCount;
1698 unsigned int genericArgsCount;
1699 unsigned int genericArgsNodeCount;
1708 // Used in DebuggerIPCFirstChanceData. This tells the LS what action to take within the hijack
1712 HIJACK_ACTION_EXIT_UNHANDLED,
1713 HIJACK_ACTION_EXIT_HANDLED,
1718 // DebuggerIPCFirstChanceData holds info communicated from the LS to the RS when signaling that an exception does not
1719 // belong to the runtime from a first chance hijack. This is used when Win32 debugging only.
1721 struct MSLAYOUT DebuggerIPCFirstChanceData
1723 LSPTR_CONTEXT pLeftSideContext;
1724 HijackAction action;
1729 // DebuggerIPCSecondChanceData holds info communicated from the RS
1730 // to the LS when setting up a second chance exception hijack. This is
1731 // used when Win32 debugging only.
1733 struct MSLAYOUT DebuggerIPCSecondChanceData
1735 DT_CONTEXT threadContext;
1740 //-----------------------------------------------------------------------------
1741 // This struct holds pointer from the LS and needs to copy to
1742 // the RS. We have to free the memory on the RS.
1743 // The transfer function is called when the RS first reads the event. At this point,
1744 // the LS is stopped while sending the event. Thus the LS pointers only need to be
1745 // valid while the LS is in SendIPCEvent.
1747 // Since this data is in an IPC/Marshallable block, it can't have any Ctors (holders)
1749 //-----------------------------------------------------------------------------
1750 struct MSLAYOUT Ls_Rs_BaseBuffer
1752 #ifdef RIGHT_SIDE_COMPILE
1754 // copy data can happen on both LS and RS. In LS case,
1755 // ReadProcessMemory is really reading from its own process memory.
1757 void CopyLSDataToRSWorker(ICorDebugDataTarget * pTargethProcess);
1759 // retrieve the RS data and own it
1760 BYTE *TransferRSDataWorker()
1762 BYTE *pbRS = m_pbRS;
1779 // Only LS can call this API
1780 void SetLsData(BYTE *pbLS, DWORD cbSize)
1786 #endif // RIGHT_SIDE_COMPILE
1790 DWORD GetSize() { return m_cbSize; }
1795 // Size of data in bytes
1798 // If this is non-null, pointer into LS for buffer.
1799 // LS can free this after the debug event is continued.
1800 BYTE *m_pbLS; // @dbgtodo cross-plat- for cross-platform purposes, this should be a TADDR
1802 // If this is non-null, pointer into RS for buffer. RS must then free this.
1803 // This buffer was copied from the LS (via CopyLSDataToRSWorker).
1807 //-----------------------------------------------------------------------------
1808 // Byte wrapper around the buffer.
1809 //-----------------------------------------------------------------------------
1810 struct MSLAYOUT Ls_Rs_ByteBuffer : public Ls_Rs_BaseBuffer
1812 #ifdef RIGHT_SIDE_COMPILE
1813 BYTE *GetRSPointer()
1818 void CopyLSDataToRS(ICorDebugDataTarget * pTarget);
1819 BYTE *TransferRSData()
1821 return TransferRSDataWorker();
1826 //-----------------------------------------------------------------------------
1827 // Wrapper around a Ls_rS_Buffer to get it as a string.
1828 // This can also do some sanity checking.
1829 //-----------------------------------------------------------------------------
1830 struct MSLAYOUT Ls_Rs_StringBuffer : public Ls_Rs_BaseBuffer
1832 #ifdef RIGHT_SIDE_COMPILE
1833 const WCHAR * GetString()
1835 return reinterpret_cast<const WCHAR*> (m_pbRS);
1838 // Copy over the string.
1839 void CopyLSDataToRS(ICorDebugDataTarget * pTarget);
1841 // Caller will pick up ownership.
1842 // Since caller will delete this data, we can't give back a constant pointer.
1843 WCHAR * TransferStringData()
1845 return reinterpret_cast<WCHAR*> (TransferRSDataWorker());
1851 // Data for an Managed Debug Assistant Probe (MDA).
1852 struct MSLAYOUT DebuggerMDANotification
1854 Ls_Rs_StringBuffer szName;
1855 Ls_Rs_StringBuffer szDescription;
1856 Ls_Rs_StringBuffer szXml;
1858 CorDebugMDAFlags flags;
1862 // The only remaining problem is that register number mappings are different for each platform. It turns out
1863 // that the debugger only uses REGNUM_SP and REGNUM_AMBIENT_SP though, so we can just virtualize these two for
1864 // the target platform.
1865 // Keep this is sync with the definitions in inc/corinfo.h.
1866 #if defined(DBG_TARGET_X86)
1867 #define DBG_TARGET_REGNUM_SP 4
1868 #define DBG_TARGET_REGNUM_AMBIENT_SP 9
1870 static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
1871 static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
1872 #endif // _TARGET_X86_
1873 #elif defined(DBG_TARGET_AMD64)
1874 #define DBG_TARGET_REGNUM_SP 4
1875 #define DBG_TARGET_REGNUM_AMBIENT_SP 17
1876 #ifdef _TARGET_AMD64_
1877 static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
1878 static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
1879 #endif // _TARGET_AMD64_
1880 #elif defined(DBG_TARGET_ARM)
1881 #define DBG_TARGET_REGNUM_SP 13
1882 #define DBG_TARGET_REGNUM_AMBIENT_SP 17
1884 C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
1885 C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
1886 #endif // _TARGET_ARM_
1887 #elif defined(DBG_TARGET_ARM64)
1888 #define DBG_TARGET_REGNUM_SP 31
1889 #define DBG_TARGET_REGNUM_AMBIENT_SP 34
1890 #ifdef _TARGET_ARM64_
1891 C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
1892 C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
1893 #endif // _TARGET_ARM64_
1895 #error Target registers are not defined for this platform
1900 // Event structure that is passed between the Runtime Controller and the
1901 // Debugger Interface. Some types of events are a fixed size and have
1902 // entries in the main union, while others are variable length and have
1903 // more specialized data structures that are attached to the end of this
1906 struct MSLAYOUT DebuggerIPCEvent
1908 DebuggerIPCEvent* next;
1909 DebuggerIPCEventType type;
1911 VMPTR_AppDomain vmAppDomain;
1912 VMPTR_Thread vmThread;
1922 // Pointer to a BOOL in the target.
1923 CORDB_ADDRESS pfBeingDebugged;
1924 } LeftSideStartupData;
1928 // Module whos metadata is being updated
1929 // This tells the RS that the metadata for that module has become invalid.
1930 VMPTR_DomainFile vmDomainFile;
1932 } MetadataUpdateData;
1936 // Handle to CLR's internal appdomain object.
1937 VMPTR_AppDomain vmAppDomain;
1942 VMPTR_DomainAssembly vmDomainAssembly;
1945 #ifdef TEST_DATA_CONSISTENCY
1946 // information necessary for testing whether the LS holds a lock on data
1947 // the RS needs to inspect. See code:DataTest::TestDataSafety and
1948 // code:IDacDbiInterface::TestCrst for more information
1951 // the lock to be tested
1953 // indicates whether the LS holds the lock
1957 // information necessary for testing whether the LS holds a lock on data
1958 // the RS needs to inspect. See code:DataTest::TestDataSafety and
1959 // code:IDacDbiInterface::TestCrst for more information
1962 // the lock to be tested
1963 VMPTR_SimpleRWLock vmRWLock;
1964 // indicates whether the LS holds the lock
1967 #endif // TEST_DATA_CONSISTENCY
1969 // Debug event that a module has been loaded
1972 // Module that was just loaded.
1973 VMPTR_DomainFile vmDomainFile;
1979 VMPTR_DomainFile vmDomainFile;
1980 LSPTR_ASSEMBLY debuggerAssemblyToken;
1984 // The given module's pdb has been updated.
1985 // Queury PDB from OOP
1988 VMPTR_DomainFile vmDomainFile;
1989 } UpdateModuleSymsData;
1991 DebuggerMDANotification MDANotification;
1995 LSPTR_BREAKPOINT breakpointToken;
1996 mdMethodDef funcMetadataToken;
1997 VMPTR_DomainFile vmDomainFile;
2001 LSPTR_METHODDESC nativeCodeMethodDescToken; // points to the MethodDesc if !isIL
2006 LSPTR_BREAKPOINT breakpointToken;
2007 } BreakpointSetErrorData;
2011 LSPTR_STEPPER stepperToken;
2012 VMPTR_Thread vmThreadToken;
2013 FramePointer frameToken;
2017 unsigned int totalRangeCount;
2018 CorDebugStepReason reason;
2019 CorDebugUnmappedStop rgfMappingStop;
2020 CorDebugIntercept rgfInterceptStop;
2021 unsigned int rangeCount;
2022 COR_DEBUG_STEP_RANGE range; //note that this is an array
2027 // An unvalidated GC-handle
2028 VMPTR_OBJECTHANDLE GCHandle;
2033 // An unvalidated GC-handle for which we're returning the results
2034 LSPTR_OBJECTHANDLE GCHandle;
2036 // The following are initialized by the LS in response to our query:
2037 VMPTR_AppDomain vmAppDomain; // AD that handle is in (only applicable if fValid).
2038 bool fValid; // Did the LS determine the GC handle to be valid?
2039 } GetGCHandleInfoResult;
2041 // Allocate memory on the left-side
2044 ULONG bufSize; // number of bytes to allocate
2047 // Memory allocated on the left-side
2050 void *pBuffer; // LS pointer to the buffer allocated
2051 HRESULT hr; // success / failure
2054 // Free a buffer allocated on the left-side with GetBuffer
2057 void *pBuffer; // Pointer previously returned in GetBufferResult
2063 } ReleaseBufferResult;
2065 // Apply an EnC edit
2068 VMPTR_DomainFile vmDomainFile; // Module to edit
2069 DWORD cbDeltaMetadata; // size of blob pointed to by pDeltaMetadata
2070 CORDB_ADDRESS pDeltaMetadata; // pointer to delta metadata in debuggee
2071 // it's the RS's responsibility to allocate and free
2072 // this (and pDeltaIL) using GetBuffer / ReleaseBuffer
2073 CORDB_ADDRESS pDeltaIL; // pointer to delta IL in debugee
2074 DWORD cbDeltaIL; // size of blob pointed to by pDeltaIL
2080 } ApplyChangesResult;
2084 mdTypeDef classMetadataToken;
2085 VMPTR_DomainFile vmDomainFile;
2086 LSPTR_ASSEMBLY classDebuggerAssemblyToken;
2091 mdTypeDef classMetadataToken;
2092 VMPTR_DomainFile vmDomainFile;
2093 LSPTR_ASSEMBLY classDebuggerAssemblyToken;
2098 VMPTR_DomainFile vmDomainFile;
2104 VMPTR_OBJECTHANDLE vmExceptionHandle;
2111 VMPTR_Thread vmThreadToken;
2122 } IsTransitionStubResult;
2126 CORDB_ADDRESS startAddress;
2128 VMPTR_Thread vmThreadToken;
2129 VMPTR_DomainFile vmDomainFile;
2130 mdMethodDef mdMethod;
2131 VMPTR_MethodDesc vmMethodDesc;
2134 void * firstExceptionHandler;
2135 } SetIP; // this is also used for CanSetIP
2141 EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szCategory;
2142 Ls_Rs_StringBuffer szContent;
2150 EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szSwitchName;
2151 EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szParentSwitchName;
2152 } LogSwitchSettingMessage;
2154 // information needed to send to the RS as part of a custom notification from the target
2157 // Domain file for the domain in which the notification occurred
2158 VMPTR_DomainFile vmDomainFile;
2160 // metadata token for the type of the CustomNotification object's type
2161 mdTypeDef classToken;
2162 } CustomNotification;
2166 VMPTR_Thread vmThreadToken;
2167 CorDebugThreadState debugState;
2170 DebuggerIPCE_FuncEvalInfo FuncEval;
2174 CORDB_ADDRESS argDataArea;
2175 LSPTR_DEBUGGEREVAL debuggerEvalKey;
2176 } FuncEvalSetupComplete;
2180 RSPTR_CORDBEVAL funcEvalKey;
2185 // AppDomain that the result is in.
2186 VMPTR_AppDomain vmAppDomain;
2188 VMPTR_OBJECTHANDLE vmObjectHandle;
2189 DebuggerIPCE_ExpandedTypeData resultType;
2194 LSPTR_DEBUGGEREVAL debuggerEvalKey;
2199 LSPTR_DEBUGGEREVAL debuggerEvalKey;
2200 } FuncEvalRudeAbort;
2204 LSPTR_DEBUGGEREVAL debuggerEvalKey;
2209 void *objectRefAddress;
2210 VMPTR_OBJECTHANDLE vmObjectHandle;
2216 NameChangeType eventType;
2217 VMPTR_AppDomain vmAppDomain;
2218 VMPTR_Thread vmThread;
2223 VMPTR_DomainFile vmDomainFile;
2228 // EnC Remap opportunity
2231 VMPTR_DomainFile vmDomainFile;
2232 mdMethodDef funcMetadataToken ; // methodDef of function with remap opportunity
2233 SIZE_T currentVersionNumber; // version currently executing
2234 SIZE_T resumeVersionNumber; // latest version
2235 SIZE_T currentILOffset; // the IL offset of the current IP
2236 SIZE_T *resumeILOffset; // pointer into left-side where an offset to resume
2237 // to should be written if remap is desired.
2240 // EnC Remap has taken place
2243 VMPTR_DomainFile vmDomainFile;
2244 mdMethodDef funcMetadataToken; // methodDef of function that was remapped
2247 // Notification that the LS is about to update a CLR data structure to account for a
2248 // specific edit made by EnC (function add/update or field add).
2251 VMPTR_DomainFile vmDomainFile;
2252 mdToken memberMetadataToken; // Either a methodDef token indicating the function that
2253 // was updated/added, or a fieldDef token indicating the
2254 // field which was added.
2255 mdTypeDef classMetadataToken; // TypeDef token of the class in which the update was made
2256 SIZE_T newVersionNumber; // The new function/module version
2263 DebuggerIPCE_BasicTypeData type;
2267 // Event used to tell LS if a single function is user or non-user code.
2268 // Same structure used to get function status.
2269 // @todo - Perhaps we can bundle these up so we can set multiple funcs w/ 1 event?
2272 VMPTR_DomainFile vmDomainFile;
2273 mdMethodDef funcMetadataToken;
2275 } SetJMCFunctionStatus;
2280 } GetThreadForTaskId;
2284 VMPTR_Thread vmThreadToken;
2285 } GetThreadForTaskIdResult;
2289 CONNID connectionId;
2294 CONNID connectionId;
2295 EmbeddedIPCString<MAX_LONGPATH> wzConnectionName;
2306 VMPTR_OBJECTHANDLE vmObjectHandle;
2307 } CreateHandleResult;
2309 // used in DB_IPCE_DISPOSE_HANDLE event
2312 VMPTR_OBJECTHANDLE vmObjectHandle;
2318 FramePointer framePointer;
2320 CorDebugExceptionCallbackType eventType;
2322 VMPTR_OBJECTHANDLE vmExceptionHandle;
2323 } ExceptionCallback2;
2327 CorDebugExceptionUnwindCallbackType eventType;
2333 VMPTR_Thread vmThreadToken;
2334 FramePointer frameToken;
2335 } InterceptException;
2339 VMPTR_Module vmModule;
2340 void * pMetadataStart;
2341 ULONG nMetadataSize;
2342 } MetadataUpdateRequest;
2348 // When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound
2349 // for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is
2350 // orthogonal to the host's page size. Round the buffer size up to a multiple of 8 since MSVC seems more
2351 // aggressive in this regard than gcc.
2352 #define CorDBIPC_TRANSPORT_BUFFER_SIZE (((sizeof(DebuggerIPCEvent) + 7) / 8) * 8)
2354 // A DebuggerIPCEvent must fit in the send & receive buffers, which are CorDBIPC_BUFFER_SIZE bytes.
2355 static_assert_no_msg(sizeof(DebuggerIPCEvent) <= CorDBIPC_BUFFER_SIZE);
2356 static_assert_no_msg(CorDBIPC_TRANSPORT_BUFFER_SIZE <= CorDBIPC_BUFFER_SIZE);
2358 // 2*sizeof(WCHAR) for the two string terminating characters in the FirstLogMessage
2359 #define LOG_MSG_PADDING 4
2361 #endif /* _DbgIPCEvents_h_ */