text: // Licensed to the .NET Foundation under one or more agreements.
  // The .NET Foundation licenses this file to you under the MIT license.
  // See the LICENSE file in the project root for more information.
  /* ------------------------------------------------------------------------- *
   * DbgIPCEvents.h -- header file for private Debugger data shared by various
  // 
  
   *                   debugger components.
   * ------------------------------------------------------------------------- */
  
  #ifndef _DbgIPCEvents_h_
  #define _DbgIPCEvents_h_
  
  #include <new.hpp>
  #include <cor.h>
  #include <cordebug.h>
  #include <corjit.h> // for ICorDebugInfo::VarLocType & VarLoc
  #include <specstrings.h>
  
  #include "dbgtargetcontext.h"
  
  
  // Get version numbers for IPCHeader stamp
  #include "ndpversion.h"
  
  #include "dbgappdomain.h"
  
  #include "./common.h"
  
  //-----------------------------------------------------------------------------
  // V3 additions to IPC protocol between LS and RS.
  //-----------------------------------------------------------------------------
  
  // Special Exception code for LS to communicate with RS. 
  // LS will raise this exception to communicate managed debug events to the RS.
  // Exception codes can't use bit 0x10000000, that's reserved by OS.
  #define CLRDBG_NOTIFICATION_EXCEPTION_CODE  ((DWORD) 0x04242420)
  
  // This is exception argument 0 included in debugger notification events. 
  // The debugger uses this as a sanity check.
  // This could be very volatile data that changes between builds.
  #define CLRDBG_EXCEPTION_DATA_CHECKSUM ((DWORD) 0x31415927)
  
  
  // Reasons for hijack.
  namespace EHijackReason
  {
      enum EHijackReason
      {
          kUnhandledException = 1,
          kM2UHandoff = 2,
          kFirstChanceSuspend = 3,
          kGenericHijack = 4,
          kMax
      };
      inline bool IsValid(EHijackReason value)
      {
          SUPPORTS_DAC;
          return (value > 0) && (value < kMax);
      }
  }
  
  
  
  #define     MAX_LOG_SWITCH_NAME_LEN     256
  
  //-----------------------------------------------------------------------------
  // Versioning note:
  // This file describes the IPC communication protocol between the LS (mscorwks)
  // and the RS (mscordbi). For Desktop builds, it is private and can change on a 
  // daily basis. The version of the LS will always match the version of the RS 
  // (but see the discussion of CoreCLR below). They are like a single conceptual 
  // DLL split across 2 processes. 
  // The only restriction is that it should be flavor agnostic - so don't change
  // layout based off '#ifdef DEBUG'. This lets us drop a Debug flavor RS onto
  // a retail installation w/o any further installation woes. That's very useful
  // for debugging.
  //-----------------------------------------------------------------------------
  
  
  // We want this available for DbgInterface.h - put it here.
  typedef enum
  {
      IPC_TARGET_OUTOFPROC,
      IPC_TARGET_COUNT,
  } IpcTarget;
  
  //
  // Names of the setup sync event and shared memory used for IPC between the Left Side and the Right Side. NOTE: these
  // names must include a %d for the process id. The process id used is the process id of the debuggee.
  //
  
  #define CorDBIPCSetupSyncEventName W("CorDBIPCSetupSyncEvent_%d")
  
  //
  // This define controls whether we always pass first chance exceptions to the in-process first chance hijack filter
  // during interop debugging or if we try to short-circuit and make the decision out-of-process as much as possible.
  //
  #define CorDB_Short_Circuit_First_Chance_Ownership 1
  
  //
  // Defines for current version numbers for the left and right sides
  //
  #define CorDB_LeftSideProtocolCurrent           2
  #define CorDB_LeftSideProtocolMinSupported      2
  #define CorDB_RightSideProtocolCurrent          2
  #define CorDB_RightSideProtocolMinSupported     2
  
  //
  // The remaining data structures in this file can be shared between two processes and for network transport
  // based debugging this can mean two different platforms as well.  The two platforms that can share these 
  // data structures must have identical layouts for them (each field must lie at the same offset and have the 
  // same length). The MSLAYOUT macro should be applied to each structure to avoid any compiler packing differences.
  //
  
  //
  // DebuggerIPCRuntimeOffsets contains addresses and offsets of important global variables, functions, and fields in
  // Runtime objects. This is populated during Left Side initialization and is read by the Right Side. This struct is
  // mostly to facilitate unmanaged debugging support, but it may have some small uses for managed debugging.
  //
  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 the CLR is using to hold Thread objects
      SIZE_T  m_TLSIsSpecialIndex;                        // The index into the Predef block of the the "IsSpecial" status for a thread.
      SIZE_T  m_TLSCantStopIndex;                         // The index into the Predef block of the 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_EEThreadCantStopOffset;                   // Offset of the can't stop count in a Thread
      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
  
      DebuggerIPCRuntimeOffsets()
      {
          ZeroMemory(this, sizeof(DebuggerIPCRuntimeOffsets));
      }
  };
  
  //
  // The size of the send and receive IPC buffers.
  // These must be big enough to fit a DebuggerIPCEvent. Also, the bigger they are, the fewer events
  // it takes to send variable length stuff like the stack trace.
  // But for perf reasons, they need to be small enough to not just push us over a page boundary in an IPC block.
  // Unfortunately, there's a lot of other goo in the IPC block, so we can't use some clean formula. So we
  // have to resort to just tuning things.
  //
  
  // When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound
  // for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is
  // orthogonal to the host's page size. Because of this we defer definition of CorDBIPC_BUFFER_SIZE until we've
  // declared DebuggerIPCEvent at the end of this header (and we can do so because in the transport case there
  // aren't any embedded buffers in the DebuggerIPCControlBlock).
  
  #if defined(DBG_TARGET_X86) || defined(DBG_TARGET_ARM)
  #ifdef _WIN64
  #define CorDBIPC_BUFFER_SIZE 2104
  #else
  #define CorDBIPC_BUFFER_SIZE 2092
  #endif
  #else  // !_TARGET_X86_ && !_TARGET_ARM_
  // This is the size of a DebuggerIPCEvent.  You will hit an assert in Cordb::Initialize() (di\rsmain.cpp)
  // if this is not defined correctly.  AMD64 actually has a page size of 0x1000, not 0x2000.
  #define CorDBIPC_BUFFER_SIZE 4016 // (4016 + 6) * 2 + 148 = 8192 (two (DebuggerIPCEvent + alignment padding) + other fields = page size)
  #endif // DBG_TARGET_X86 || DBG_TARGET_ARM
  
  //
  // DebuggerIPCControlBlock describes the layout of the shared memory shared between the Left Side and the Right
  // Side. This includes error information, handles for the IPC channel, and space for the send/receive buffers.
  //
  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;
  
  #if defined(DBG_TARGET_WIN64)
      // 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;
  #endif // DBG_TARGET_WIN64
  
  
      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;
  
      // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without
      // changing this!
      // Only initialized by the LS, opened by the RS.
      HRESULT Init(
                   HANDLE rsea, 
                   HANDLE rser, 
                   HANDLE lsea, 
                   HANDLE lser,
                   HANDLE lsuwe
                  );
  
  };
  
  #if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
  
  // We need an alternate definition for the control block if using the transport, because the control block has to be sent over the transport
  // In particular we can't nest the send/receive buffers inside of it and we don't use any of the remote handles
  
  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;
  
  #if defined(DBG_TARGET_WIN64)
      // 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;
  #endif // DBG_TARGET_WIN64
  
      // 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;
  
      // NOTE The Init method works since there are no virtual functions - don't add any virtual functions without
      // changing this!
      // Only initialized by the LS, opened by the RS.
      HRESULT Init();
  
  };
  
  #endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
  
  #if defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
  #include "dbgtransportsession.h"
  #endif // defined(FEATURE_DBGIPC_TRANSPORT_VM) || defined(FEATURE_DBGIPC_TRANSPORT_DI)
  
  #if defined(DBG_TARGET_X86) && !defined(FEATURE_CORESYSTEM)
  // We have an versioning requirement.
  // 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
  // to look at a v2.0 app enough to recognize the version mismatch.
  // This check is only necessary for platforms that ran on v1.1 (Win32-x86)
  
  // Just to catch any potential illegal change in the IPC block, we assert the offsets against the offsets from v1.1.
  // The constants here are pulled from v1.1.
  // The RS will look at these versioning fields, so they absolutely must line up.
  static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolCurrent) == 0x10);
  static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_leftSideProtocolMinSupported) == 0x14);
  static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolCurrent) == 0x18);
  static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProtocolMinSupported) == 0x1c);
  
  // Unfortunately, on detecting such failure, v1.1 will also null out LSEA, LSER and RSPH.
  // If these get adjusted, a version-mismatch attach  will effectively null out random fields.
  static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSEA) == 0x30);
  static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_paddingObsoleteLSER) == 0x34);
  static_assert_no_msg(offsetof(DebuggerIPCControlBlock, m_rightSideProcessHandle) == 0x38);
  
  
  
  #endif
  
  #define INITIAL_APP_DOMAIN_INFO_LIST_SIZE   16
  
  
  //-----------------------------------------------------------------------------
  // Provide some Type-safety in the IPC block when we pass remote pointers around.
  //-----------------------------------------------------------------------------
  
  
  //-----------------------------------------------------------------------------
  // This is the same in both the LS & RS.
  // Definitions on the LS & RS should be binary compatible. So all storage is
  // declared in GeneralLsPointer, and then the Ls & RS each have their own
  // derived accessors.
  //-----------------------------------------------------------------------------
  class MSLAYOUT GeneralLsPointer
  {
  protected:
      friend ULONG_PTR LsPtrToCookie(GeneralLsPointer p);
      void * m_ptr;
  
  public:
      bool IsNull() { return m_ptr == NULL; }
  };
  
  class MSLAYOUT GeneralRsPointer
  {
  protected:
      UINT m_data;
  
  public:
      bool IsNull() { return m_data == 0; }
  };
  
  // In some cases, we need to get a uuid from a pointer (ie, in a hash)
  inline ULONG_PTR LsPtrToCookie(GeneralLsPointer p) {
      return (ULONG_PTR) p.m_ptr;
  }
  #define VmPtrToCookie(vm) LsPtrToCookie((vm).ToLsPtr())
  
  
  #ifdef RIGHT_SIDE_COMPILE
  //-----------------------------------------------------------------------------
  // Infrasturcture for RS Definitions
  //-----------------------------------------------------------------------------
  
  // On the RS, we don't have the LS classes defined, so we can't templatize that
  // in terms of <class T>, but we still want things to be unique.
  // So we create an empty enum for each LS type and then templatize it in terms
  // of the enum.
  template <typename T>
  class MSLAYOUT LsPointer : public GeneralLsPointer
  {
  public:
      void Set(void * p)
      {
          m_ptr = p;
      }
      void * UnsafeGet()
      {
          return m_ptr;
      }
  
      static LsPointer<T> NullPtr()
      {
          return MakePtr(NULL);
      }
  
      static LsPointer<T> MakePtr(T* p)
      {
  #ifdef _PREFAST_
  #pragma warning(push)
  #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
  #endif // _PREFAST_
  
          LsPointer<T> t;
          t.Set(p);
          return t;
  
  #ifdef _PREFAST_
  #pragma warning(pop)
  #endif // _PREFAST_
      }
  
      bool operator!= (void * p) { return m_ptr != p; }
      bool operator== (void * p) { return m_ptr == p; }
      bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; }
  
      // We should never UnWrap() them in the RS, so we don't define that here.
  };
  
  class CordbProcess;
  template <class T> UINT AllocCookie(CordbProcess * pProc, T * p);
  template <class T> T * UnwrapCookie(CordbProcess * pProc, UINT cookie);
  
  UINT AllocCookieCordbEval(CordbProcess * pProc, class CordbEval * p);
  class CordbEval * UnwrapCookieCordbEval(CordbProcess * pProc, UINT cookie);
  
  template <class CordbEval> UINT AllocCookie(CordbProcess * pProc, CordbEval * p)
  {
      return AllocCookieCordbEval(pProc, p);
  }
  template <class CordbEval> CordbEval * UnwrapCookie(CordbProcess * pProc, UINT cookie)
  {
      return UnwrapCookieCordbEval(pProc, cookie);
  }
  
  
  
  // This is how the RS sees the pointers in the IPC block.
  template<class T>
  class MSLAYOUT RsPointer : public GeneralRsPointer
  {
  public:
      // Since we're being used inside a union, we can't have a ctor.
  
      static RsPointer<T> NullPtr()
      {
          RsPointer<T> t;
          t.m_data = 0;
          return t;        
      }
  
      bool AllocHandle(CordbProcess *pProc, T* p)
      {    
          // This will force validation.
          m_data = AllocCookie<T>(pProc, p);
          return (m_data != 0);       
      }
  
      bool operator==(RsPointer<T> p) { return p.m_data == this->m_data; }
  
      T* UnWrapAndRemove(CordbProcess *pProc)
      {
          return UnwrapCookie<T>(pProc, m_data);
      }
      
  protected:
  };
  
  // Forward declare a class so that each type of LS pointer can have
  // its own type.  We use the real class name to be compatible with VMPTRs.
  #define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \
      ls_type; \
      typedef LsPointer<ls_type> ptr_name;
  
  
  #define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \
      class rs_type; \
      typedef RsPointer<rs_type> ptr_name;
  
  #else // !RIGHT_SIDE_COMPILE
  //-----------------------------------------------------------------------------
  // Infrastructure for LS Definitions
  //-----------------------------------------------------------------------------
  
  // This is how the LS sees the pointers in the IPC block.
  template<typename T>
  class MSLAYOUT LsPointer : public GeneralLsPointer
  {
  public:
      // Since we're being used inside a union, we can't have a ctor.
      //LsPointer() { }
  
      static LsPointer<T> NullPtr()
      {
          return MakePtr(NULL);
      }
  
      static LsPointer<T> MakePtr(T * p)
      {
  #ifdef _PREFAST_
  #pragma warning(push)
  #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
  #endif // _PREFAST_
  
          LsPointer<T> t;
          t.Set(p);
          return t;
  
  #ifdef _PREFAST_
  #pragma warning(pop)
  #endif // _PREFAST_
      }
  
      bool operator!= (void * p) { return m_ptr != p; }
      bool operator== (void * p) { return m_ptr == p; }
      bool operator==(LsPointer<T> p) { return p.m_ptr == this->m_ptr; }
  
      // @todo - we want to be able to swap out Set + Unwrap functions
      void Set(T * p)
      {
          SUPPORTS_DAC;
          // We could validate the pointer here.
          m_ptr = p;
      }
  
      T * UnWrap()
      {
          // If we wanted to validate the pointer, here's our chance.
          return static_cast<T*>(m_ptr);        
      }
  };
  
  template <class n>
  class MSLAYOUT RsPointer : public GeneralRsPointer
  {
  public:
      static RsPointer<n> NullPtr()
      {
          RsPointer<n> t;
          t.m_data = 0;
          return t;
      }
  
      bool operator==(RsPointer<n> p) { return p.m_data == this->m_data; }
  
      // We should never UnWrap() them in the LS, so we don't define that here.
  };
  
  #define DEFINE_LSPTR_TYPE(ls_type, ptr_name) \
      ls_type; \
      typedef LsPointer<ls_type> ptr_name;
  
  #define DEFINE_RSPTR_TYPE(rs_type, ptr_name) \
      enum __RS__##rs_type { };  \
      typedef RsPointer<__RS__##rs_type> ptr_name;
  
  #endif // !RIGHT_SIDE_COMPILE
  
  // We must be binary compatible w/ a pointer.
  static_assert_no_msg(sizeof(LsPointer<void>) == sizeof(GeneralLsPointer));
  
  static_assert_no_msg(sizeof(void*) == sizeof(GeneralLsPointer));
  
  
  
  //-----------------------------------------------------------------------------
  // Definitions for Left-Side ptrs.
  // NOTE: Use VMPTR instead of LSPTR. Don't add new LSPTR types.
  // 
  //-----------------------------------------------------------------------------
  
  
  
  DEFINE_LSPTR_TYPE(class Assembly,  LSPTR_ASSEMBLY);
  DEFINE_LSPTR_TYPE(class DebuggerJitInfo, LSPTR_DJI);
  DEFINE_LSPTR_TYPE(class DebuggerMethodInfo, LSPTR_DMI);
  DEFINE_LSPTR_TYPE(class MethodDesc,         LSPTR_METHODDESC);
  DEFINE_LSPTR_TYPE(class DebuggerBreakpoint, LSPTR_BREAKPOINT);
  DEFINE_LSPTR_TYPE(class DebuggerDataBreakpoint, LSPTR_DATA_BREAKPOINT);
  DEFINE_LSPTR_TYPE(class DebuggerEval,       LSPTR_DEBUGGEREVAL);
  DEFINE_LSPTR_TYPE(class DebuggerStepper,    LSPTR_STEPPER);
  
  // Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct.
  #if defined(RIGHT_SIDE_COMPILE)
  typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT;
  #else  // RIGHT_SIDE_COMPILE
  typedef LsPointer<DT_CONTEXT> LSPTR_CONTEXT;
  #endif // RIGHT_SIDE_COMPILE
  
  DEFINE_LSPTR_TYPE(struct OBJECTHANDLE__,    LSPTR_OBJECTHANDLE);
  DEFINE_LSPTR_TYPE(class TypeHandleDummyPtr, LSPTR_TYPEHANDLE); // TypeHandle in the LS is not a direct pointer.
  
  //-----------------------------------------------------------------------------
  // Definitions for Right-Side ptrs.
  //-----------------------------------------------------------------------------
  DEFINE_RSPTR_TYPE(CordbEval,               RSPTR_CORDBEVAL);
  
  
  //---------------------------------------------------------------------------------------
  // VMPTR_Base is the base type for an abstraction over pointers into the VM so 
  // that DBI can treat them as opaque handles. Classes will derive from it to 
  // provide type-safe Target pointers, which ICD will view as opaque handles.
  //
  // Lifetimes:  
  //   VMPTR_ objects survive across flushing the DAC cache. Therefore, the underlying
  //   storage must be a target-pointer (and not a marshalled host pointer).
  //   The RS must ensure they're still in sync with the LS (eg, by
  //   tracking unload events).
  //  
  //
  // Assumptions:
  //    These handles are TADDR pointers and must not require any cleanup from DAC/DBI.
  //    For direct untyped pointers into the VM, use CORDB_ADDRESS.
  //
  // Notes:
  //  1. This helps enforce that DBI goes through the primitives interface
  //     for all access (and that it doesn't accidentally start calling
  //     dac-ized methods on the objects)
  //  2. This isolates DBI from VM headers. 
  //  3. This isolates DBI from the dac implementation (of DAC_Ptr)
  //  4. This is distinct from LSPTR because LSPTRs are truly opaque handles, whereas VMPtrs
  //     move across VM, DAC, and DBI, exposing proper functionality in each component.
  //  5. VMPTRs are blittable because they are Target Addresses which act as opaque
  //     handles outside of the Target / Dac-marshaller.  
  //
  //---------------------------------------------------------------------------------------
  
  
  template <typename TTargetPtr, typename TDacPtr>
  class MSLAYOUT VMPTR_Base
  {
      // Underlying pointer into Target address space.
      // Target pointers are blittable. 
      // - In Target: can be used as normal local pointers.
      // - In DAC: must be marshalled to a host-pointer and then they can be used via DAC
      // - In RS: opaque handles.
  private:
      TADDR m_addr;
  
  public:
      typedef VMPTR_Base<TTargetPtr,TDacPtr> VMPTR_This;
  
      // For DBI, VMPTRs are opaque handles.
      // But the DAC side is allowed to inspect the handles to get at the raw pointer.
  #if defined(ALLOW_VMPTR_ACCESS)
      // 
      // Case 1: Using in DAcDbi implementation
      //
  
      // DAC accessor
      TDacPtr GetDacPtr() const
      {
          SUPPORTS_DAC;
          return TDacPtr(m_addr);
      }
  
  
      // This will initialize the handle to a given target-pointer. 
      // We choose TADDR to make it explicit that it's a target pointer and avoid the risk
      // of it accidentally getting marshalled to a host pointer. 
      void SetDacTargetPtr(TADDR addr)
      {
          SUPPORTS_DAC;
          m_addr = addr;
      }
      
      void SetHostPtr(const TTargetPtr * pObject)
      {
          SUPPORTS_DAC;
          m_addr = PTR_HOST_TO_TADDR(pObject);        
      }
  
  
  #elif !defined(RIGHT_SIDE_COMPILE)
      //
      // Case 2: Used in Left-side. Can get/set from local pointers.
      //
  
      // This will set initialize from a Target pointer. Since this is happening in the 
      // Left-side (Target), the pointer is local.
      // This is commonly used by the Left-side to create a VMPTR_ for a notification event.
      void SetRawPtr(TTargetPtr * ptr) 
      {
          m_addr = reinterpret_cast<TADDR>(ptr);
      }
  
      // This will get the raw underlying target pointer. 
      // This can be used by inproc Left-side code to unwrap a VMPTR (Eg, for a func-eval
      // hijack or in-proc worker threads)
      TTargetPtr * GetRawPtr()
      {
          return reinterpret_cast<TTargetPtr*>(m_addr);
      }
  
      // Convenience for converting TTargetPtr --> VMPTR
      static VMPTR_This MakePtr(TTargetPtr * ptr)
      {
  #ifdef _PREFAST_
  #pragma warning(push)
  #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
  #endif // _PREFAST_
  
          VMPTR_This t;
          t.SetRawPtr(ptr);
          return t;
  
  #ifdef _PREFAST_
  #pragma warning(pop)
  #endif // _PREFAST_
      }
  
  
  #else
      //
      // Case 3: Used in RS. Opaque handles only.
      //
  #endif
  
  
  #ifndef DACCESS_COMPILE
      // For compatibility, these can be converted to LSPTRs on the RS or LS (case 2 and 3).  We don't allow
      // this in the DAC case because it's a cast between address spaces which we're trying to eliminate
      // in the DAC code.
      // @dbgtodo  inspection: LSPTRs will go away entirely once we've moved completely over to DAC
      LsPointer<TTargetPtr> ToLsPtr()
      {
          return LsPointer<TTargetPtr>::MakePtr( reinterpret_cast<TTargetPtr *>(m_addr));
      }
  #endif
      
      //
      // Operators to emulate Pointer semantics.
      //
      bool IsNull() { SUPPORTS_DAC; return m_addr == NULL; }
  
      static VMPTR_This NullPtr()
      {
          SUPPORTS_DAC;
  
  #ifdef _PREFAST_
  #pragma warning(push)
  #pragma warning(disable:6001) // PREfast warning: Using uninitialize memory 't'
  #endif // _PREFAST_
  
          VMPTR_This dummy;
          dummy.m_addr = NULL;
          return dummy;
  
  #ifdef _PREFAST_
  #pragma warning(pop)
  #endif // _PREFAST_
      }
  
      bool operator!= (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr != vmOther.m_addr; }
      bool operator== (VMPTR_This vmOther) const { SUPPORTS_DAC; return this->m_addr == vmOther.m_addr; }
  };
  
  #if defined(ALLOW_VMPTR_ACCESS)
  // Helper macro to define a VMPTR.
  // This is used in the DAC case, so this definition connects the pointers up to their DAC values.
  #define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \
      ls_type;  \
      typedef VMPTR_Base<ls_type, dac_ptr_type> ptr_name;
  
  #else
  // Helper macro to define a VMPTR.
  // This is used in the Right-side and Left-side (but not DAC) case.
  // This definition explicitly ignores dac_ptr_type to prevent accidental DAC usage.
  #define DEFINE_VMPTR(ls_type, dac_ptr_type, ptr_name) \
      ls_type;  \
      typedef VMPTR_Base<ls_type, void> ptr_name;
  
  #endif
  
  // Declare VMPTRs.
  // The naming convention for instantiating a VMPTR is a 'vm' prefix. 
  //
  //           VM definition,         DAC definition,     pretty name for VMPTR
  DEFINE_VMPTR(class AppDomain,       PTR_AppDomain,      VMPTR_AppDomain);
  
  // Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct.
  // DEFINE_VMPTR(struct _CONTEXT,       PTR_CONTEXT,        VMPTR_CONTEXT);
  #if defined(ALLOW_VMPTR_ACCESS)
  typedef VMPTR_Base<DT_CONTEXT, PTR_CONTEXT> VMPTR_CONTEXT;
  #else
  typedef VMPTR_Base<DT_CONTEXT, void > VMPTR_CONTEXT;
  #endif
  
  // DomainFile is a base-class for a CLR module, with app-domain affinity.
  // For domain-neutral modules (like mscorlib), there is a DomainFile instance
  // for each appdomain the module lives in. 
  // This is the canonical handle ICorDebug uses to a CLR module. 
  DEFINE_VMPTR(class DomainFile,      PTR_DomainFile,     VMPTR_DomainFile);
  DEFINE_VMPTR(class Module,          PTR_Module,         VMPTR_Module);
  
  // DomainAssembly derives from DomainFile and represents a manifest module. 
  DEFINE_VMPTR(class DomainAssembly,  PTR_DomainAssembly, VMPTR_DomainAssembly);
  DEFINE_VMPTR(class Assembly,        PTR_Assembly,       VMPTR_Assembly);
  
  DEFINE_VMPTR(class PEFile,          PTR_PEFile,         VMPTR_PEFile); 
  DEFINE_VMPTR(class MethodDesc,      PTR_MethodDesc,     VMPTR_MethodDesc);
  DEFINE_VMPTR(class FieldDesc,       PTR_FieldDesc,      VMPTR_FieldDesc);
  
  // ObjectHandle is a safe way to represent an object into the GC heap. It gets updated
  // when a GC occurs.
  DEFINE_VMPTR(struct OBJECTHANDLE__, TADDR,              VMPTR_OBJECTHANDLE);
  
  DEFINE_VMPTR(class TypeHandle,      PTR_TypeHandle,     VMPTR_TypeHandle);   
  
  // A VMPTR_Thread represents a thread that has entered the runtime at some point. 
  // It may or may not have executed managed code yet; and it may or may not have managed code
  // on its callstack.
  DEFINE_VMPTR(class Thread,          PTR_Thread,         VMPTR_Thread);
  
  DEFINE_VMPTR(class Object,          PTR_Object,         VMPTR_Object);
  
  DEFINE_VMPTR(class CrstBase,        PTR_Crst,           VMPTR_Crst);
  DEFINE_VMPTR(class SimpleRWLock,    PTR_SimpleRWLock,   VMPTR_SimpleRWLock);
  DEFINE_VMPTR(class SimpleRWLock,    PTR_SimpleRWLock,   VMPTR_RWLock);
  DEFINE_VMPTR(struct ReJitInfo,       PTR_ReJitInfo,      VMPTR_ReJitInfo);
  DEFINE_VMPTR(struct SharedReJitInfo, PTR_SharedReJitInfo, VMPTR_SharedReJitInfo);
  DEFINE_VMPTR(class NativeCodeVersionNode, PTR_NativeCodeVersionNode, VMPTR_NativeCodeVersionNode);
  DEFINE_VMPTR(class ILCodeVersionNode, PTR_ILCodeVersionNode, VMPTR_ILCodeVersionNode);
  
  typedef CORDB_ADDRESS GENERICS_TYPE_TOKEN;
  
  
  //-----------------------------------------------------------------------------
  // We pass some fixed size strings in the IPC block.
  // Helper class to wrap the buffer and protect against buffer overflows.
  // This should be binary compatible w/ a wchar[] array.
  //-----------------------------------------------------------------------------
  
  template <int nMaxLengthIncludingNull>
  class MSLAYOUT EmbeddedIPCString
  {
  public:
      // Set, caller responsibility that wcslen(pData) < nMaxLengthIncludingNull
      void SetString(const WCHAR * pData)
      {
          // If the string doesn't fit into the buffer, that's an issue (and so this is a real
          // assert, not just a simplifying assumption). To fix it, either:
          // - make the buffer larger
          // - don't pass the string as an embedded string in the IPC block.
          // This will truncate (rather than AV on the RS).
          int ret;
          ret = SafeCopy(pData);
  
          // See comment above - caller should guarantee that buffer is large enough.
          _ASSERTE(ret != STRUNCATE);
      }
  
      // Set a string from a substring. This will truncate if necessary.
      void SetStringTruncate(const WCHAR * pData)
      {
          // ignore return value because truncation is ok.
          SafeCopy(pData);
      }
  
      const WCHAR * GetString()
      {
          // For a null-termination just in case an issue in the debuggee process
          // yields a malformed string.
          m_data[nMaxLengthIncludingNull - 1] = W('\0');
          return &m_data[0];
      }
      int GetMaxSize() const { return nMaxLengthIncludingNull; }
  
  private:
      int SafeCopy(const WCHAR * pData)
      {
          return wcsncpy_s(
              m_data, nMaxLengthIncludingNull,
              pData, _TRUNCATE);
      }
      WCHAR m_data[nMaxLengthIncludingNull];
  };
  
  //
  // Types of events that can be sent between the Runtime Controller and
  // the Debugger Interface. Some of these events are one way only, while
  // others go both ways. The grouping of the event numbers is an attempt
  // to show this distinction and perhaps even allow generic operations
  // based on the type of the event.
  //
  enum DebuggerIPCEventType
  {
  #define IPC_EVENT_TYPE0(type, val)  type = val,
  #define IPC_EVENT_TYPE1(type, val)  type = val,
  #define IPC_EVENT_TYPE2(type, val)  type = val,
  #include "dbgipceventtypes.h"
  #undef IPC_EVENT_TYPE2
  #undef IPC_EVENT_TYPE1
  #undef IPC_EVENT_TYPE0
  };
  
  #ifdef _DEBUG
  
  // This is a static debugging structure to help breaking at the right place.
  // Debug only. This is to track the number of events that have been happened so far.
  // User can choose to set break point base on the number of events.
  // Variables are named as the event name with prefix m_iDebugCount. For example
  // m_iDebugCount_DB_IPCE_BREAKPOINT if for event DB_IPCE_BREAKPOINT.
  struct MSLAYOUT DebugEventCounter
  {
  // we don't need the event type 0
  #define IPC_EVENT_TYPE0(type, val)
  #define IPC_EVENT_TYPE1(type, val)  int m_iDebugCount_##type;
  #define IPC_EVENT_TYPE2(type, val)  int m_iDebugCount_##type;
  #include "dbgipceventtypes.h"
  #undef IPC_EVENT_TYPE2
  #undef IPC_EVENT_TYPE1
  #undef IPC_EVENT_TYPE0
  };
  #endif // _DEBUG
  
  
  #if !defined(DACCESS_COMPILE)
  
  struct MSLAYOUT IPCEventTypeNameMapping
      {
              DebuggerIPCEventType    eventType;
              const char *            eventName;
  };
  
  extern const IPCEventTypeNameMapping DECLSPEC_SELECTANY DbgIPCEventTypeNames[] =
  {
      #define IPC_EVENT_TYPE0(type, val)  { type, #type },
      #define IPC_EVENT_TYPE1(type, val)  { type, #type },
      #define IPC_EVENT_TYPE2(type, val)  { type, #type },
      #include "dbgipceventtypes.h"
      #undef IPC_EVENT_TYPE2
      #undef IPC_EVENT_TYPE1
      #undef IPC_EVENT_TYPE0
      { DB_IPCE_INVALID_EVENT, "DB_IPCE_Error" }
  };
  
  const size_t nameCount = sizeof(DbgIPCEventTypeNames) / sizeof(DbgIPCEventTypeNames[0]);
  
  
  struct MSLAYOUT IPCENames // We use a class/struct so that the function can remain in a shared header file
  {
      static DebuggerIPCEventType GetEventType(__in_z char * strEventType)
      {
          // pass in the string of event name and find the matching enum value
          // This is a linear search which is pretty slow. However, this is only used
          // at startup time when debug assert is turn on and with registry key set. So it is not that bad.
          //
          for (size_t i = 0; i < nameCount; i++)
          {
              if (_stricmp(DbgIPCEventTypeNames[i].eventName, strEventType) == 0)
                  return DbgIPCEventTypeNames[i].eventType;
          }
          return DB_IPCE_INVALID_EVENT;
      }
      static const char * GetName(DebuggerIPCEventType eventType)
      {
  
          enum DbgIPCEventTypeNum
          {
          #define IPC_EVENT_TYPE0(type, val)  type##_Num,
          #define IPC_EVENT_TYPE1(type, val)  type##_Num,
          #define IPC_EVENT_TYPE2(type, val)  type##_Num,
          #include "dbgipceventtypes.h"
          #undef IPC_EVENT_TYPE2
          #undef IPC_EVENT_TYPE1
          #undef IPC_EVENT_TYPE0
          };
  
          unsigned int i, lim;
  
          if (eventType < DB_IPCE_DEBUGGER_FIRST)
          {
              i = DB_IPCE_RUNTIME_FIRST_Num + 1;
              lim = DB_IPCE_DEBUGGER_FIRST_Num;
          }
          else
          {
              i = DB_IPCE_DEBUGGER_FIRST_Num + 1;
              lim = nameCount;
          }
  
          for (/**/; i < lim; i++)
          {
              if (DbgIPCEventTypeNames[i].eventType == eventType)
                  return DbgIPCEventTypeNames[i].eventName;
          }
  
          return DbgIPCEventTypeNames[nameCount - 1].eventName;
      }
  };
  
  #endif // !DACCESS_COMPILE
  
  //
  // NOTE:  CPU-specific values below!
  //
  // DebuggerREGDISPLAY is very similar to the EE REGDISPLAY structure. It holds
  // register values that can be saved over calls for each frame in a stack
  // trace.
  //
  // DebuggerIPCE_FloatCount is the number of doubles in the processor's
  // floating point stack.
  //
  // <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
  // address of each register, too, to support using enregistered variables on non-leaf frames as args to a func eval. Its
  // very, very possible that we would rework the entire code base to just use the register's address instead of passing
  // both, but its way, way too late in V1 to undertake that, so I'm just using these addresses to suppport our one func
  // eval case. Clearly, this needs to be cleaned up post V1.
  //
  // -- Fri Feb 09 11:21:24 2001</TODO>
  //
  
  struct MSLAYOUT DebuggerREGDISPLAY
  {
  #if defined(DBG_TARGET_X86)
      #define DebuggerIPCE_FloatCount 8
  
      SIZE_T  Edi;
      void   *pEdi;
      SIZE_T  Esi;
      void   *pEsi;
      SIZE_T  Ebx;
      void   *pEbx;
      SIZE_T  Edx;
      void   *pEdx;
      SIZE_T  Ecx;
      void   *pEcx;
      SIZE_T  Eax;
      void   *pEax;
      SIZE_T  FP;
      void   *pFP;
      SIZE_T  SP;
      SIZE_T  PC;
  
  #elif defined(DBG_TARGET_AMD64)
      #define DebuggerIPCE_FloatCount 16
  
      SIZE_T  Rax;
      void   *pRax;
      SIZE_T  Rcx;
      void   *pRcx;
      SIZE_T  Rdx;
      void   *pRdx;
      SIZE_T  Rbx;
      void   *pRbx;
      SIZE_T  Rbp;
      void   *pRbp;
      SIZE_T  Rsi;
      void   *pRsi;
      SIZE_T  Rdi;
      void   *pRdi;
  
      SIZE_T  R8;
      void   *pR8;
      SIZE_T  R9;
      void   *pR9;
      SIZE_T  R10;
      void   *pR10;
      SIZE_T  R11;
      void   *pR11;
      SIZE_T  R12;
      void   *pR12;
      SIZE_T  R13;
      void   *pR13;
      SIZE_T  R14;
      void   *pR14;
      SIZE_T  R15;
      void   *pR15;
  
      SIZE_T  SP;
      SIZE_T  PC;
  #elif defined(DBG_TARGET_ARM)
      #define DebuggerIPCE_FloatCount 32
  
      SIZE_T  R0;
      void   *pR0;
      SIZE_T  R1;
      void   *pR1;
      SIZE_T  R2;
      void   *pR2;
      SIZE_T  R3;
      void   *pR3;
      SIZE_T  R4;
      void   *pR4;
      SIZE_T  R5;
      void   *pR5;
      SIZE_T  R6;
      void   *pR6;
      SIZE_T  R7;
      void   *pR7;
      SIZE_T  R8;
      void   *pR8;
      SIZE_T  R9;
      void   *pR9;
      SIZE_T  R10;
      void   *pR10;
      SIZE_T  R11;
      void   *pR11;
      SIZE_T  R12;
      void   *pR12;
      SIZE_T  SP;
      void   *pSP;
      SIZE_T  LR;
      void   *pLR;
      SIZE_T  PC;
      void   *pPC;
  #elif defined(DBG_TARGET_ARM64)
      #define DebuggerIPCE_FloatCount 32
  
      SIZE_T  X[29];
      SIZE_T  SP;
      SIZE_T  FP;
      SIZE_T  LR;
      SIZE_T  PC;
  #else
      #define DebuggerIPCE_FloatCount 1
  
      SIZE_T PC;
      SIZE_T FP;
      SIZE_T SP;
      void   *pFP;
  #endif
  };
  
  inline LPVOID GetSPAddress(const DebuggerREGDISPLAY * display)
  {
      return (LPVOID)&display->SP;
  }
  
  #if !defined(DBG_TARGET_AMD64) && !defined(DBG_TARGET_ARM)
  inline LPVOID GetFPAddress(const DebuggerREGDISPLAY * display)
  {
      return (LPVOID)&display->FP;
  }
  #endif // !DBG_TARGET_AMD64
  
  
  class MSLAYOUT FramePointer
  {
  friend bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2);
  friend bool IsCloserToRoot(FramePointer fp1, FramePointer fp2);
  friend bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2);
  friend bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2);
  
  public:
  
      static FramePointer MakeFramePointer(LPVOID sp)
      {
          LIMITED_METHOD_DAC_CONTRACT;
          FramePointer fp;
          fp.m_sp = sp;
          return fp;
      }
  
      static FramePointer MakeFramePointer(UINT_PTR sp)
      {
          SUPPORTS_DAC;
          return MakeFramePointer((LPVOID)sp);
      }
  
      inline bool operator==(FramePointer fp)
      {
          return (m_sp == fp.m_sp);
      }
  
      inline bool operator!=(FramePointer fp)
      {
          return !(*this == fp);
      }
  
      // This is needed because on the RS, the m_id values of CordbFrame and
      // CordbChain are really FramePointers.
      LPVOID GetSPValue() const
      {
          return m_sp;
      }
  
  
  private:
      // Declare some private constructors which signatures matching common usage of FramePointer
      // to prevent people from accidentally assigning a pointer to a FramePointer().
      FramePointer &operator=(LPVOID sp);
      FramePointer &operator=(BYTE* sp);
      FramePointer &operator=(const BYTE* sp);
  
      LPVOID m_sp;
  };
  
  // For non-IA64 platforms, we use stack pointers as frame pointers.
  // (Stack grows towards smaller address.)
  #define LEAF_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)NULL)
  #define ROOT_MOST_FRAME FramePointer::MakeFramePointer((LPVOID)-1)
  
  static_assert_no_msg(sizeof(FramePointer) == sizeof(void*));
  
  
  inline bool IsCloserToLeaf(FramePointer fp1, FramePointer fp2)
  {
      return (fp1.m_sp < fp2.m_sp);
  }
  
  inline bool IsCloserToRoot(FramePointer fp1, FramePointer fp2)
  {
      return (fp1.m_sp > fp2.m_sp);
  }
  
  inline bool IsEqualOrCloserToLeaf(FramePointer fp1, FramePointer fp2)
  {
      return !IsCloserToRoot(fp1, fp2);
  }
  
  inline bool IsEqualOrCloserToRoot(FramePointer fp1, FramePointer fp2)
  {
      return !IsCloserToLeaf(fp1, fp2);
  }
  
  
  // struct DebuggerIPCE_FuncData:   DebuggerIPCE_FuncData holds data
  // to describe a given function, its
  // class, and a little bit about the code for the function. This is used
  // in the stack trace result data to pass function information back that
  // may be needed. Its also used when getting data about a specific function.
  //
  // void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is
  //          the address of the real start address of the native code.
  //          This field will be NULL only if the method hasn't been JITted
  //          yet (and thus no code is available).  Otherwise, it will be
  //          the adress of a CORDB_ADDRESS in the remote memory.  This
  //          CORDB_ADDRESS may be NULL, in which case the code is unavailable
  //          has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE)
  //
  // SIZE_T nVersion: The version of the code that this instance of the
  //          function is using.
  struct MSLAYOUT DebuggerIPCE_FuncData
  {
      mdMethodDef funcMetadataToken;
      VMPTR_DomainFile vmDomainFile;
  
      mdTypeDef   classMetadataToken;
  
      void*       ilStartAddress;
      SIZE_T      ilSize;
  
      SIZE_T      currentEnCVersion;
  
      mdSignature  localVarSigToken;
  
  
  };
  
  // struct DebuggerIPCE_JITFuncData:   DebuggerIPCE_JITFuncData holds
  // a little bit about the JITted code for the function.
  //
  // void* nativeStartAddressPtr: Ptr to CORDB_ADDRESS, which is
  //          the address of the real start address of the native code.
  //          This field will be NULL only if the method hasn't been JITted
  //          yet (and thus no code is available).  Otherwise, it will be
  //          the address of a CORDB_ADDRESS in the remote memory.  This
  //          CORDB_ADDRESS may be NULL, in which case the code is unavailable
  //          or has been pitched (return CORDBG_E_CODE_NOT_AVAILABLE)
  //
  // SIZE_T nativeSize: Size of the native code.
  //
  // SIZE_T nativeOffset: Offset from the beginning of the function,
  //          in bytes.  This may be non-zero even when nativeStartAddressPtr
  //          is NULL
  // void * nativeCodeJITInfoToken: An opaque value to hand back to the left
  //          side when fetching the JITInfo for the native code, i.e. the
  //          IL->native maps for the variables.  This may be NULL if no JITInfo is available.
  // void * nativeCodeMethodDescToken: An opaque value to hand back to the left
  //          side when fetching the code.  In addition this token can act as the
  //          unique identity for the native code in the case where there are
  //          multiple blobs of native code per IL method (i.e. if the method is
  //          generic code of some kind)
  // BOOL isInstantiatedGeneric: Indicates if the method is
  //          generic code of some kind.
  // BOOL jsutAfterILThrow: indicates that code just threw a software exception and
  //          nativeOffset points to an instruction just after [call IL_Throw].
  //          This is being used to figure out a real offset of the exception origin.  
  //          By subtracting STACKWALK_CONTROLPC_ADJUST_OFFSET from nativeOffset you can get 
  //          an address somewhere inside [call IL_Throw] instruction.
  // void *ilToNativeMapAddr etc.: If nativeCodeJITInfoToken is not NULL then these
  //          specify the table giving the mapping of IPs.
  struct MSLAYOUT DebuggerIPCE_JITFuncData
  {
      TADDR       nativeStartAddressPtr;
      SIZE_T      nativeHotSize;
  
      // If we have a cold region, need its size & the pointer to where starts.
      TADDR       nativeStartAddressColdPtr;
      SIZE_T      nativeColdSize;
  
  
      SIZE_T      nativeOffset;
      LSPTR_DJI   nativeCodeJITInfoToken;
      VMPTR_MethodDesc vmNativeCodeMethodDescToken;
  
  #ifdef WIN64EXCEPTIONS
      BOOL         fIsFilterFrame;
      SIZE_T       parentNativeOffset;
      FramePointer fpParentOrSelf;
  #endif // WIN64EXCEPTIONS
  
      // indicates if the MethodDesc is a generic function or a method inside a generic class (or
      // both!).
      BOOL         isInstantiatedGeneric;
  
      // this is the version of the jitted code
      SIZE_T       enCVersion;
  
      BOOL         jsutAfterILThrow;
  };
  
  //
  // DebuggerIPCE_STRData holds data for each stack frame or chain. This data is passed
  // from the RC to the DI during a stack walk.
  //
  #if defined(_MSC_VER)
  #pragma warning( push )
  #pragma warning( disable:4324 ) // the compiler pads a structure to comply with alignment requirements
  #endif                          // ARM context structures have a 16-byte alignment requirement
  struct MSLAYOUT DebuggerIPCE_STRData
  {
      FramePointer            fp;
      // @dbgtodo  stackwalker/shim- Ideally we should be able to get rid of the DebuggerREGDISPLAY and just use the CONTEXT.
      DT_CONTEXT              ctx;
      DebuggerREGDISPLAY      rd;
      bool                    quicklyUnwound;
  
      VMPTR_AppDomain         vmCurrentAppDomainToken;
  
  
      enum EType
      {
          cMethodFrame = 0,
          cChain,
          cStubFrame,
          cRuntimeNativeFrame
      } eType;
  
      union MSLAYOUT
      {
          // Data for a chain
          struct MSLAYOUT
          {
              CorDebugChainReason chainReason;
              bool                managed;
          } u;
  
          // Data for a Method
          struct MSLAYOUT
          {
              struct DebuggerIPCE_FuncData funcData;
              struct DebuggerIPCE_JITFuncData jitFuncData;
              SIZE_T                       ILOffset;
              CorDebugMappingResult        mapping;
  
              bool        fVarArgs;
  
              // Indicates whether the managed method has any metadata.
              // Some dynamic methods such as IL stubs and LCG methods don't have any metadata.
              // This is used only by the V3 stackwalker, not the V2 one, because we only 
              // expose dynamic methods as real stack frames in V3.
              bool        fNoMetadata;
  
              TADDR       taAmbientESP;
  
              GENERICS_TYPE_TOKEN exactGenericArgsToken;
              DWORD               dwExactGenericArgsTokenIndex;
  
          } v;
  
          // Data for an Stub Frame.
          struct MSLAYOUT
          {
              mdMethodDef funcMetadataToken;
              VMPTR_DomainFile vmDomainFile;
              VMPTR_MethodDesc vmMethodDesc;
              CorDebugInternalFrameType frameType;
          } stubFrame;
  
      };
  };
  #if defined(_MSC_VER)
  #pragma warning( pop )
  #endif
  
  //
  // DebuggerIPCE_BasicTypeData and DebuggerIPCE_ExpandedTypeData
  // hold data for each type sent across the
  // boundary, whether it be a constructed type List<String> or a non-constructed
  // type such as String, Foo or Object.
  //
  // Logically speaking DebuggerIPCE_BasicTypeData might just be "typeHandle", as
  // we could then send further events to ask what the elementtype, typeToken and moduleToken
  // are for the type handle.  But as
  // nearly all types are non-generic we send across even the basic type information in
  // the slightly expanded form shown below, sending the element type and the
  // tokens with the type handle itself. The fields debuggerModuleToken, metadataToken and typeHandle
  // are only used as follows:
  //                                   elementType    debuggerModuleToken metadataToken      typeHandle
  //     E_T_INT8    :                  E_T_INT8         No                     No              No
  //     Boxed E_T_INT8:                E_T_CLASS        No                     No              No
  //     E_T_CLASS, non-generic class:  E_T_CLASS       Yes                    Yes              No
  //     E_T_VALUETYPE, non-generic:    E_T_VALUETYPE   Yes                    Yes              No
  //     E_T_CLASS,     generic class:  E_T_CLASS       Yes                    Yes             Yes
  //     E_T_VALUETYPE, generic class:  E_T_VALUETYPE   Yes                    Yes             Yes
  //     E_T_BYREF                   :  E_T_BYREF        No                     No             Yes
  //     E_T_PTR                     :  E_T_PTR          No                     No             Yes
  //     E_T_ARRAY etc.              :  E_T_ARRAY        No                     No             Yes
  //     E_T_FNPTR etc.              :  E_T_FNPTR        No                     No             Yes
  // This allows us to always set "typeHandle" to NULL except when dealing with highly nested
  // types or function-pointer types (the latter are too complexe to transfer over in one hit).
  //
  
  struct MSLAYOUT DebuggerIPCE_BasicTypeData
  {
      CorElementType  elementType;
      mdTypeDef       metadataToken;
      VMPTR_Module     vmModule;
      VMPTR_DomainFile vmDomainFile;
      VMPTR_TypeHandle vmTypeHandle;
  };
  
  // DebuggerIPCE_ExpandedTypeData contains more information showing further
  // details for array types, byref types etc.
  // Whenever you fetch type information from the left-side
  // you get back one of these.  These in turn contain further
  // DebuggerIPCE_BasicTypeData's and typeHandles which you can
  // then query to get further information about the type parameters.
  // This copes with the nested cases, e.g. jagged arrays,
  // String ****, &(String*), Pair<String,Pair<String>>
  // and so on.
  //
  // So this type information is not "fully expanded", it's just a little
  // more detail then DebuggerIPCE_BasicTypeData.  For type
  // instantiatons (e.g. List<int>) and
  // function pointer types you will need to make further requests for
  // information about the type parameters.
  // For array types there is always only one type parameter so
  // we include that as part of the expanded data.
  //
  //
  struct MSLAYOUT DebuggerIPCE_ExpandedTypeData
  {
      CorElementType  elementType; // Note this is _never_ E_T_VAR, E_T_WITH or E_T_MVAR
      union MSLAYOUT
      {
          // used for E_T_CLASS and E_T_VALUECLASS, E_T_PTR, E_T_BYREF etc.
          // For non-constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be NULL
          // For constructed E_T_CLASS or E_T_VALUECLASS the tokens will be set and the typeHandle will be non-NULL
          // For E_T_PTR etc. the tokens will be NULL and the typeHandle will be non-NULL.
          struct MSLAYOUT
           {
              mdTypeDef       metadataToken;
              VMPTR_Module vmModule;
              VMPTR_DomainFile vmDomainFile;
              VMPTR_TypeHandle typeHandle; // if non-null then further fetches will be needed to get type arguments
          } ClassTypeData;
  
          // used for E_T_PTR, E_T_BYREF etc.
          struct MSLAYOUT
           {
              DebuggerIPCE_BasicTypeData unaryTypeArg;  // used only when sending back to debugger
          } UnaryTypeData;
  
  
          // used for E_T_ARRAY etc.
          struct MSLAYOUT
          {
            DebuggerIPCE_BasicTypeData arrayTypeArg; // used only when sending back to debugger
              DWORD           arrayRank;
          } ArrayTypeData;
  
          // used for E_T_FNPTR
          struct MSLAYOUT
           {
              VMPTR_TypeHandle typeHandle; // if non-null then further fetches needed to get type arguments
          } NaryTypeData;
  
      };
  };
  
  // DebuggerIPCE_TypeArgData is used when sending type arguments
  // across to a funceval.  It contains the DebuggerIPCE_ExpandedTypeData describing the
  // essence of the type, but the typeHandle and other
  // BasicTypeData fields should be zero and will be ignored.
  // The DebuggerIPCE_ExpandedTypeData is then followed
  // by the required number of type arguments, each of which
  // will be a further DebuggerIPCE_TypeArgData record in the stream of
  // flattened type argument data.
  struct MSLAYOUT DebuggerIPCE_TypeArgData
  {
      DebuggerIPCE_ExpandedTypeData  data;
      unsigned int                   numTypeArgs; // number of immediate children on the type tree
  };
  
  
  //
  // DebuggerIPCE_ObjectData holds the results of a
  // GetAndSendObjectInfo, i.e., all the info about an object that the
  // Right Side would need to access it. (This include array, string,
  // and nstruct info.)
  //
  struct MSLAYOUT DebuggerIPCE_ObjectData
  {
      void           *objRef;
      bool            objRefBad;
      SIZE_T          objSize;
  
      // Offset from the beginning of the object to the beginning of the first field
      SIZE_T          objOffsetToVars;
  
      // The type of the object....
      struct DebuggerIPCE_ExpandedTypeData objTypeData;
  
      union MSLAYOUT
      {
          struct MSLAYOUT
          {
              SIZE_T          length;
              SIZE_T          offsetToStringBase;
          } stringInfo;
  
          struct MSLAYOUT
          {
              SIZE_T          rank;
              SIZE_T          offsetToArrayBase;
              SIZE_T          offsetToLowerBounds; // 0 if not present
              SIZE_T          offsetToUpperBounds; // 0 if not present
              SIZE_T          componentCount;
              SIZE_T          elementSize;
          } arrayInfo;
  
          struct MSLAYOUT
          {
              struct DebuggerIPCE_BasicTypeData typedByrefType; // the type of the thing contained in a typedByref...
          } typedByrefInfo;
      };
  };
  
  //
  // Remote enregistered info used by CordbValues and for passing
  // variable homes between the left and right sides during a func eval.
  //
  
  enum RemoteAddressKind
  {
      RAK_NONE = 0,
      RAK_REG,
      RAK_REGREG,
      RAK_REGMEM,
      RAK_MEMREG,
      RAK_FLOAT,
      RAK_END
  };
  
  const CORDB_ADDRESS kLeafFrameRegAddr = 0;
  const CORDB_ADDRESS kNonLeafFrameRegAddr = (CORDB_ADDRESS)(-1);
  
  struct MSLAYOUT RemoteAddress
  {
      RemoteAddressKind    kind;
      void                *frame;
  
      CorDebugRegister     reg1;
      void                *reg1Addr;
      SIZE_T               reg1Value;         // this is the actual value of the register
  
      union MSLAYOUT
      {
          struct MSLAYOUT
          {
              CorDebugRegister  reg2;
              void             *reg2Addr;
              SIZE_T            reg2Value;    // this is the actual value of the register
          } u;
  
          CORDB_ADDRESS    addr;
          DWORD            floatIndex;
      };
  };
  
  //
  // DebuggerIPCE_FuncEvalType specifies the type of a function
  // evaluation that will occur.
  //
  enum DebuggerIPCE_FuncEvalType
  {
      DB_IPCE_FET_NORMAL,
      DB_IPCE_FET_NEW_OBJECT,
      DB_IPCE_FET_NEW_OBJECT_NC,
      DB_IPCE_FET_NEW_STRING,
      DB_IPCE_FET_NEW_ARRAY,
      DB_IPCE_FET_RE_ABORT
  };
  
  
  enum NameChangeType
  {
      APP_DOMAIN_NAME_CHANGE,
      THREAD_NAME_CHANGE
  };
  
  //
  // DebuggerIPCE_FuncEvalArgData holds data for each argument to a
  // function evaluation.
  //
  struct MSLAYOUT DebuggerIPCE_FuncEvalArgData
  {
      RemoteAddress     argHome;  // enregistered variable home
      void             *argAddr;  // address if not enregistered
      CorElementType    argElementType;
      unsigned int      fullArgTypeNodeCount; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types)
      void             *fullArgType; // Pointer to LS (DebuggerIPCE_TypeArgData *) buffer holding full description of the argument type (if needed - only needed for struct types)
      BYTE              argLiteralData[8]; // copy of generic value data
      bool              argIsLiteral; // true if value is in argLiteralData
      bool              argIsHandleValue; // true if argAddr is OBJECTHANDLE
  };
  
  
  //
  // DebuggerIPCE_FuncEvalInfo holds info necessary to setup a func eval
  // operation.
  //
  struct MSLAYOUT DebuggerIPCE_FuncEvalInfo
  {
      VMPTR_Thread               vmThreadToken;
      DebuggerIPCE_FuncEvalType  funcEvalType;
      mdMethodDef                funcMetadataToken;
      mdTypeDef                  funcClassMetadataToken;
      VMPTR_DomainFile           vmDomainFile;
      RSPTR_CORDBEVAL            funcEvalKey;
      bool                       evalDuringException;
  
      unsigned int               argCount;
      unsigned int               genericArgsCount;
      unsigned int               genericArgsNodeCount;
  
      SIZE_T                     stringSize;
  
      SIZE_T                     arrayRank;
  };
  
  
  //
  // Used in DebuggerIPCFirstChanceData. This tells the LS what action to take within the hijack
  //
  enum HijackAction
  {
      HIJACK_ACTION_EXIT_UNHANDLED,
      HIJACK_ACTION_EXIT_HANDLED,
      HIJACK_ACTION_WAIT
  };
  
  //
  // DebuggerIPCFirstChanceData holds info communicated from the LS to the RS when signaling that an exception does not
  // belong to the runtime from a first chance hijack. This is used when Win32 debugging only.
  //
  struct MSLAYOUT DebuggerIPCFirstChanceData
  {
      LSPTR_CONTEXT     pLeftSideContext;
      HijackAction      action;
      UINT              debugCounter;
  };
  
  //
  // DebuggerIPCSecondChanceData holds info communicated from the RS
  // to the LS when setting up a second chance exception hijack. This is
  // used when Win32 debugging only.
  //
  struct MSLAYOUT DebuggerIPCSecondChanceData
  {
      DT_CONTEXT       threadContext;
  };
  
  
  
  //-----------------------------------------------------------------------------
  // This struct holds pointer from the LS and needs to copy to
  // the RS. We have to free the memory on the RS.
  // The transfer function is called when the RS first reads the event. At this point, 
  // the LS is stopped while sending the event. Thus the LS pointers only need to be
  // valid while the LS is in SendIPCEvent.
  //
  // Since this data is in an IPC/Marshallable block, it can't have any Ctors (holders)
  // in it. 
  //-----------------------------------------------------------------------------
  struct MSLAYOUT Ls_Rs_BaseBuffer
  {
  #ifdef RIGHT_SIDE_COMPILE
  protected:
      // copy data can happen on both LS and RS. In LS case,
      // ReadProcessMemory is really reading from its own process memory.
      //
      void CopyLSDataToRSWorker(ICorDebugDataTarget * pTargethProcess);
      
      // retrieve the RS data and own it
      BYTE *TransferRSDataWorker()
      {
          BYTE *pbRS = m_pbRS;
          m_pbRS = NULL;
          return pbRS;
      }
  public:
      
  
      void CleanUp()
      {
          if (m_pbRS != NULL)
          {
              delete [] m_pbRS;
              m_pbRS = NULL;
          }
      }
  #else
  public:
      // Only LS can call this API
      void SetLsData(BYTE *pbLS, DWORD cbSize)
      {
          m_pbRS = NULL;
          m_pbLS = pbLS;
          m_cbSize = cbSize;
      }
  #endif // RIGHT_SIDE_COMPILE
  
  public:
      // Common APIs.
      DWORD  GetSize() { return m_cbSize; }
  
  
  
  protected:
      // Size of data in bytes 
      DWORD  m_cbSize;
  
      // If this is non-null, pointer into LS for buffer.
      // LS can free this after the debug event is continued.
      BYTE  *m_pbLS; // @dbgtodo  cross-plat- for cross-platform purposes, this should be a TADDR
  
      // If this is non-null, pointer into RS for buffer. RS must then free this. 
      // This buffer was copied from the LS (via CopyLSDataToRSWorker).
      BYTE  *m_pbRS;
  };
  
  //-----------------------------------------------------------------------------
  // Byte wrapper around the buffer.
  //-----------------------------------------------------------------------------
  struct MSLAYOUT Ls_Rs_ByteBuffer : public Ls_Rs_BaseBuffer
  {
  #ifdef RIGHT_SIDE_COMPILE
      BYTE *GetRSPointer() 
      { 
          return m_pbRS;
      }
  
      void CopyLSDataToRS(ICorDebugDataTarget * pTarget);
      BYTE *TransferRSData()
      {
          return TransferRSDataWorker();
      }
  #endif    
  };
  
  //-----------------------------------------------------------------------------
  // Wrapper around a Ls_rS_Buffer to get it as a string.
  // This can also do some sanity checking.
  //-----------------------------------------------------------------------------
  struct MSLAYOUT Ls_Rs_StringBuffer : public Ls_Rs_BaseBuffer
  {
  #ifdef RIGHT_SIDE_COMPILE
      const WCHAR * GetString()
      {
          return reinterpret_cast<const WCHAR*> (m_pbRS);
      }
  
      // Copy over the string.
      void CopyLSDataToRS(ICorDebugDataTarget * pTarget);
  
      // Caller will pick up ownership.
      // Since caller will delete this data, we can't give back a constant pointer.
      WCHAR * TransferStringData()
      {
          return reinterpret_cast<WCHAR*> (TransferRSDataWorker());
      }
  #endif  
  };
  
  
  // Data for an Managed Debug Assistant Probe (MDA).
  struct MSLAYOUT DebuggerMDANotification
  {
      Ls_Rs_StringBuffer szName;
      Ls_Rs_StringBuffer szDescription;
      Ls_Rs_StringBuffer szXml;
      DWORD        dwOSThreadId;
      CorDebugMDAFlags flags;
  };
  
  
  // The only remaining problem is that register number mappings are different for each platform. It turns out
  // that the debugger only uses REGNUM_SP and REGNUM_AMBIENT_SP though, so we can just virtualize these two for
  // the target platform.
  // Keep this is sync with the definitions in inc/corinfo.h.
  #if defined(DBG_TARGET_X86)
  #define DBG_TARGET_REGNUM_SP 4
  #define DBG_TARGET_REGNUM_AMBIENT_SP 9
  #ifdef _TARGET_X86_
  static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
  static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
  #endif // _TARGET_X86_
  #elif defined(DBG_TARGET_AMD64)
  #define DBG_TARGET_REGNUM_SP 4
  #define DBG_TARGET_REGNUM_AMBIENT_SP 17
  #ifdef _TARGET_AMD64_
  static_assert_no_msg(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
  static_assert_no_msg(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
  #endif // _TARGET_AMD64_
  #elif defined(DBG_TARGET_ARM)
  #define DBG_TARGET_REGNUM_SP 13
  #define DBG_TARGET_REGNUM_AMBIENT_SP 17
  #ifdef _TARGET_ARM_
  C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
  C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
  #endif // _TARGET_ARM_
  #elif defined(DBG_TARGET_ARM64)
  #define DBG_TARGET_REGNUM_SP 31
  #define DBG_TARGET_REGNUM_AMBIENT_SP 34
  #ifdef _TARGET_ARM64_
  C_ASSERT(DBG_TARGET_REGNUM_SP == ICorDebugInfo::REGNUM_SP);
  C_ASSERT(DBG_TARGET_REGNUM_AMBIENT_SP == ICorDebugInfo::REGNUM_AMBIENT_SP);
  #endif // _TARGET_ARM64_
  #else
  #error Target registers are not defined for this platform
  #endif
  
  
  //
  // Event structure that is passed between the Runtime Controller and the
  // Debugger Interface. Some types of events are a fixed size and have
  // entries in the main union, while others are variable length and have
  // more specialized data structures that are attached to the end of this
  // structure.
  //
  struct MSLAYOUT DebuggerIPCEvent
  {
      DebuggerIPCEvent*       next;
      DebuggerIPCEventType    type;
      DWORD             processId;
      DWORD             threadId;
      VMPTR_AppDomain   vmAppDomain;
      VMPTR_Thread      vmThread;
  
      HRESULT           hr;
      bool              replyRequired;
      bool              asyncSend;
  
      union MSLAYOUT
      {
          struct MSLAYOUT
          {
              // Pointer to a BOOL in the target.
              CORDB_ADDRESS pfBeingDebugged;
          } LeftSideStartupData;
  
          struct MSLAYOUT
          {
              // Module whos metadata is being updated
              // This tells the RS that the metadata for that module has become invalid.
              VMPTR_DomainFile vmDomainFile;
            
          } MetadataUpdateData;
  
          struct MSLAYOUT
          {
              // Handle to CLR's internal appdomain object.
              VMPTR_AppDomain vmAppDomain;
          } AppDomainData;
  
          struct MSLAYOUT
          {
              VMPTR_DomainAssembly vmDomainAssembly;
          } AssemblyData;
  
  #ifdef TEST_DATA_CONSISTENCY
          // information necessary for testing whether the LS holds a lock on data
          // the RS needs to inspect. See code:DataTest::TestDataSafety and 
          // code:IDacDbiInterface::TestCrst for more information
          struct MSLAYOUT
          {
              // the lock to be tested
              VMPTR_Crst vmCrst;
              // indicates whether the LS holds the lock 
              bool       fOkToTake;
          } TestCrstData;
  
          // information necessary for testing whether the LS holds a lock on data
          // the RS needs to inspect. See code:DataTest::TestDataSafety and 
          // code:IDacDbiInterface::TestCrst for more information
          struct MSLAYOUT
          {
              // the lock to be tested
              VMPTR_SimpleRWLock vmRWLock;
              // indicates whether the LS holds the lock  
              bool               fOkToTake;
          } TestRWLockData;
  #endif // TEST_DATA_CONSISTENCY
  
          // Debug event that a module has been loaded
          struct MSLAYOUT
          {
              // Module that was just loaded.
              VMPTR_DomainFile vmDomainFile;
          }LoadModuleData;
  
          
          struct MSLAYOUT
          {
              VMPTR_DomainFile vmDomainFile;
              LSPTR_ASSEMBLY debuggerAssemblyToken;
          } UnloadModuleData;
  
          
          // The given module's pdb has been updated. 
          // Queury PDB from OOP
          struct MSLAYOUT
          {   
              VMPTR_DomainFile vmDomainFile;
          } UpdateModuleSymsData;
  
          DebuggerMDANotification MDANotification;
  
          struct MSLAYOUT
          {
              LSPTR_BREAKPOINT breakpointToken;
              mdMethodDef  funcMetadataToken;
              VMPTR_DomainFile vmDomainFile;
              bool         isIL;
              SIZE_T       offset;
              SIZE_T       encVersion;
              LSPTR_METHODDESC  nativeCodeMethodDescToken; // points to the MethodDesc if !isIL
          } BreakpointData;
  
          struct MSLAYOUT
          {
              LSPTR_BREAKPOINT breakpointToken;
          } BreakpointSetErrorData;
  
          struct MSLAYOUT
          {
  #ifdef FEATURE_DATABREAKPOINT
              CONTEXT context;
  #else
              int dummy;
  #endif
          } DataBreakpointData;
  
          struct MSLAYOUT
          {
              LSPTR_STEPPER        stepperToken;
              VMPTR_Thread         vmThreadToken;
              FramePointer         frameToken;
              bool                 stepIn;
              bool                 rangeIL;
              bool                 IsJMCStop;
              unsigned int         totalRangeCount;
              CorDebugStepReason   reason;
              CorDebugUnmappedStop rgfMappingStop;
              CorDebugIntercept    rgfInterceptStop;
              unsigned int         rangeCount;
              COR_DEBUG_STEP_RANGE range; //note that this is an array
          } StepData;
  
          struct MSLAYOUT
          {
              // An unvalidated GC-handle
              VMPTR_OBJECTHANDLE GCHandle;
          } GetGCHandleInfo;
  
          struct MSLAYOUT
          {
              // An unvalidated GC-handle for which we're returning the results
              LSPTR_OBJECTHANDLE GCHandle;
  
              // The following are initialized by the LS in response to our query:
              VMPTR_AppDomain vmAppDomain; // AD that handle is in (only applicable if fValid).
              bool            fValid; // Did the LS determine the GC handle to be valid?
          } GetGCHandleInfoResult;
  
          // Allocate memory on the left-side
          struct MSLAYOUT
          {
              ULONG      bufSize;             // number of bytes to allocate
          } GetBuffer;
  
          // Memory allocated on the left-side
          struct MSLAYOUT
          {
              void        *pBuffer;           // LS pointer to the buffer allocated
              HRESULT     hr;                 // success / failure
          } GetBufferResult;
  
          // Free a buffer allocated on the left-side with GetBuffer
          struct MSLAYOUT
          {
              void        *pBuffer;           // Pointer previously returned in GetBufferResult
          } ReleaseBuffer;
  
          struct MSLAYOUT
          {
              HRESULT     hr;
          } ReleaseBufferResult;
  
          // Apply an EnC edit
          struct MSLAYOUT
          {            
              VMPTR_DomainFile vmDomainFile;      // Module to edit
              DWORD cbDeltaMetadata;              // size of blob pointed to by pDeltaMetadata
              CORDB_ADDRESS pDeltaMetadata;       // pointer to delta metadata in debuggee
                                                  // it's the RS's responsibility to allocate and free
                                                  // this (and pDeltaIL) using GetBuffer / ReleaseBuffer
              CORDB_ADDRESS pDeltaIL;             // pointer to delta IL in debugee
              DWORD cbDeltaIL;                    // size of blob pointed to by pDeltaIL
          } ApplyChanges;
  
          struct MSLAYOUT
          {
              HRESULT hr;
          } ApplyChangesResult;
  
          struct MSLAYOUT
          {
              mdTypeDef   classMetadataToken;
              VMPTR_DomainFile vmDomainFile;
              LSPTR_ASSEMBLY classDebuggerAssemblyToken;
          } LoadClass;
  
          struct MSLAYOUT
          {
              mdTypeDef   classMetadataToken;
              VMPTR_DomainFile vmDomainFile;
              LSPTR_ASSEMBLY classDebuggerAssemblyToken;
          } UnloadClass;
  
          struct MSLAYOUT
          {            
              VMPTR_DomainFile vmDomainFile;
              bool  flag;
          } SetClassLoad;
  
          struct MSLAYOUT
          {
              VMPTR_OBJECTHANDLE vmExceptionHandle;
              bool        firstChance;
              bool        continuable;
          } Exception;
  
          struct MSLAYOUT
          {
              VMPTR_Thread   vmThreadToken;
          } ClearException;
  
          struct MSLAYOUT
          {
              void        *address;
          } IsTransitionStub;
  
          struct MSLAYOUT
          {
              bool        isStub;
          } IsTransitionStubResult;
  
          struct MSLAYOUT
          {
              CORDB_ADDRESS    startAddress;
              bool             fCanSetIPOnly;
              VMPTR_Thread     vmThreadToken;
              VMPTR_DomainFile vmDomainFile;
              mdMethodDef      mdMethod;
              VMPTR_MethodDesc vmMethodDesc;
              SIZE_T           offset;
              bool             fIsIL;
              void *           firstExceptionHandler;
          } SetIP; // this is also used for CanSetIP
  
          struct MSLAYOUT
          {
              int iLevel;
  
              EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szCategory;
              Ls_Rs_StringBuffer szContent;
          } FirstLogMessage;
  
          struct MSLAYOUT
          {
              int iLevel;
              int iReason;
  
              EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szSwitchName;
              EmbeddedIPCString<MAX_LOG_SWITCH_NAME_LEN + 1> szParentSwitchName;
          } LogSwitchSettingMessage;
  
          // information needed to send to the RS as part of a custom notification from the target
          struct MSLAYOUT
          {
              // Domain file for the domain in which the notification occurred
              VMPTR_DomainFile vmDomainFile;
  
              // metadata token for the type of the CustomNotification object's type
              mdTypeDef    classToken;
          } CustomNotification;
  
          struct MSLAYOUT
          {
              VMPTR_Thread vmThreadToken;
              CorDebugThreadState debugState;
          } SetAllDebugState;
  
          DebuggerIPCE_FuncEvalInfo FuncEval;
  
          struct MSLAYOUT
          {
              CORDB_ADDRESS argDataArea;
              LSPTR_DEBUGGEREVAL debuggerEvalKey;
          } FuncEvalSetupComplete;
  
          struct MSLAYOUT
          {
              RSPTR_CORDBEVAL funcEvalKey;
              bool            successful;
              bool            aborted;
              void           *resultAddr;
  
              // AppDomain that the result is in.
              VMPTR_AppDomain vmAppDomain;
  
              VMPTR_OBJECTHANDLE vmObjectHandle;
              DebuggerIPCE_ExpandedTypeData resultType;
          } FuncEvalComplete;
  
          struct MSLAYOUT
          {
              LSPTR_DEBUGGEREVAL debuggerEvalKey;
          } FuncEvalAbort;
  
          struct MSLAYOUT
          {
              LSPTR_DEBUGGEREVAL debuggerEvalKey;
          } FuncEvalRudeAbort;
  
          struct MSLAYOUT
          {
              LSPTR_DEBUGGEREVAL debuggerEvalKey;
          } FuncEvalCleanup;
  
          struct MSLAYOUT
          {
              void           *objectRefAddress;
              VMPTR_OBJECTHANDLE vmObjectHandle;
              void           *newReference;
          } SetReference;
  
          struct MSLAYOUT
          {
              NameChangeType  eventType;
              VMPTR_AppDomain vmAppDomain;
              VMPTR_Thread    vmThread;
          } NameChange;
  
          struct MSLAYOUT
          {
              VMPTR_DomainFile vmDomainFile;
              BOOL             fAllowJitOpts;
              BOOL             fEnableEnC;
          } JitDebugInfo;
  
          // EnC Remap opportunity
          struct MSLAYOUT
          {
              VMPTR_DomainFile vmDomainFile;
              mdMethodDef funcMetadataToken ;        // methodDef of function with remap opportunity
              SIZE_T          currentVersionNumber;  // version currently executing
              SIZE_T          resumeVersionNumber;   // latest version
              SIZE_T          currentILOffset;       // the IL offset of the current IP
              SIZE_T          *resumeILOffset;       // pointer into left-side where an offset to resume
                                                     // to should be written if remap is desired.
          } EnCRemap;
  
          // EnC Remap has taken place
          struct MSLAYOUT
          {
              VMPTR_DomainFile vmDomainFile;
              mdMethodDef funcMetadataToken;         // methodDef of function that was remapped
          } EnCRemapComplete;
  
          // Notification that the LS is about to update a CLR data structure to account for a
          // specific edit made by EnC (function add/update or field add).
          struct MSLAYOUT
          {
              VMPTR_DomainFile vmDomainFile;
              mdToken         memberMetadataToken;   // Either a methodDef token indicating the function that
                                                     // was updated/added, or a fieldDef token indicating the
                                                     // field which was added.
              mdTypeDef       classMetadataToken;    // TypeDef token of the class in which the update was made
              SIZE_T          newVersionNumber;      // The new function/module version
          } EnCUpdate;
  
          struct MSLAYOUT
          {
              void      *oldData;
              void      *newData;
              DebuggerIPCE_BasicTypeData type;
          } SetValueClass;
  
  
          // Event used to tell LS if a single function is user or non-user code.
          // Same structure used to get function status.
          // @todo - Perhaps we can bundle these up so we can set multiple funcs w/ 1 event?
          struct MSLAYOUT
          {
              VMPTR_DomainFile vmDomainFile;
              mdMethodDef     funcMetadataToken;
              DWORD           dwStatus;
          } SetJMCFunctionStatus;
  
          struct MSLAYOUT
          {
              TASKID      taskid;
          } GetThreadForTaskId;
  
          struct MSLAYOUT
          {
              VMPTR_Thread vmThreadToken;
          } GetThreadForTaskIdResult;
  
          struct MSLAYOUT
          {
              CONNID     connectionId;
          } ConnectionChange;
  
          struct MSLAYOUT
          {
              CONNID     connectionId;
              EmbeddedIPCString<MAX_LONGPATH> wzConnectionName;
          } CreateConnection;
  
          struct MSLAYOUT
          {
              void            *objectToken;
              BOOL          fStrong;
          } CreateHandle;
  
          struct MSLAYOUT
          {
              VMPTR_OBJECTHANDLE vmObjectHandle;
          } CreateHandleResult;
  
          // used in DB_IPCE_DISPOSE_HANDLE event
          struct MSLAYOUT
          {
              VMPTR_OBJECTHANDLE vmObjectHandle;
              BOOL            fStrong;
          } DisposeHandle;
  
          struct MSLAYOUT
          {
              FramePointer                  framePointer;
              SIZE_T                        nOffset;
              CorDebugExceptionCallbackType eventType;
              DWORD                         dwFlags;
              VMPTR_OBJECTHANDLE            vmExceptionHandle;
          } ExceptionCallback2;
  
          struct MSLAYOUT
          {
              CorDebugExceptionUnwindCallbackType eventType;
              DWORD                               dwFlags;
          } ExceptionUnwind;
  
          struct MSLAYOUT
          {
              VMPTR_Thread vmThreadToken;
              FramePointer frameToken;
          } InterceptException;
  
          struct MSLAYOUT
          {
              VMPTR_Module vmModule;
              void * pMetadataStart;
              ULONG nMetadataSize;
          } MetadataUpdateRequest;
      };
  };
  
  
  // When using a network transport rather than shared memory buffers CorDBIPC_BUFFER_SIZE is the upper bound
  // for a single DebuggerIPCEvent structure. This now relates to the maximal size of a network message and is
  // orthogonal to the host's page size. Round the buffer size up to a multiple of 8 since MSVC seems more
  // aggressive in this regard than gcc.
  #define CorDBIPC_TRANSPORT_BUFFER_SIZE (((sizeof(DebuggerIPCEvent) + 7) / 8) * 8)
  
  // A DebuggerIPCEvent must fit in the send & receive buffers, which are CorDBIPC_BUFFER_SIZE bytes.
  static_assert_no_msg(sizeof(DebuggerIPCEvent) <= CorDBIPC_BUFFER_SIZE);
  static_assert_no_msg(CorDBIPC_TRANSPORT_BUFFER_SIZE <= CorDBIPC_BUFFER_SIZE);
  
  // 2*sizeof(WCHAR) for the two string terminating characters in the FirstLogMessage
  #define LOG_MSG_PADDING         4
  
  #endif /* _DbgIPCEvents_h_ */
  