Merge pull request #2887 from stephentoub/license_headers
[platform/upstream/coreclr.git] / src / debug / di / shimremotedatatarget.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
6 // 
7 // File: ShimRemoteDataTarget.cpp
8 //
9 //*****************************************************************************
10 #include "stdafx.h"
11 #include "safewrap.h"
12
13 #include "check.h" 
14
15 #include <limits.h>
16
17 #include "shimpriv.h"
18 #include "shimdatatarget.h"
19
20 #include "dbgtransportsession.h"
21 #include "dbgtransportmanager.h"
22
23
24 class ShimRemoteDataTarget : public ShimDataTarget
25 {
26 public:
27     ShimRemoteDataTarget(DWORD processId, DbgTransportTarget * pProxy, DbgTransportSession * pTransport);
28
29     virtual ~ShimRemoteDataTarget();
30
31     virtual void Dispose();
32
33     //
34     // ICorDebugMutableDataTarget.
35     //
36
37     virtual HRESULT STDMETHODCALLTYPE GetPlatform( 
38         CorDebugPlatform *pPlatform);
39
40     virtual HRESULT STDMETHODCALLTYPE ReadVirtual( 
41         CORDB_ADDRESS address,
42         BYTE * pBuffer,
43         ULONG32 request,
44         ULONG32 *pcbRead);
45
46     virtual HRESULT STDMETHODCALLTYPE WriteVirtual( 
47         CORDB_ADDRESS address,
48         const BYTE * pBuffer,
49         ULONG32 request);
50
51     virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
52         DWORD dwThreadID,
53         ULONG32 contextFlags,
54         ULONG32 contextSize,
55         BYTE * context);
56
57     virtual HRESULT STDMETHODCALLTYPE SetThreadContext(
58         DWORD dwThreadID,
59         ULONG32 contextSize,
60         const BYTE * context);
61
62     virtual HRESULT STDMETHODCALLTYPE ContinueStatusChanged(
63         DWORD dwThreadId,
64         CORDB_CONTINUE_STATUS dwContinueStatus);
65
66     virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(
67         DWORD threadId, ULONG32 contextSize, PBYTE context);
68
69 private:
70     DbgTransportTarget  * m_pProxy;
71     DbgTransportSession * m_pTransport;
72 };
73
74
75 // Helper macro to check for failure conditions at the start of data-target methods.
76 #define ReturnFailureIfStateNotOk() \
77     if (m_hr != S_OK) \
78     { \
79         return m_hr; \
80     }
81
82 //---------------------------------------------------------------------------------------
83 //
84 // This is the ctor for ShimRemoteDataTarget. 
85 //
86 // Arguments:
87 //      processId  - pid of live process on the remote machine
88 //      pProxy     - connection to the debugger proxy
89 //      pTransport - connection to the debuggee process
90 //
91
92 ShimRemoteDataTarget::ShimRemoteDataTarget(DWORD processId, 
93                                            DbgTransportTarget * pProxy, 
94                                            DbgTransportSession * pTransport)
95 {
96     m_ref = 0;
97
98     m_processId = processId;
99     m_pProxy = pProxy;
100     m_pTransport = pTransport;
101
102     m_hr = S_OK;
103
104     m_fpContinueStatusChanged = NULL;
105     m_pContinueStatusChangedUserData = NULL;
106 }
107
108 //---------------------------------------------------------------------------------------
109 //
110 // dtor for ShimRemoteDataTarget
111 //
112
113 ShimRemoteDataTarget::~ShimRemoteDataTarget()
114 {
115     Dispose();
116 }
117
118 //---------------------------------------------------------------------------------------
119 //
120 // Dispose all resources and neuter the object.
121 //
122 // Notes:
123 //    Release all resources (such as the connections to the debugger proxy and the debuggee process).
124 //    May be called multiple times.
125 //    All other non-trivial APIs (eg, not IUnknown) will fail after this.
126 //
127
128 void ShimRemoteDataTarget::Dispose()
129 {
130     if (m_pTransport != NULL)
131     {
132         m_pProxy->ReleaseTransport(m_pTransport);
133     }
134
135     m_pTransport = NULL;
136     m_hr = CORDBG_E_OBJECT_NEUTERED;
137 }
138
139 //---------------------------------------------------------------------------------------
140 //
141 // Construction method for data-target
142 //
143 // Arguments:
144 //      machineInfo  - (input) the IP address of the remote machine and the port number of the debugger proxy
145 //      processId    - (input) live OS process ID to build a data-target for.
146 //      ppDataTarget - (output) new data-target instance. This gets addreffed.
147 //
148 // Return Value:
149 //    S_OK on success.
150 //
151 // Assumptions:
152 //    pid is for a process on the remote machine specified by the IP address in machineInfo
153 //    Caller must release *ppDataTarget.
154 //
155
156 HRESULT BuildPlatformSpecificDataTarget(MachineInfo machineInfo,
157                                         DWORD processId, 
158                                         ShimDataTarget ** ppDataTarget)
159 {
160     HandleHolder hDummy;
161     HRESULT hr = E_FAIL;
162
163     ShimRemoteDataTarget * pRemoteDataTarget = NULL;
164     DbgTransportTarget *   pProxy = g_pDbgTransportTarget;
165     DbgTransportSession *  pTransport = NULL;
166
167     hr = pProxy->GetTransportForProcess(processId, &pTransport, &hDummy);
168     if (FAILED(hr))
169     {
170         goto Label_Exit;
171     }
172
173     if (!pTransport->WaitForSessionToOpen(10000))
174     {
175         hr = CORDBG_E_TIMEOUT;
176         goto Label_Exit;
177     }
178
179     pRemoteDataTarget = new (nothrow) ShimRemoteDataTarget(processId, pProxy, pTransport);
180     if (pRemoteDataTarget == NULL)
181     {
182         hr = E_OUTOFMEMORY;
183         goto Label_Exit;
184     }
185
186     _ASSERTE(SUCCEEDED(hr));
187     *ppDataTarget = pRemoteDataTarget;
188     pRemoteDataTarget->AddRef(); // must addref out-parameters
189
190 Label_Exit:
191     if (FAILED(hr))
192     {
193         if (pRemoteDataTarget != NULL)
194         {
195             // The ShimRemoteDataTarget has ownership of the proxy and the transport, 
196             // so we don't need to clean them up here.
197             delete pRemoteDataTarget;
198         }
199         else
200         {
201             if (pTransport != NULL)
202             {
203                 pProxy->ReleaseTransport(pTransport);
204             }
205         }
206     }
207
208     return hr;
209 }
210
211 // impl of interface method ICorDebugDataTarget::GetPlatform
212 HRESULT STDMETHODCALLTYPE
213 ShimRemoteDataTarget::GetPlatform( 
214         CorDebugPlatform *pPlatform)
215 {
216 #ifdef FEATURE_PAL
217      #if defined(DBG_TARGET_X86)
218          *pPlatform = CORDB_PLATFORM_POSIX_X86;
219      #elif defined(DBG_TARGET_AMD64)
220          *pPlatform = CORDB_PLATFORM_POSIX_AMD64;
221      #elif defined(DBG_TARGET_ARM)
222          *pPlatform = CORDB_PLATFORM_POSIX_ARM;
223      #elif defined(DBG_TARGET_ARM64)
224          *pPlatform = CORDB_PLATFORM_POSIX_ARM64;
225      #else
226          #error Unknown Processor.
227      #endif
228 #else
229     #if defined(DBG_TARGET_X86)
230         *pPlatform = CORDB_PLATFORM_WINDOWS_X86;
231     #elif defined(DBG_TARGET_AMD64)
232         *pPlatform = CORDB_PLATFORM_WINDOWS_AMD64;
233     #elif defined(DBG_TARGET_ARM)
234         *pPlatform = CORDB_PLATFORM_WINDOWS_ARM;
235     #elif defined(DBG_TARGET_ARM64)
236         *pPlatform = CORDB_PLATFORM_WINDOWS_ARM64;
237     #else
238         #error Unknown Processor.
239     #endif
240 #endif
241
242     return S_OK;
243 }
244
245 // impl of interface method ICorDebugDataTarget::ReadVirtual
246 HRESULT STDMETHODCALLTYPE
247 ShimRemoteDataTarget::ReadVirtual( 
248     CORDB_ADDRESS address,
249     PBYTE pBuffer,
250     ULONG32 cbRequestSize,
251     ULONG32 *pcbRead)
252 {
253     ReturnFailureIfStateNotOk();
254
255     HRESULT hr = E_FAIL;
256     hr = m_pTransport->ReadMemory(reinterpret_cast<BYTE *>(CORDB_ADDRESS_TO_PTR(address)), 
257                                   pBuffer, 
258                                   cbRequestSize);
259     if (pcbRead != NULL)
260     {
261         *pcbRead = (SUCCEEDED(hr) ? cbRequestSize : 0);
262     }
263     return hr;
264 }
265
266 // impl of interface method ICorDebugMutableDataTarget::WriteVirtual
267 HRESULT STDMETHODCALLTYPE
268 ShimRemoteDataTarget::WriteVirtual( 
269     CORDB_ADDRESS pAddress,
270     const BYTE * pBuffer,
271     ULONG32 cbRequestSize)
272 {
273     ReturnFailureIfStateNotOk();
274
275     HRESULT hr = E_FAIL;
276     hr = m_pTransport->WriteMemory(reinterpret_cast<BYTE *>(CORDB_ADDRESS_TO_PTR(pAddress)), 
277                                    const_cast<BYTE *>(pBuffer), 
278                                    cbRequestSize);
279     return hr;
280 }
281
282 // impl of interface method ICorDebugMutableDataTarget::GetThreadContext
283 HRESULT STDMETHODCALLTYPE
284 ShimRemoteDataTarget::GetThreadContext(
285     DWORD dwThreadID,
286     ULONG32 contextFlags,
287     ULONG32 contextSize,
288     BYTE * pContext)
289 {
290     ReturnFailureIfStateNotOk();
291         
292     // GetThreadContext() is currently not implemented in ShimRemoteDataTarget, which is used with our pipe transport 
293     // (FEATURE_DBGIPC_TRANSPORT_DI). Pipe transport is used on POSIX system, but occasionally we can turn it on for Windows for testing,
294     // and then we'd like to have same behavior as on POSIX system (zero context).
295     //
296     // 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 
297     // thread handle.  The function to do the conversion is OpenThread(), which is not implemented in PAL. Even if we had a handle, PAL implementation 
298     // of GetThreadContext() is very limited and doesn't work when we're not attached with ptrace. 
299     // Instead, we just zero out the seed CONTEXT for the stackwalk.  This tells the stackwalker to
300     // start the stackwalk with the first explicit frame.  This won't work when we do native debugging, 
301     // but that won't happen on the POSIX systems since they don't support native debugging.
302     ZeroMemory(pContext, contextSize);
303     return E_NOTIMPL;
304 }
305
306 // impl of interface method ICorDebugMutableDataTarget::SetThreadContext
307 HRESULT STDMETHODCALLTYPE
308 ShimRemoteDataTarget::SetThreadContext(
309     DWORD dwThreadID,
310     ULONG32 contextSize,
311     const BYTE * pContext)
312 {
313     ReturnFailureIfStateNotOk();
314
315     // ICorDebugDataTarget::GetThreadContext() and ICorDebugDataTarget::SetThreadContext() are currently only 
316     // required for interop-debugging and inspection of floating point registers, both of which are not 
317     // implemented on Mac.
318     _ASSERTE(!"The remote data target doesn't know how to set a thread's CONTEXT.");
319     return E_NOTIMPL;
320 }
321
322 // Public implementation of ICorDebugMutableDataTarget::ContinueStatusChanged
323 HRESULT STDMETHODCALLTYPE
324 ShimRemoteDataTarget::ContinueStatusChanged(
325     DWORD dwThreadId,
326     CORDB_CONTINUE_STATUS dwContinueStatus)
327 {
328     ReturnFailureIfStateNotOk();
329
330     _ASSERTE(!"ShimRemoteDataTarget::ContinueStatusChanged() is called unexpectedly");
331     if (m_fpContinueStatusChanged != NULL)
332     {
333         return m_fpContinueStatusChanged(m_pContinueStatusChangedUserData, dwThreadId, dwContinueStatus);
334     }
335     return E_NOTIMPL;
336 }
337
338 //---------------------------------------------------------------------------------------
339 //
340 // Unwind the stack to the next frame.
341 //
342 // Return Value: 
343 //     context filled in with the next frame
344 //
345 HRESULT STDMETHODCALLTYPE 
346 ShimRemoteDataTarget::VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
347 {
348     return m_pTransport->VirtualUnwind(threadId, contextSize, context);
349 }