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
6//
7
8//
9// Implements the old-style event channel between two remote processes.
10//*****************************************************************************
11
12#include "stdafx.h"
13#include "eventchannel.h"
14
15#include "dbgtransportsession.h"
16#include "dbgtransportmanager.h"
17
18
19//---------------------------------------------------------------------------------------
20// Class serves as a connector to win32 native-debugging API.
21class RemoteEventChannel : public IEventChannel
22{
23public:
24 RemoteEventChannel(DebuggerIPCControlBlock * pDCBBuffer,
25 DbgTransportTarget * pProxy,
26 DbgTransportSession * pTransport);
27
28 virtual ~RemoteEventChannel() {}
29
30 // Inititalize the event channel.
31 virtual HRESULT Init(HANDLE hTargetProc);
32
33 // Called when the debugger is detaching.
34 virtual void Detach();
35
36 // Delete the event channel and clean up all the resources it owns. This function can only be called once.
37 virtual void Delete();
38
39
40
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);
43
44 // Update the entire RS copy of the debugger control block by reading the LS copy.
45 virtual HRESULT UpdateRightSideDCB();
46
47 // Get the pointer to the RS DCB.
48 virtual DebuggerIPCControlBlock * GetDCB();
49
50
51
52 // Check whether we need to wait for an acknowledgement from the LS after sending an IPC event.
53 virtual BOOL NeedToWaitForAck(DebuggerIPCEvent * pEvent);
54
55 // Get a handle to wait on after sending an IPC event to the LS. The caller should call NeedToWaitForAck()
56 virtual HANDLE GetRightSideEventAckHandle();
57
58 // Clean up the state if the wait for an acknowledgement is unsuccessful.
59 virtual void ClearEventForLeftSide();
60
61
62
63 // Send an IPC event to the LS.
64 virtual HRESULT SendEventToLeftSide(DebuggerIPCEvent * pEvent, SIZE_T eventSize);
65
66 // Get the reply from the LS for a previously sent IPC event.
67 virtual HRESULT GetReplyFromLeftSide(DebuggerIPCEvent * pReplyEvent, SIZE_T eventSize);
68
69
70
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);
74
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);
78
79private:
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
83
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;
88};
89
90// Allocate and return an old-style event channel object for this target platform.
91HRESULT NewEventChannelForThisPlatform(CORDB_ADDRESS pLeftSideDCB,
92 ICorDebugMutableDataTarget * pMutableDataTarget,
93 const ProcessDescriptor * pProcessDescriptor,
94 MachineInfo machineInfo,
95 IEventChannel ** ppEventChannel)
96{
97 // @dbgtodo Mac - Consider moving all of the transport logic to one place.
98 // Perhaps add a new function on DbgTransportManager.
99 HandleHolder hDummy;
100 HRESULT hr = E_FAIL;
101
102 RemoteEventChannel * pEventChannel = NULL;
103 DebuggerIPCControlBlock * pDCBBuffer = NULL;
104
105 DbgTransportTarget * pProxy = g_pDbgTransportTarget;
106 DbgTransportSession * pTransport = NULL;
107
108 hr = pProxy->GetTransportForProcess(pProcessDescriptor, &pTransport, &hDummy);
109 if (FAILED(hr))
110 {
111 goto Label_Exit;
112 }
113
114 if (!pTransport->WaitForSessionToOpen(10000))
115 {
116 hr = CORDBG_E_TIMEOUT;
117 goto Label_Exit;
118 }
119
120 pDCBBuffer = new (nothrow) DebuggerIPCControlBlock;
121 if (pDCBBuffer == NULL)
122 {
123 hr = E_OUTOFMEMORY;
124 goto Label_Exit;
125 }
126
127 pEventChannel = new (nothrow) RemoteEventChannel(pDCBBuffer, pProxy, pTransport);
128 if (pEventChannel == NULL)
129 {
130 hr = E_OUTOFMEMORY;
131 goto Label_Exit;
132 }
133
134 _ASSERTE(SUCCEEDED(hr));
135 *ppEventChannel = pEventChannel;
136
137Label_Exit:
138 if (FAILED(hr))
139 {
140 if (pEventChannel != NULL)
141 {
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;
145 }
146 else
147 {
148 if (pTransport != NULL)
149 {
150 pProxy->ReleaseTransport(pTransport);
151 }
152 if (pDCBBuffer != NULL)
153 {
154 delete pDCBBuffer;
155 }
156 }
157 }
158 return hr;
159}
160
161//-----------------------------------------------------------------------------
162//
163// This is the constructor.
164//
165// Arguments:
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
169//
170
171RemoteEventChannel::RemoteEventChannel(DebuggerIPCControlBlock * pDCBBuffer,
172 DbgTransportTarget * pProxy,
173 DbgTransportSession * pTransport)
174{
175 m_pDCBBuffer = pDCBBuffer;
176 m_pProxy = pProxy;
177 m_pTransport = pTransport;
178 m_fLeftSideEventAvailable = FALSE;
179}
180
181// Inititalize the event channel.
182//
183// virtual
184HRESULT RemoteEventChannel::Init(HANDLE hTargetProc)
185{
186 return S_OK;
187}
188
189// Called when the debugger is detaching.
190//
191// virtual
192void RemoteEventChannel::Detach()
193{
194 // This is a nop for Mac debugging because we don't use RSEA/RSER.
195 return;
196}
197
198// Delete the event channel and clean up all the resources it owns. This function can only be called once.
199//
200// virtual
201void RemoteEventChannel::Delete()
202{
203 if (m_pDCBBuffer != NULL)
204 {
205 delete m_pDCBBuffer;
206 m_pDCBBuffer = NULL;
207 }
208
209 if (m_pTransport != NULL)
210 {
211 m_pProxy->ReleaseTransport(m_pTransport);
212 }
213
214 delete this;
215}
216
217// Update a single field with a value stored in the RS copy of the DCB.
218//
219// virtual
220HRESULT RemoteEventChannel::UpdateLeftSideDCBField(void * rsFieldAddr, SIZE_T size)
221{
222 _ASSERTE(m_pDCBBuffer != NULL);
223
224 // Ask the transport to update the LS DCB.
225 return m_pTransport->SetDCB(m_pDCBBuffer);
226}
227
228// Update the entire RS copy of the debugger control block by reading the LS copy.
229//
230// virtual
231HRESULT RemoteEventChannel::UpdateRightSideDCB()
232{
233 _ASSERTE(m_pDCBBuffer != NULL);
234
235 // Ask the transport to read the DCB from the Ls.
236 return m_pTransport->GetDCB(m_pDCBBuffer);
237}
238
239// Get the pointer to the RS DCB.
240//
241// virtual
242DebuggerIPCControlBlock * RemoteEventChannel::GetDCB()
243{
244 return m_pDCBBuffer;
245}
246
247// Check whether we need to wait for an acknowledgement from the LS after sending an IPC event.
248//
249// virtual
250BOOL RemoteEventChannel::NeedToWaitForAck(DebuggerIPCEvent * pEvent)
251{
252 // There are three cases to consider when sending an event over the transport:
253 //
254 // 1) asynchronous
255 // - the LS can just send the event and continue
256 //
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.
261 //
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);
265}
266
267// Get a handle to wait on after sending an IPC event to the LS. The caller should call NeedToWaitForAck()
268//
269// virtual
270HANDLE RemoteEventChannel::GetRightSideEventAckHandle()
271{
272 // Delegate to the transport which does the real work.
273 return m_pTransport->GetIPCEventReadyEvent();
274}
275
276// Clean up the state if the wait for an acknowledgement is unsuccessful.
277//
278// virtual
279void RemoteEventChannel::ClearEventForLeftSide()
280{
281 // This is a nop for Mac debugging because we don't use RSEA/RSER.
282 return;
283}
284
285// Send an IPC event to the LS.
286//
287// virtual
288HRESULT RemoteEventChannel::SendEventToLeftSide(DebuggerIPCEvent * pEvent, SIZE_T eventSize)
289{
290 _ASSERTE(eventSize <= CorDBIPC_BUFFER_SIZE);
291
292 // Delegate to the transport. The event size is ignored.
293 return m_pTransport->SendEvent(pEvent);
294}
295
296// Get the reply from the LS for a previously sent IPC event.
297//
298// virtual
299HRESULT RemoteEventChannel::GetReplyFromLeftSide(DebuggerIPCEvent * pReplyEvent, SIZE_T eventSize)
300{
301 // Delegate to the transport.
302 m_pTransport->GetNextEvent(pReplyEvent, (DWORD)eventSize);
303 return S_OK;
304}
305
306// Save an IPC event from the LS.
307// Used for transferring an IPC event from the native pipeline to the IPC event channel.
308//
309// virtual
310HRESULT RemoteEventChannel::SaveEventFromLeftSide(DebuggerIPCEvent * pEventFromLeftSide)
311{
312 if (m_fLeftSideEventAvailable)
313 {
314 // We should only be saving one event at a time.
315 return E_FAIL;
316 }
317 else
318 {
319 memcpy(m_rgbLeftSideEventBuffer, reinterpret_cast<BYTE *>(pEventFromLeftSide), CorDBIPC_BUFFER_SIZE);
320 m_fLeftSideEventAvailable = TRUE;
321 return S_OK;
322 }
323}
324
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.
327//
328// virtual
329HRESULT RemoteEventChannel::GetEventFromLeftSide(DebuggerIPCEvent * pLocalManagedEvent)
330{
331 if (m_fLeftSideEventAvailable)
332 {
333 memcpy(reinterpret_cast<BYTE *>(pLocalManagedEvent), m_rgbLeftSideEventBuffer, CorDBIPC_BUFFER_SIZE);
334 m_fLeftSideEventAvailable = FALSE;
335 return S_OK;
336 }
337 else
338 {
339 // We have not saved any event.
340 return E_FAIL;
341 }
342}
343