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