summaryrefslogtreecommitdiff
path: root/src/debug/di/remoteeventchannel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug/di/remoteeventchannel.cpp')
-rw-r--r--src/debug/di/remoteeventchannel.cpp342
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;
+ }
+}