2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //*****************************************************************************
8 // File: ShimRemoteDataTarget.cpp
10 //*****************************************************************************
19 #include "shimdatatarget.h"
21 #include "dbgtransportsession.h"
22 #include "dbgtransportmanager.h"
25 class ShimRemoteDataTarget : public ShimDataTarget
28 ShimRemoteDataTarget(DWORD processId, DbgTransportTarget * pProxy, DbgTransportSession * pTransport);
30 virtual ~ShimRemoteDataTarget();
32 virtual void Dispose();
35 // ICorDebugMutableDataTarget.
38 virtual HRESULT STDMETHODCALLTYPE GetPlatform(
39 CorDebugPlatform *pPlatform);
41 virtual HRESULT STDMETHODCALLTYPE ReadVirtual(
42 CORDB_ADDRESS address,
47 virtual HRESULT STDMETHODCALLTYPE WriteVirtual(
48 CORDB_ADDRESS address,
52 virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
58 virtual HRESULT STDMETHODCALLTYPE SetThreadContext(
61 const BYTE * context);
63 virtual HRESULT STDMETHODCALLTYPE ContinueStatusChanged(
65 CORDB_CONTINUE_STATUS dwContinueStatus);
68 DbgTransportTarget * m_pProxy;
69 DbgTransportSession * m_pTransport;
73 // Helper macro to check for failure conditions at the start of data-target methods.
74 #define ReturnFailureIfStateNotOk() \
80 //---------------------------------------------------------------------------------------
82 // This is the ctor for ShimRemoteDataTarget.
85 // processId - pid of live process on the remote machine
86 // pProxy - connection to the debugger proxy
87 // pTransport - connection to the debuggee process
90 ShimRemoteDataTarget::ShimRemoteDataTarget(DWORD processId,
91 DbgTransportTarget * pProxy,
92 DbgTransportSession * pTransport)
96 m_processId = processId;
98 m_pTransport = pTransport;
102 m_fpContinueStatusChanged = NULL;
103 m_pContinueStatusChangedUserData = NULL;
106 //---------------------------------------------------------------------------------------
108 // dtor for ShimRemoteDataTarget
111 ShimRemoteDataTarget::~ShimRemoteDataTarget()
116 //---------------------------------------------------------------------------------------
118 // Dispose all resources and neuter the object.
121 // Release all resources (such as the connections to the debugger proxy and the debuggee process).
122 // May be called multiple times.
123 // All other non-trivial APIs (eg, not IUnknown) will fail after this.
126 void ShimRemoteDataTarget::Dispose()
128 if (m_pTransport != NULL)
130 m_pProxy->ReleaseTransport(m_pTransport);
133 m_hr = CORDBG_E_OBJECT_NEUTERED;
136 //---------------------------------------------------------------------------------------
138 // Construction method for data-target
141 // machineInfo - (input) the IP address of the remote machine and the port number of the debugger proxy
142 // processId - (input) live OS process ID to build a data-target for.
143 // ppDataTarget - (output) new data-target instance. This gets addreffed.
149 // pid is for a process on the remote machine specified by the IP address in machineInfo
150 // Caller must release *ppDataTarget.
153 HRESULT BuildPlatformSpecificDataTarget(MachineInfo machineInfo,
155 ShimDataTarget ** ppDataTarget)
160 ShimRemoteDataTarget * pRemoteDataTarget = NULL;
161 DbgTransportTarget * pProxy = g_pDbgTransportTarget;
162 DbgTransportSession * pTransport = NULL;
164 hr = pProxy->GetTransportForProcess(processId, &pTransport, &hDummy);
170 if (!pTransport->WaitForSessionToOpen(10000))
172 hr = CORDBG_E_TIMEOUT;
176 pRemoteDataTarget = new (nothrow) ShimRemoteDataTarget(processId, pProxy, pTransport);
177 if (pRemoteDataTarget == NULL)
183 _ASSERTE(SUCCEEDED(hr));
184 *ppDataTarget = pRemoteDataTarget;
185 pRemoteDataTarget->AddRef(); // must addref out-parameters
190 if (pRemoteDataTarget != NULL)
192 // The ShimRemoteDataTarget has ownership of the proxy and the transport,
193 // so we don't need to clean them up here.
194 delete pRemoteDataTarget;
198 if (pTransport != NULL)
200 pProxy->ReleaseTransport(pTransport);
208 // impl of interface method ICorDebugDataTarget::GetPlatform
209 HRESULT STDMETHODCALLTYPE
210 ShimRemoteDataTarget::GetPlatform(
211 CorDebugPlatform *pPlatform)
214 #if defined(DBG_TARGET_X86)
215 *pPlatform = CORDB_PLATFORM_POSIX_X86;
216 #elif defined(DBG_TARGET_AMD64)
217 *pPlatform = CORDB_PLATFORM_POSIX_AMD64;
219 #error Unknown Processor.
222 #if defined(DBG_TARGET_X86)
223 *pPlatform = CORDB_PLATFORM_WINDOWS_X86;
224 #elif defined(DBG_TARGET_AMD64)
225 *pPlatform = CORDB_PLATFORM_WINDOWS_AMD64;
226 #elif defined(DBG_TARGET_ARM)
227 *pPlatform = CORDB_PLATFORM_WINDOWS_ARM;
228 #elif defined(DBG_TARGET_ARM64)
229 *pPlatform = CORDB_PLATFORM_WINDOWS_ARM64;
231 #error Unknown Processor.
238 // impl of interface method ICorDebugDataTarget::ReadVirtual
239 HRESULT STDMETHODCALLTYPE
240 ShimRemoteDataTarget::ReadVirtual(
241 CORDB_ADDRESS address,
243 ULONG32 cbRequestSize,
246 ReturnFailureIfStateNotOk();
249 hr = m_pTransport->ReadMemory(reinterpret_cast<BYTE *>(CORDB_ADDRESS_TO_PTR(address)),
254 *pcbRead = (SUCCEEDED(hr) ? cbRequestSize : 0);
259 // impl of interface method ICorDebugMutableDataTarget::WriteVirtual
260 HRESULT STDMETHODCALLTYPE
261 ShimRemoteDataTarget::WriteVirtual(
262 CORDB_ADDRESS pAddress,
263 const BYTE * pBuffer,
264 ULONG32 cbRequestSize)
266 ReturnFailureIfStateNotOk();
269 hr = m_pTransport->WriteMemory(reinterpret_cast<BYTE *>(CORDB_ADDRESS_TO_PTR(pAddress)),
270 const_cast<BYTE *>(pBuffer),
275 // impl of interface method ICorDebugMutableDataTarget::GetThreadContext
276 HRESULT STDMETHODCALLTYPE
277 ShimRemoteDataTarget::GetThreadContext(
279 ULONG32 contextFlags,
283 ReturnFailureIfStateNotOk();
285 #ifdef FEATURE_DBGIPC_TRANSPORT_DI
286 // GetThreadContext() is currently not implemented in ShimRemoteDataTarget, which is used with our pipe transport
287 // (FEATURE_DBGIPC_TRANSPORT_DI). Pipe transport is used on POSIX system, but occasionally we can turn it on for Windows for testing,
288 // and then we'd like to have same behavior as on POSIX system (zero context).
290 // We don't have a good way to implement GetThreadContext() in ShimRemoteDataTarget yet, because we have no way to convert a thread ID to a
291 // thread handle. The function to do the conversion is OpenThread(), which is not implemented in PAL. Even if we had a handle, PAL implementation
292 // of GetThreadContext() is very limited and doesn't work when we're not attached with ptrace.
293 // Instead, we just zero out the seed CONTEXT for the stackwalk. This tells the stackwalker to
294 // start the stackwalk with the first explicit frame. This won't work when we do native debugging,
295 // but that won't happen on the POSIX systems since they don't support native debugging.
296 ZeroMemory(pContext, contextSize);
299 // ICorDebugDataTarget::GetThreadContext() and ICorDebugDataTarget::SetThreadContext() are currently only
300 // required for interop-debugging and inspection of floating point registers, both of which are not
301 // implemented on Mac.
302 _ASSERTE(!"The remote data target doesn't know how to get a thread's CONTEXT.");
304 #endif // DFEATURE_DBGIPC_TRANSPORT_DI
307 // impl of interface method ICorDebugMutableDataTarget::SetThreadContext
308 HRESULT STDMETHODCALLTYPE
309 ShimRemoteDataTarget::SetThreadContext(
312 const BYTE * pContext)
314 ReturnFailureIfStateNotOk();
316 // ICorDebugDataTarget::GetThreadContext() and ICorDebugDataTarget::SetThreadContext() are currently only
317 // required for interop-debugging and inspection of floating point registers, both of which are not
318 // implemented on Mac.
319 _ASSERTE(!"The remote data target doesn't know how to set a thread's CONTEXT.");
323 // Public implementation of ICorDebugMutableDataTarget::ContinueStatusChanged
324 HRESULT STDMETHODCALLTYPE
325 ShimRemoteDataTarget::ContinueStatusChanged(
327 CORDB_CONTINUE_STATUS dwContinueStatus)
329 ReturnFailureIfStateNotOk();
331 _ASSERTE(!"ShimRemoteDataTarget::ContinueStatusChanged() is called unexpectedly");
332 if (m_fpContinueStatusChanged != NULL)
334 return m_fpContinueStatusChanged(m_pContinueStatusChangedUserData, dwThreadId, dwContinueStatus);