typedef unsigned int DWORD; typedef unsigned char BYTE; typedef unsigned char * PBYTE; typedef DWORD HRESULT; typedef unsigned short USHORT; typedef unsigned int ULONG; typedef unsigned char UCHAR; typedef bool BOOL; static const DWORD kCurrentMajorVersion = 2; static const DWORD kCurrentMinorVersion = 0; #define CorDBIPC_BUFFER_SIZE 4016 #define MSLAYOUT __attribute__((__ms_struct__)) enum IPCEventType { IPCET_OldStyle, IPCET_DebugEvent, IPCET_Max, }; typedef struct _GUID { ULONG Data1; // NOTE: diff from Win32, for LP64 USHORT Data2; USHORT Data3; UCHAR Data4[ 8 ]; } GUID; enum MessageType { // Session management operations. These must come first and MT_SessionClose must be last in the group. MT_SessionRequest, // RS -> LS : Request a new session be formed (optionally pass encrypted data key) MT_SessionAccept, // LS -> RS : Accept new session MT_SessionReject, // LS -> RS : Reject new session, give reason MT_SessionResync, // RS <-> LS : Resync broken connection by informing other side which messages must be resent MT_SessionClose, // RS -> LS : Gracefully terminate a session // Debugger events. MT_Event, // RS <-> LS : A debugger event is being sent as the data block of the message // Misc management operations. MT_ReadMemory, // RS <-> LS : RS wants to read LS memory block (or LS is replying to such a request) MT_WriteMemory, // RS <-> LS : RS wants to write LS memory block (or LS is replying to such a request) MT_VirtualUnwind, // RS <-> LS : RS wants to LS unwind a stack frame (or LS is replying to such a request) MT_GetDCB, // RS <-> LS : RS wants to read LS DCB (or LS is replying to such a request) MT_SetDCB, // RS <-> LS : RS wants to write LS DCB (or LS is replying to such a request) MT_GetAppDomainCB, // RS <-> LS : RS wants to read LS AppDomainCB (or LS is replying to such a request) }; enum RejectReason { RR_IncompatibleVersion, // LS doesn't support the major version asked for in the request. RR_AlreadyAttached, // LS already has another session open (LS only supports one session at a time) }; struct MessageHeader { MessageType m_eType; // Type of message this is DWORD m_cbDataBlock; // Size of data block that immediately follows this header (can be zero) DWORD m_dwId; // Message ID assigned by the sender of this message DWORD m_dwReplyId; // Message ID that this is a reply to (used by messages such as MT_GetDCB) DWORD m_dwLastSeenId; // Message ID last seen by sender (receiver can discard up to here from send queue) DWORD m_dwReserved; // Reserved for future expansion (must be initialized to zero and // never read) // The rest of the header varies depending on the message type (keep the maximum size of this union // small since all messages will pay the overhead, large message type specific data should go in the // following data block). union { // Used by MT_SessionRequest / MT_SessionAccept. struct { DWORD m_dwMajorVersion; // Protocol version requested/accepted DWORD m_dwMinorVersion; } VersionInfo; // Used by MT_SessionReject. struct { RejectReason m_eReason; // Reason for rejection. DWORD m_dwMajorVersion; // Highest protocol version the LS supports DWORD m_dwMinorVersion; } SessionReject; // Used by MT_ReadMemory and MT_WriteMemory. struct { PBYTE m_pbLeftSideBuffer; // Address of memory to read/write on the LS DWORD m_cbLeftSideBuffer; // Size in bytes of memory to read/write HRESULT m_hrResult; // Result from LS (access can fail due to unmapped memory etc.) } MemoryAccess; // Used by MT_Event. struct { IPCEventType m_eIPCEventType; // multiplexing type of this IPC event DWORD m_eType; // Event type (useful for debugging) } Event; } TypeSpecificData; BYTE m_sMustBeZero[8]; // Set this to zero when initializing and never read the contents }; struct SessionRequestData { GUID m_sSessionID; // Unique session ID. Treated as byte blob so no endian-ness }; typedef unsigned int SIZE_T; typedef unsigned int RemoteHANDLE; struct MSLAYOUT DebuggerIPCRuntimeOffsets { #ifdef FEATURE_INTEROP_DEBUGGING void *m_genericHijackFuncAddr; void *m_signalHijackStartedBPAddr; void *m_excepForRuntimeHandoffStartBPAddr; void *m_excepForRuntimeHandoffCompleteBPAddr; void *m_signalHijackCompleteBPAddr; void *m_excepNotForRuntimeBPAddr; void *m_notifyRSOfSyncCompleteBPAddr; void *m_raiseExceptionAddr; // The address of kernel32!RaiseException in the debuggee DWORD m_debuggerWordTLSIndex; // The TLS slot for the debugger word used in the debugger hijack functions #endif // FEATURE_INTEROP_DEBUGGING SIZE_T m_TLSIndex; // The TLS index of the thread-local storage for coreclr.dll SIZE_T m_TLSEEThreadOffset; // TLS Offset of the Thread pointer. SIZE_T m_TLSIsSpecialOffset; // TLS Offset of the "IsSpecial" status for a thread. SIZE_T m_TLSCantStopOffset; // TLS Offset of the Can't-Stop count. SIZE_T m_EEThreadStateOffset; // Offset of m_state in a Thread SIZE_T m_EEThreadStateNCOffset; // Offset of m_stateNC in a Thread SIZE_T m_EEThreadPGCDisabledOffset; // Offset of the bit for whether PGC is disabled or not in a Thread DWORD m_EEThreadPGCDisabledValue; // Value at m_EEThreadPGCDisabledOffset that equals "PGC disabled". SIZE_T m_EEThreadFrameOffset; // Offset of the Frame ptr in a Thread SIZE_T m_EEThreadMaxNeededSize; // Max memory to read to get what we need out of a Thread object DWORD m_EEThreadSteppingStateMask; // Mask for Thread::TSNC_DebuggerIsStepping DWORD m_EEMaxFrameValue; // The max Frame value SIZE_T m_EEThreadDebuggerFilterContextOffset; // Offset of debugger's filter context within a Thread Object. SIZE_T m_EEFrameNextOffset; // Offset of the next ptr in a Frame DWORD m_EEIsManagedExceptionStateMask; // Mask for Thread::TSNC_DebuggerIsManagedException void *m_pPatches; // Addr of patch table BOOL *m_pPatchTableValid; // Addr of g_patchTableValid SIZE_T m_offRgData; // Offset of m_pcEntries SIZE_T m_offCData; // Offset of count of m_pcEntries SIZE_T m_cbPatch; // Size per patch entry SIZE_T m_offAddr; // Offset within patch of target addr SIZE_T m_offOpcode; // Offset within patch of target opcode SIZE_T m_cbOpcode; // Max size of opcode SIZE_T m_offTraceType; // Offset of the trace.type within a patch DWORD m_traceTypeUnmanaged; // TRACE_UNMANAGED }; // DCB struct MSLAYOUT DebuggerIPCControlBlock { // Version data should be first in the control block to ensure that we can read it even if the control block // changes. SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized ULONG m_verMajor; // CLR build number for the Left Side. ULONG m_verMinor; // CLR build number for the Left Side. // This next stuff fits in a DWORD. bool m_checkedBuild; // CLR build type for the Left Side. // using the first padding byte to indicate if hosted in fiber mode. // We actually just need one bit. So if needed, can turn this to a bit. // BYTE padding1; bool m_bHostingInFiber; BYTE padding2; BYTE padding3; ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side. ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support. ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side. ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires. HRESULT m_errorHR; unsigned int m_errorCode; // 64-bit needs this padding to make the handles after this aligned. // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0. ULONG padding4; RemoteHANDLE m_rightSideEventAvailable; RemoteHANDLE m_rightSideEventRead; // @dbgtodo inspection - this is where LSEA and LSER used to be. We need to the padding to maintain binary compatibility. // Eventually, we expect to remove this whole block. RemoteHANDLE m_paddingObsoleteLSEA; RemoteHANDLE m_paddingObsoleteLSER; RemoteHANDLE m_rightSideProcessHandle; //............................................................................. // Everything above this point must have the exact same binary layout as v1.1. // See protocol details below. //............................................................................. RemoteHANDLE m_leftSideUnmanagedWaitEvent; // This is set immediately when the helper thread is created. // This will be set even if there's a temporary helper thread or if the real helper // thread is not yet pumping (eg, blocked on a loader lock). DWORD m_realHelperThreadId; // This is only published once the helper thread starts running in its main loop. // Thus we can use this field to see if the real helper thread is actually pumping. DWORD m_helperThreadId; // This is non-zero if the LS has a temporary helper thread. DWORD m_temporaryHelperThreadId; // ID of the Helper's canary thread. DWORD m_CanaryThreadId; DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets; void *m_helperThreadStartAddr; void *m_helperRemoteStartAddr; DWORD *m_specialThreadList; BYTE m_receiveBuffer[CorDBIPC_BUFFER_SIZE]; BYTE m_sendBuffer[CorDBIPC_BUFFER_SIZE]; DWORD m_specialThreadListLength; bool m_shutdownBegun; bool m_rightSideIsWin32Debugger; // RS status bool m_specialThreadListDirty; bool m_rightSideShouldCreateHelperThread; }; struct MSLAYOUT DebuggerIPCControlBlockTransport { // Version data should be first in the control block to ensure that we can read it even if the control block // changes. SIZE_T m_DCBSize; // note this field is used as a semaphore to indicate the DCB is initialized ULONG m_verMajor; // CLR build number for the Left Side. ULONG m_verMinor; // CLR build number for the Left Side. // This next stuff fits in a DWORD. bool m_checkedBuild; // CLR build type for the Left Side. // using the first padding byte to indicate if hosted in fiber mode. // We actually just need one bit. So if needed, can turn this to a bit. // BYTE padding1; bool m_bHostingInFiber; BYTE padding2; BYTE padding3; ULONG m_leftSideProtocolCurrent; // Current protocol version for the Left Side. ULONG m_leftSideProtocolMinSupported; // Minimum protocol the Left Side can support. ULONG m_rightSideProtocolCurrent; // Current protocol version for the Right Side. ULONG m_rightSideProtocolMinSupported; // Minimum protocol the Right Side requires. HRESULT m_errorHR; unsigned int m_errorCode; // 64-bit needs this padding to make the handles after this aligned. // But x86 can't have this padding b/c it breaks binary compatibility between v1.1 and v2.0. ULONG padding4; // This is set immediately when the helper thread is created. // This will be set even if there's a temporary helper thread or if the real helper // thread is not yet pumping (eg, blocked on a loader lock). DWORD m_realHelperThreadId; // This is only published once the helper thread starts running in its main loop. // Thus we can use this field to see if the real helper thread is actually pumping. DWORD m_helperThreadId; // This is non-zero if the LS has a temporary helper thread. DWORD m_temporaryHelperThreadId; // ID of the Helper's canary thread. DWORD m_CanaryThreadId; DebuggerIPCRuntimeOffsets *m_pRuntimeOffsets; void *m_helperThreadStartAddr; void *m_helperRemoteStartAddr; DWORD *m_specialThreadList; DWORD m_specialThreadListLength; bool m_shutdownBegun; bool m_rightSideIsWin32Debugger; // RS status bool m_specialThreadListDirty; bool m_rightSideShouldCreateHelperThread; };