1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
5 // File: RemoteEventChannel.cpp
9 // Implements the old-style event channel between two remote processes.
10 //*****************************************************************************
13 #include "eventchannel.h"
15 #include "dbgtransportsession.h"
16 #include "dbgtransportmanager.h"
19 //---------------------------------------------------------------------------------------
20 // Class serves as a connector to win32 native-debugging API.
21 class RemoteEventChannel : public IEventChannel
24 RemoteEventChannel(DebuggerIPCControlBlock * pDCBBuffer,
25 DbgTransportTarget * pProxy,
26 DbgTransportSession * pTransport);
28 virtual ~RemoteEventChannel() {}
30 // Inititalize the event channel.
31 virtual HRESULT Init(HANDLE hTargetProc);
33 // Called when the debugger is detaching.
34 virtual void Detach();
36 // Delete the event channel and clean up all the resources it owns. This function can only be called once.
37 virtual void Delete();
41 // Update a single field with a value stored in the RS copy of the DCB.
42 virtual HRESULT UpdateLeftSideDCBField(void *rsFieldAddr, SIZE_T size);
44 // Update the entire RS copy of the debugger control block by reading the LS copy.
45 virtual HRESULT UpdateRightSideDCB();
47 // Get the pointer to the RS DCB.
48 virtual DebuggerIPCControlBlock * GetDCB();
52 // Check whether we need to wait for an acknowledgement from the LS after sending an IPC event.
53 virtual BOOL NeedToWaitForAck(DebuggerIPCEvent * pEvent);
55 // Get a handle to wait on after sending an IPC event to the LS. The caller should call NeedToWaitForAck()
56 virtual HANDLE GetRightSideEventAckHandle();
58 // Clean up the state if the wait for an acknowledgement is unsuccessful.
59 virtual void ClearEventForLeftSide();
63 // Send an IPC event to the LS.
64 virtual HRESULT SendEventToLeftSide(DebuggerIPCEvent * pEvent, SIZE_T eventSize);
66 // Get the reply from the LS for a previously sent IPC event.
67 virtual HRESULT GetReplyFromLeftSide(DebuggerIPCEvent * pReplyEvent, SIZE_T eventSize);
71 // Save an IPC event from the LS.
72 // Used for transferring an IPC event from the native pipeline to the IPC event channel.
73 virtual HRESULT SaveEventFromLeftSide(DebuggerIPCEvent * pEventFromLeftSide);
75 // Get a saved IPC event from the LS.
76 // Used for transferring an IPC event from the native pipeline to the IPC event channel.
77 virtual HRESULT GetEventFromLeftSide(DebuggerIPCEvent * pLocalManagedEvent);
80 DebuggerIPCControlBlock * m_pDCBBuffer; // local buffer for the DCB on the RS
81 DbgTransportTarget * m_pProxy; // connection to the debugger proxy
82 DbgTransportSession * m_pTransport; // connection to the debuggee process
84 // The next two fields are used for storing an IPC event from the native pipeline
85 // for the IPC event channel.
86 BYTE m_rgbLeftSideEventBuffer[CorDBIPC_BUFFER_SIZE];
87 BOOL m_fLeftSideEventAvailable;
90 // Allocate and return an old-style event channel object for this target platform.
91 HRESULT NewEventChannelForThisPlatform(CORDB_ADDRESS pLeftSideDCB,
92 ICorDebugMutableDataTarget * pMutableDataTarget,
94 MachineInfo machineInfo,
95 IEventChannel ** ppEventChannel)
97 // @dbgtodo Mac - Consider moving all of the transport logic to one place.
98 // Perhaps add a new function on DbgTransportManager.
102 RemoteEventChannel * pEventChannel = NULL;
103 DebuggerIPCControlBlock * pDCBBuffer = NULL;
105 DbgTransportTarget * pProxy = g_pDbgTransportTarget;
106 DbgTransportSession * pTransport = NULL;
108 hr = pProxy->GetTransportForProcess(dwProcessId, &pTransport, &hDummy);
114 if (!pTransport->WaitForSessionToOpen(10000))
116 hr = CORDBG_E_TIMEOUT;
120 pDCBBuffer = new (nothrow) DebuggerIPCControlBlock;
121 if (pDCBBuffer == NULL)
127 pEventChannel = new (nothrow) RemoteEventChannel(pDCBBuffer, pProxy, pTransport);
128 if (pEventChannel == NULL)
134 _ASSERTE(SUCCEEDED(hr));
135 *ppEventChannel = pEventChannel;
140 if (pEventChannel != NULL)
142 // The IEventChannel has ownership of the proxy and the transport,
143 // so we don't need to clean them up here.
144 delete pEventChannel;
148 if (pTransport != NULL)
150 pProxy->ReleaseTransport(pTransport);
152 if (pDCBBuffer != NULL)
161 //-----------------------------------------------------------------------------
163 // This is the constructor.
166 // pLeftSideDCB - target address of the DCB on the LS
167 // pDCBBuffer - local buffer for storing the DCB on the RS; the memory is owned by this class
168 // pMutableDataTarget - data target for reading from and writing to the target process's address space
171 RemoteEventChannel::RemoteEventChannel(DebuggerIPCControlBlock * pDCBBuffer,
172 DbgTransportTarget * pProxy,
173 DbgTransportSession * pTransport)
175 m_pDCBBuffer = pDCBBuffer;
177 m_pTransport = pTransport;
178 m_fLeftSideEventAvailable = FALSE;
181 // Inititalize the event channel.
184 HRESULT RemoteEventChannel::Init(HANDLE hTargetProc)
189 // Called when the debugger is detaching.
192 void RemoteEventChannel::Detach()
194 // This is a nop for Mac debugging because we don't use RSEA/RSER.
198 // Delete the event channel and clean up all the resources it owns. This function can only be called once.
201 void RemoteEventChannel::Delete()
203 if (m_pDCBBuffer != NULL)
209 if (m_pTransport != NULL)
211 m_pProxy->ReleaseTransport(m_pTransport);
217 // Update a single field with a value stored in the RS copy of the DCB.
220 HRESULT RemoteEventChannel::UpdateLeftSideDCBField(void * rsFieldAddr, SIZE_T size)
222 _ASSERTE(m_pDCBBuffer != NULL);
224 // Ask the transport to update the LS DCB.
225 return m_pTransport->SetDCB(m_pDCBBuffer);
228 // Update the entire RS copy of the debugger control block by reading the LS copy.
231 HRESULT RemoteEventChannel::UpdateRightSideDCB()
233 _ASSERTE(m_pDCBBuffer != NULL);
235 // Ask the transport to read the DCB from the Ls.
236 return m_pTransport->GetDCB(m_pDCBBuffer);
239 // Get the pointer to the RS DCB.
242 DebuggerIPCControlBlock * RemoteEventChannel::GetDCB()
247 // Check whether we need to wait for an acknowledgement from the LS after sending an IPC event.
250 BOOL RemoteEventChannel::NeedToWaitForAck(DebuggerIPCEvent * pEvent)
252 // There are three cases to consider when sending an event over the transport:
255 // - the LS can just send the event and continue
257 // 2) synchronous, but no reply
258 // - This is different than Windows. We don't wait for an acknowledgement.
259 // Needless to say this is a semantical difference, but none of our code actually expects
260 // this type of IPC events to be synchronized.
262 // 3) synchronous, reply required:
263 // - This is the only case we need to wait for an acknowledgement in the Mac debugging case.
264 return (!pEvent->asyncSend && pEvent->replyRequired);
267 // Get a handle to wait on after sending an IPC event to the LS. The caller should call NeedToWaitForAck()
270 HANDLE RemoteEventChannel::GetRightSideEventAckHandle()
272 // Delegate to the transport which does the real work.
273 return m_pTransport->GetIPCEventReadyEvent();
276 // Clean up the state if the wait for an acknowledgement is unsuccessful.
279 void RemoteEventChannel::ClearEventForLeftSide()
281 // This is a nop for Mac debugging because we don't use RSEA/RSER.
285 // Send an IPC event to the LS.
288 HRESULT RemoteEventChannel::SendEventToLeftSide(DebuggerIPCEvent * pEvent, SIZE_T eventSize)
290 _ASSERTE(eventSize <= CorDBIPC_BUFFER_SIZE);
292 // Delegate to the transport. The event size is ignored.
293 return m_pTransport->SendEvent(pEvent);
296 // Get the reply from the LS for a previously sent IPC event.
299 HRESULT RemoteEventChannel::GetReplyFromLeftSide(DebuggerIPCEvent * pReplyEvent, SIZE_T eventSize)
301 // Delegate to the transport.
302 m_pTransport->GetNextEvent(pReplyEvent, (DWORD)eventSize);
306 // Save an IPC event from the LS.
307 // Used for transferring an IPC event from the native pipeline to the IPC event channel.
310 HRESULT RemoteEventChannel::SaveEventFromLeftSide(DebuggerIPCEvent * pEventFromLeftSide)
312 if (m_fLeftSideEventAvailable)
314 // We should only be saving one event at a time.
319 memcpy(m_rgbLeftSideEventBuffer, reinterpret_cast<BYTE *>(pEventFromLeftSide), CorDBIPC_BUFFER_SIZE);
320 m_fLeftSideEventAvailable = TRUE;
325 // Get a saved IPC event from the LS.
326 // Used for transferring an IPC event from the native pipeline to the IPC event channel.
329 HRESULT RemoteEventChannel::GetEventFromLeftSide(DebuggerIPCEvent * pLocalManagedEvent)
331 if (m_fLeftSideEventAvailable)
333 memcpy(reinterpret_cast<BYTE *>(pLocalManagedEvent), m_rgbLeftSideEventBuffer, CorDBIPC_BUFFER_SIZE);
334 m_fLeftSideEventAvailable = FALSE;
339 // We have not saved any event.