Merge pull request #11243 from sdmaclea/PR-ARM64-LDP-ALLOW-GCREFS
[platform/upstream/coreclr.git] / src / debug / di / remoteeventchannel.cpp
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.
21 class RemoteEventChannel : public IEventChannel
22 {
23 public:
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
79 private:
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.
91 HRESULT NewEventChannelForThisPlatform(CORDB_ADDRESS pLeftSideDCB, 
92                                        ICorDebugMutableDataTarget * pMutableDataTarget,
93                                        DWORD dwProcessId,
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(dwProcessId, &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
137 Label_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
171 RemoteEventChannel::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
184 HRESULT RemoteEventChannel::Init(HANDLE hTargetProc)
185 {
186     return S_OK;
187 }
188
189 // Called when the debugger is detaching.
190 //
191 // virtual
192 void 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
201 void 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 
220 HRESULT 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 
231 HRESULT 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 
242 DebuggerIPCControlBlock * 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 
250 BOOL 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 
270 HANDLE 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 
279 void 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 
288 HRESULT 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 
299 HRESULT 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
310 HRESULT 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
329 HRESULT 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 }