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: LocalEventChannel.cpp
9 // Implements the old-style event channel between two processes on a local Windows machine.
10 //*****************************************************************************
13 #include "eventchannel.h"
16 //---------------------------------------------------------------------------------------
18 // This is the implementation of the event channel for the normal case, where both the debugger and the
19 // debuggee are on the same Windows machine. See code:IEventChannel for more information.
22 class LocalEventChannel : public IEventChannel
25 LocalEventChannel(CORDB_ADDRESS pLeftSideDCB,
26 DebuggerIPCControlBlock * pDCBBuffer,
27 ICorDebugMutableDataTarget * pMutableDataTarget);
29 // Inititalize the event channel.
30 virtual HRESULT Init(HANDLE hTargetProc);
32 // Called when the debugger is detaching.
33 virtual void Detach();
35 // Delete the event channel and clean up all the resources it owns. This function can only be called once.
36 virtual void Delete();
40 // Update a single field with a value stored in the RS copy of the DCB.
41 virtual HRESULT UpdateLeftSideDCBField(void *rsFieldAddr, SIZE_T size);
43 // Update the entire RS copy of the debugger control block by reading the LS copy.
44 virtual HRESULT UpdateRightSideDCB();
46 // Get the pointer to the RS DCB.
47 virtual DebuggerIPCControlBlock * GetDCB();
51 // Check whether we need to wait for an acknowledgement from the LS after sending an IPC event.
52 virtual BOOL NeedToWaitForAck(DebuggerIPCEvent * pEvent);
54 // Get a handle to wait on after sending an IPC event to the LS. The caller should call NeedToWaitForAck()
55 virtual HANDLE GetRightSideEventAckHandle();
57 // Clean up the state if the wait for an acknowledgement is unsuccessful.
58 virtual void ClearEventForLeftSide();
62 // Send an IPC event to the LS.
63 virtual HRESULT SendEventToLeftSide(DebuggerIPCEvent * pEvent, SIZE_T eventSize);
65 // Get the reply from the LS for a previously sent IPC event.
66 virtual HRESULT GetReplyFromLeftSide(DebuggerIPCEvent * pReplyEvent, SIZE_T eventSize);
70 // Save an IPC event from the LS.
71 // Used for transferring an IPC event from the native pipeline to the IPC event channel.
72 virtual HRESULT SaveEventFromLeftSide(DebuggerIPCEvent * pEventFromLeftSide);
74 // Get a saved IPC event from the LS.
75 // Used for transferring an IPC event from the native pipeline to the IPC event channel.
76 virtual HRESULT GetEventFromLeftSide(DebuggerIPCEvent * pLocalManagedEvent);
79 // Get a target buffer representing the area of the DebuggerIPCControlBlock on the helper thread that
80 // holds information received from the LS as the result of an IPC event.
81 TargetBuffer RemoteReceiveBuffer(SIZE_T size);
83 // Get a target buffer representing the area of the DebuggerIPCControlBlock on the helper thread that
84 // holds information sent to the LS with an IPC event.
85 TargetBuffer RemoteSendBuffer(SIZE_T size);
87 // write memory to the LS using the data target
88 HRESULT SafeWriteBuffer(TargetBuffer tb, const BYTE * pLocalBuffer);
90 // read memory from the LS using the data target
91 HRESULT SafeReadBuffer(TargetBuffer tb, BYTE * pLocalBuffer);
93 // duplicate a remote handle into the local process
94 HRESULT DuplicateHandleToLocalProcess(HANDLE * pLocalHandle, RemoteHANDLE * pRemoteHandle);
96 // target address of the DCB on the LS
97 CORDB_ADDRESS m_pLeftSideDCB;
99 // used to signal the to the LS that an event is available
100 HANDLE m_rightSideEventAvailable;
102 // used by the LS to signal that the event is read
103 HANDLE m_rightSideEventRead;
105 // handle of the debuggee process
106 HANDLE m_hTargetProc;
108 // local buffer for the DCB on the RS
109 DebuggerIPCControlBlock * m_pDCBBuffer;
111 // data target used for cross-process memory reads and writes
112 RSExtSmartPtr<ICorDebugMutableDataTarget> m_pMutableDataTarget;
115 // Allocate and return an old-style event channel object for this target platform.
116 HRESULT NewEventChannelForThisPlatform(CORDB_ADDRESS pLeftSideDCB,
117 ICorDebugMutableDataTarget * pMutableDataTarget,
119 MachineInfo machineInfo,
120 IEventChannel ** ppEventChannel)
122 _ASSERTE(ppEventChannel != NULL);
124 LocalEventChannel * pEventChannel = NULL;
125 DebuggerIPCControlBlock * pDCBBuffer = NULL;
127 pDCBBuffer = new (nothrow) DebuggerIPCControlBlock;
128 if (pDCBBuffer == NULL)
130 return E_OUTOFMEMORY;
133 pEventChannel = new (nothrow) LocalEventChannel(pLeftSideDCB, pDCBBuffer, pMutableDataTarget);
134 if (pEventChannel == NULL)
137 return E_OUTOFMEMORY;
140 *ppEventChannel = pEventChannel;
144 //-----------------------------------------------------------------------------
146 // This is the constructor.
149 // pLeftSideDCB - target address of the DCB on the LS
150 // pDCBBuffer - local buffer for storing the DCB on the RS; the memory is owned by this class
151 // pMutableDataTarget - data target for reading from and writing to the target process's address space
154 LocalEventChannel::LocalEventChannel(CORDB_ADDRESS pLeftSideDCB,
155 DebuggerIPCControlBlock * pDCBBuffer,
156 ICorDebugMutableDataTarget * pMutableDataTarget)
158 m_pLeftSideDCB = pLeftSideDCB;
159 m_pDCBBuffer = pDCBBuffer;
161 m_rightSideEventAvailable = NULL;
162 m_rightSideEventRead = NULL;
164 m_pMutableDataTarget.Assign(pMutableDataTarget);
167 // Inititalize the event channel.
170 HRESULT LocalEventChannel::Init(HANDLE hTargetProc)
174 m_hTargetProc = hTargetProc;
176 // Duplicate the handle of the RS process (i.e. the debugger) to the LS process's address space.
178 m_pDCBBuffer->m_rightSideProcessHandle.DuplicateToRemoteProcess(m_hTargetProc, GetCurrentProcess());
181 return HRESULT_FROM_GetLastError();
184 IfFailRet(UpdateLeftSideDCBField(&(m_pDCBBuffer->m_rightSideProcessHandle),
185 sizeof(m_pDCBBuffer->m_rightSideProcessHandle)));
187 // Dup RSEA and RSER into this process if we don't already have them.
188 // On Launch, we don't have them yet, but on attach we do.
189 IfFailRet(DuplicateHandleToLocalProcess(&m_rightSideEventAvailable,
190 &m_pDCBBuffer->m_rightSideEventAvailable));
191 IfFailRet(DuplicateHandleToLocalProcess(&m_rightSideEventRead,
192 &m_pDCBBuffer->m_rightSideEventRead));
197 // Called when the debugger is detaching.
200 void LocalEventChannel::Detach()
202 // This averts a race condition wherein we'll detach, then reattach,
203 // and find these events in the still-signalled state.
204 if (m_rightSideEventAvailable != NULL)
206 ResetEvent(m_rightSideEventAvailable);
208 if (m_rightSideEventRead != NULL)
210 ResetEvent(m_rightSideEventRead);
214 // Delete the event channel and clean up all the resources it owns. This function can only be called once.
217 void LocalEventChannel::Delete()
219 if (m_hTargetProc != NULL)
221 m_pDCBBuffer->m_rightSideProcessHandle.CloseInRemoteProcess(m_hTargetProc);
222 UpdateLeftSideDCBField(&(m_pDCBBuffer->m_rightSideProcessHandle), sizeof(m_pDCBBuffer->m_rightSideProcessHandle));
223 m_hTargetProc = NULL;
226 if (m_rightSideEventAvailable != NULL)
228 CloseHandle(m_rightSideEventAvailable);
229 m_rightSideEventAvailable = NULL;
232 if (m_rightSideEventRead!= NULL)
234 CloseHandle(m_rightSideEventRead);
235 m_rightSideEventRead = NULL;
238 if (m_pDCBBuffer != NULL)
244 if (m_pMutableDataTarget != NULL)
246 m_pMutableDataTarget.Clear();
252 // Update a single field with a value stored in the RS copy of the DCB.
255 HRESULT LocalEventChannel::UpdateLeftSideDCBField(void * rsFieldAddr, SIZE_T size)
257 _ASSERTE(m_pDCBBuffer != NULL);
258 _ASSERTE(m_pLeftSideDCB != NULL);
260 BYTE * pbRSFieldAddr = reinterpret_cast<BYTE *>(rsFieldAddr);
261 CORDB_ADDRESS lsFieldAddr = m_pLeftSideDCB + (pbRSFieldAddr - reinterpret_cast<BYTE *>(m_pDCBBuffer));
262 return SafeWriteBuffer(TargetBuffer(lsFieldAddr, (ULONG)size), const_cast<const BYTE *>(pbRSFieldAddr));
265 // Update the entire RS copy of the debugger control block by reading the LS copy.
268 HRESULT LocalEventChannel::UpdateRightSideDCB()
270 _ASSERTE(m_pDCBBuffer != NULL);
271 _ASSERTE(m_pLeftSideDCB != NULL);
273 return SafeReadBuffer(TargetBuffer(m_pLeftSideDCB, sizeof(DebuggerIPCControlBlock)),
274 reinterpret_cast<BYTE *>(m_pDCBBuffer));
277 // Get the pointer to the RS DCB.
280 DebuggerIPCControlBlock * LocalEventChannel::GetDCB()
286 // Check whether we need to wait for an acknowledgement from the LS after sending an IPC event.
289 BOOL LocalEventChannel::NeedToWaitForAck(DebuggerIPCEvent * pEvent)
291 // On Windows, we need to wait for acknowledgement for every synchronous event.
292 return !pEvent->asyncSend;
295 // Get a handle to wait on after sending an IPC event to the LS. The caller should call NeedToWaitForAck()
298 HANDLE LocalEventChannel::GetRightSideEventAckHandle()
300 return m_rightSideEventRead;
303 // Clean up the state if the wait for an acknowledgement is unsuccessful.
306 void LocalEventChannel::ClearEventForLeftSide()
308 ResetEvent(m_rightSideEventAvailable);
311 // Send an IPC event to the LS.
314 HRESULT LocalEventChannel::SendEventToLeftSide(DebuggerIPCEvent * pEvent, SIZE_T eventSize)
316 _ASSERTE(eventSize <= CorDBIPC_BUFFER_SIZE);
319 BOOL fSuccess = FALSE;
321 // Copy the event into the shared memory segment.
322 hr = SafeWriteBuffer(RemoteReceiveBuffer(eventSize), reinterpret_cast<BYTE *>(pEvent));
328 // Do some safety-checks for sending an Async-Event.
331 // We can only send 1 event from RS-->LS at a time.
332 // For non-async events, this is obviously enforced. (since the events are blocking & serialized)
333 // If this is an AsyncSend, then our caller was responsible for making sure it
335 // There should be no other IPC event in the pipeline. This, both RSEA & RSER
336 // should be non-signaled. check that now.
337 // It's ok if these fail - we detect that below.
338 int res2 = ::WaitForSingleObject(m_rightSideEventAvailable, 0);
339 CONSISTENCY_CHECK_MSGF(res2 != WAIT_OBJECT_0, ("RSEA:%d", res2));
341 int res3 = ::WaitForSingleObject(m_rightSideEventRead, 0);
342 CONSISTENCY_CHECK_MSGF(res3 != WAIT_OBJECT_0, ("RSER:%d", res3));
346 // Tell the runtime controller there is an event ready.
347 STRESS_LOG0(LF_CORDB, LL_INFO1000, "Set RSEA\n");
348 fSuccess = SetEvent(m_rightSideEventAvailable);
352 ThrowHR(HRESULT_FROM_GetLastError());
358 // Get the reply from the LS for a previously sent IPC event.
361 HRESULT LocalEventChannel::GetReplyFromLeftSide(DebuggerIPCEvent * pReplyEvent, SIZE_T eventSize)
363 // Simply read the IPC event reply directly from the receive buffer on the LS.
364 return SafeReadBuffer(RemoteReceiveBuffer(eventSize), reinterpret_cast<BYTE *>(pReplyEvent));
367 // Save an IPC event from the LS.
368 // Used for transferring an IPC event from the native pipeline to the IPC event channel.
371 HRESULT LocalEventChannel::SaveEventFromLeftSide(DebuggerIPCEvent * pEventFromLeftSide)
373 // On Windows, when a thread raises a debug event through the native pipeline, the process is suspended.
374 // Thus, the LS IPC event will still be in the send buffer in the debuggee's address space.
375 // Since there is no chance the send buffer can be altered, we don't need to save the event.
376 // We can simply read from it.
380 // Get a saved IPC event from the LS.
381 // Used for transferring an IPC event from the native pipeline to the IPC event channel.
384 HRESULT LocalEventChannel::GetEventFromLeftSide(DebuggerIPCEvent * pLocalManagedEvent)
386 // See code:LocalEventChannel::SaveEventFromLeftSide.
387 // Make sure we are reading form the send buffer, not the receive buffer.
388 return SafeReadBuffer(RemoteSendBuffer(CorDBIPC_BUFFER_SIZE), reinterpret_cast<BYTE *>(pLocalManagedEvent));
391 //-----------------------------------------------------------------------------
393 // Get a target buffer representing the area of the DebuggerIPCControlBlock on the helper thread that
394 // holds information received from the LS as the result of an IPC event.
397 // size - size of the receive buffer
400 // a TargetBuffer representing the receive buffer on the LS
403 TargetBuffer LocalEventChannel::RemoteReceiveBuffer(SIZE_T size)
405 return TargetBuffer(m_pLeftSideDCB + offsetof(DebuggerIPCControlBlock, m_receiveBuffer), (ULONG)size);
408 //-----------------------------------------------------------------------------
410 // Get a target buffer representing the area of the DebuggerIPCControlBlock on the helper thread that
411 // holds information sent to the LS with an IPC event.
414 // size - size of the send buffer
417 // a TargetBuffer representing the send buffer on the LS
420 TargetBuffer LocalEventChannel::RemoteSendBuffer(SIZE_T size)
422 return TargetBuffer(m_pLeftSideDCB + offsetof(DebuggerIPCControlBlock, m_sendBuffer), (ULONG)size);
425 //-----------------------------------------------------------------------------
427 // Write memory to the LS using the data target.
430 // tb - target address and size to be written to
431 // pLocalBuffer - data to write
434 // S_OK if successful
437 HRESULT LocalEventChannel::SafeWriteBuffer(TargetBuffer tb, const BYTE * pLocalBuffer)
439 return m_pMutableDataTarget->WriteVirtual(tb.pAddress, pLocalBuffer, tb.cbSize);
442 //-----------------------------------------------------------------------------
444 // Read memory from the LS using the data target.
447 // tb - target address and size to be read from
448 // pLocalBuffer - buffer for storing the data read from the LS
451 // S_OK if the entire specified range is read successful
454 HRESULT LocalEventChannel::SafeReadBuffer(TargetBuffer tb, BYTE * pLocalBuffer)
457 HRESULT hr = m_pMutableDataTarget->ReadVirtual(tb.pAddress, pLocalBuffer, tb.cbSize, &cbRead);
460 return CORDBG_E_READVIRTUAL_FAILURE;
463 if (cbRead != tb.cbSize)
465 return HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
471 //-----------------------------------------------------------------------------
473 // Duplicate a remote handle into the local process.
476 // pLocalHandle - out parameter; return the duplicated handle
477 // pRemoteHandle - remote handle to be duplicated
480 // S_OK if successful
483 // nop if pLocalHandle is already initialized
486 HRESULT LocalEventChannel::DuplicateHandleToLocalProcess(HANDLE * pLocalHandle, RemoteHANDLE * pRemoteHandle)
488 // Dup RSEA and RSER into this process if we don't already have them.
489 // On Launch, we don't have them yet, but on attach we do.
490 if (*pLocalHandle == NULL)
492 BOOL fSuccess = pRemoteHandle->DuplicateToLocalProcess(m_hTargetProc, pLocalHandle);
495 return HRESULT_FROM_GetLastError();