diff options
Diffstat (limited to 'src/debug/di/remoteeventchannel.cpp')
-rw-r--r-- | src/debug/di/remoteeventchannel.cpp | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/src/debug/di/remoteeventchannel.cpp b/src/debug/di/remoteeventchannel.cpp new file mode 100644 index 0000000000..fc1d57a60f --- /dev/null +++ b/src/debug/di/remoteeventchannel.cpp @@ -0,0 +1,342 @@ +// 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. +//***************************************************************************** +// File: RemoteEventChannel.cpp +// + +// +// Implements the old-style event channel between two remote processes. +//***************************************************************************** + +#include "stdafx.h" +#include "eventchannel.h" + +#include "dbgtransportsession.h" +#include "dbgtransportmanager.h" + + +//--------------------------------------------------------------------------------------- +// Class serves as a connector to win32 native-debugging API. +class RemoteEventChannel : public IEventChannel +{ +public: + RemoteEventChannel(DebuggerIPCControlBlock * pDCBBuffer, + DbgTransportTarget * pProxy, + DbgTransportSession * pTransport); + + virtual ~RemoteEventChannel() {} + + // Inititalize the event channel. + virtual HRESULT Init(HANDLE hTargetProc); + + // Called when the debugger is detaching. + virtual void Detach(); + + // Delete the event channel and clean up all the resources it owns. This function can only be called once. + virtual void Delete(); + + + + // Update a single field with a value stored in the RS copy of the DCB. + virtual HRESULT UpdateLeftSideDCBField(void *rsFieldAddr, SIZE_T size); + + // Update the entire RS copy of the debugger control block by reading the LS copy. + virtual HRESULT UpdateRightSideDCB(); + + // Get the pointer to the RS DCB. + virtual DebuggerIPCControlBlock * GetDCB(); + + + + // Check whether we need to wait for an acknowledgement from the LS after sending an IPC event. + virtual BOOL NeedToWaitForAck(DebuggerIPCEvent * pEvent); + + // Get a handle to wait on after sending an IPC event to the LS. The caller should call NeedToWaitForAck() + virtual HANDLE GetRightSideEventAckHandle(); + + // Clean up the state if the wait for an acknowledgement is unsuccessful. + virtual void ClearEventForLeftSide(); + + + + // Send an IPC event to the LS. + virtual HRESULT SendEventToLeftSide(DebuggerIPCEvent * pEvent, SIZE_T eventSize); + + // Get the reply from the LS for a previously sent IPC event. + virtual HRESULT GetReplyFromLeftSide(DebuggerIPCEvent * pReplyEvent, SIZE_T eventSize); + + + + // Save an IPC event from the LS. + // Used for transferring an IPC event from the native pipeline to the IPC event channel. + virtual HRESULT SaveEventFromLeftSide(DebuggerIPCEvent * pEventFromLeftSide); + + // Get a saved IPC event from the LS. + // Used for transferring an IPC event from the native pipeline to the IPC event channel. + virtual HRESULT GetEventFromLeftSide(DebuggerIPCEvent * pLocalManagedEvent); + +private: + DebuggerIPCControlBlock * m_pDCBBuffer; // local buffer for the DCB on the RS + DbgTransportTarget * m_pProxy; // connection to the debugger proxy + DbgTransportSession * m_pTransport; // connection to the debuggee process + + // The next two fields are used for storing an IPC event from the native pipeline + // for the IPC event channel. + BYTE m_rgbLeftSideEventBuffer[CorDBIPC_BUFFER_SIZE]; + BOOL m_fLeftSideEventAvailable; +}; + +// Allocate and return an old-style event channel object for this target platform. +HRESULT NewEventChannelForThisPlatform(CORDB_ADDRESS pLeftSideDCB, + ICorDebugMutableDataTarget * pMutableDataTarget, + DWORD dwProcessId, + MachineInfo machineInfo, + IEventChannel ** ppEventChannel) +{ + // @dbgtodo Mac - Consider moving all of the transport logic to one place. + // Perhaps add a new function on DbgTransportManager. + HandleHolder hDummy; + HRESULT hr = E_FAIL; + + RemoteEventChannel * pEventChannel = NULL; + DebuggerIPCControlBlock * pDCBBuffer = NULL; + + DbgTransportTarget * pProxy = g_pDbgTransportTarget; + DbgTransportSession * pTransport = NULL; + + hr = pProxy->GetTransportForProcess(dwProcessId, &pTransport, &hDummy); + if (FAILED(hr)) + { + goto Label_Exit; + } + + if (!pTransport->WaitForSessionToOpen(10000)) + { + hr = CORDBG_E_TIMEOUT; + goto Label_Exit; + } + + pDCBBuffer = new (nothrow) DebuggerIPCControlBlock; + if (pDCBBuffer == NULL) + { + hr = E_OUTOFMEMORY; + goto Label_Exit; + } + + pEventChannel = new (nothrow) RemoteEventChannel(pDCBBuffer, pProxy, pTransport); + if (pEventChannel == NULL) + { + hr = E_OUTOFMEMORY; + goto Label_Exit; + } + + _ASSERTE(SUCCEEDED(hr)); + *ppEventChannel = pEventChannel; + +Label_Exit: + if (FAILED(hr)) + { + if (pEventChannel != NULL) + { + // The IEventChannel has ownership of the proxy and the transport, + // so we don't need to clean them up here. + delete pEventChannel; + } + else + { + if (pTransport != NULL) + { + pProxy->ReleaseTransport(pTransport); + } + if (pDCBBuffer != NULL) + { + delete pDCBBuffer; + } + } + } + return hr; +} + +//----------------------------------------------------------------------------- +// +// This is the constructor. +// +// Arguments: +// pLeftSideDCB - target address of the DCB on the LS +// pDCBBuffer - local buffer for storing the DCB on the RS; the memory is owned by this class +// pMutableDataTarget - data target for reading from and writing to the target process's address space +// + +RemoteEventChannel::RemoteEventChannel(DebuggerIPCControlBlock * pDCBBuffer, + DbgTransportTarget * pProxy, + DbgTransportSession * pTransport) +{ + m_pDCBBuffer = pDCBBuffer; + m_pProxy = pProxy; + m_pTransport = pTransport; + m_fLeftSideEventAvailable = FALSE; +} + +// Inititalize the event channel. +// +// virtual +HRESULT RemoteEventChannel::Init(HANDLE hTargetProc) +{ + return S_OK; +} + +// Called when the debugger is detaching. +// +// virtual +void RemoteEventChannel::Detach() +{ + // This is a nop for Mac debugging because we don't use RSEA/RSER. + return; +} + +// Delete the event channel and clean up all the resources it owns. This function can only be called once. +// +// virtual +void RemoteEventChannel::Delete() +{ + if (m_pDCBBuffer != NULL) + { + delete m_pDCBBuffer; + m_pDCBBuffer = NULL; + } + + if (m_pTransport != NULL) + { + m_pProxy->ReleaseTransport(m_pTransport); + } + + delete this; +} + +// Update a single field with a value stored in the RS copy of the DCB. +// +// virtual +HRESULT RemoteEventChannel::UpdateLeftSideDCBField(void * rsFieldAddr, SIZE_T size) +{ + _ASSERTE(m_pDCBBuffer != NULL); + + // Ask the transport to update the LS DCB. + return m_pTransport->SetDCB(m_pDCBBuffer); +} + +// Update the entire RS copy of the debugger control block by reading the LS copy. +// +// virtual +HRESULT RemoteEventChannel::UpdateRightSideDCB() +{ + _ASSERTE(m_pDCBBuffer != NULL); + + // Ask the transport to read the DCB from the Ls. + return m_pTransport->GetDCB(m_pDCBBuffer); +} + +// Get the pointer to the RS DCB. +// +// virtual +DebuggerIPCControlBlock * RemoteEventChannel::GetDCB() +{ + return m_pDCBBuffer; +} + +// Check whether we need to wait for an acknowledgement from the LS after sending an IPC event. +// +// virtual +BOOL RemoteEventChannel::NeedToWaitForAck(DebuggerIPCEvent * pEvent) +{ + // There are three cases to consider when sending an event over the transport: + // + // 1) asynchronous + // - the LS can just send the event and continue + // + // 2) synchronous, but no reply + // - This is different than Windows. We don't wait for an acknowledgement. + // Needless to say this is a semantical difference, but none of our code actually expects + // this type of IPC events to be synchronized. + // + // 3) synchronous, reply required: + // - This is the only case we need to wait for an acknowledgement in the Mac debugging case. + return (!pEvent->asyncSend && pEvent->replyRequired); +} + +// Get a handle to wait on after sending an IPC event to the LS. The caller should call NeedToWaitForAck() +// +// virtual +HANDLE RemoteEventChannel::GetRightSideEventAckHandle() +{ + // Delegate to the transport which does the real work. + return m_pTransport->GetIPCEventReadyEvent(); +} + +// Clean up the state if the wait for an acknowledgement is unsuccessful. +// +// virtual +void RemoteEventChannel::ClearEventForLeftSide() +{ + // This is a nop for Mac debugging because we don't use RSEA/RSER. + return; +} + +// Send an IPC event to the LS. +// +// virtual +HRESULT RemoteEventChannel::SendEventToLeftSide(DebuggerIPCEvent * pEvent, SIZE_T eventSize) +{ + _ASSERTE(eventSize <= CorDBIPC_BUFFER_SIZE); + + // Delegate to the transport. The event size is ignored. + return m_pTransport->SendEvent(pEvent); +} + +// Get the reply from the LS for a previously sent IPC event. +// +// virtual +HRESULT RemoteEventChannel::GetReplyFromLeftSide(DebuggerIPCEvent * pReplyEvent, SIZE_T eventSize) +{ + // Delegate to the transport. + m_pTransport->GetNextEvent(pReplyEvent, (DWORD)eventSize); + return S_OK; +} + +// Save an IPC event from the LS. +// Used for transferring an IPC event from the native pipeline to the IPC event channel. +// +// virtual +HRESULT RemoteEventChannel::SaveEventFromLeftSide(DebuggerIPCEvent * pEventFromLeftSide) +{ + if (m_fLeftSideEventAvailable) + { + // We should only be saving one event at a time. + return E_FAIL; + } + else + { + memcpy(m_rgbLeftSideEventBuffer, reinterpret_cast<BYTE *>(pEventFromLeftSide), CorDBIPC_BUFFER_SIZE); + m_fLeftSideEventAvailable = TRUE; + return S_OK; + } +} + +// Get a saved IPC event from the LS. +// Used for transferring an IPC event from the native pipeline to the IPC event channel. +// +// virtual +HRESULT RemoteEventChannel::GetEventFromLeftSide(DebuggerIPCEvent * pLocalManagedEvent) +{ + if (m_fLeftSideEventAvailable) + { + memcpy(reinterpret_cast<BYTE *>(pLocalManagedEvent), m_rgbLeftSideEventBuffer, CorDBIPC_BUFFER_SIZE); + m_fLeftSideEventAvailable = FALSE; + return S_OK; + } + else + { + // We have not saved any event. + return E_FAIL; + } +} |